Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(dashboard): add support for moonraker sensor #1888

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions src/components/panels/Miscellaneous/MoonrakerSensor.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<template>
<v-container class="px-0 py-2">
<v-row>
<v-col class="pb-3">
<v-subheader class="mb-1 d-block _moonraker-sensor-subheader">
{{ convertName(name) }}
</v-subheader>
<v-subheader class="d-block _moonraker-sensor-subheader">
<moonraker-sensor-value
v-for="(valueName, index) of valueNames"
:key="'moonraker_sensor_value_' + index"
:sensor="name"
:value-name="valueName" />
</v-subheader>
</v-col>
</v-row>
</v-container>
</template>

<script lang="ts">
import { convertName } from '@/plugins/helpers'
import { Component, Mixins, Prop } from 'vue-property-decorator'
import BaseMixin from '@/components/mixins/base'
import MoonrakerSensorValue from '@/components/panels/Miscellaneous/MoonrakerSensorValue.vue'
import {} from '@mdi/js'

@Component({
components: { MoonrakerSensorValue },
})
export default class MoonrakerSensor extends Mixins(BaseMixin) {
convertName = convertName

@Prop({ type: String, required: true }) declare readonly name: string

get valueNames() {
const sensors = this.$store.state.server.sensor.sensors
if (!(this.name in sensors)) return []

return Object.keys(sensors[this.name].values)
}
}
</script>

<style scoped>
._moonraker-sensor-subheader {
height: auto;
}
</style>
92 changes: 92 additions & 0 deletions src/components/panels/Miscellaneous/MoonrakerSensorValue.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<template>
<div class="d-flex w-100 flex-row align-center">
<v-icon small left>{{ symbol }}</v-icon>
<span class="flex-grow-1">{{ name }}:</span>
<span>{{ output }}</span>
</div>
</template>

<script lang="ts">
import { convertName } from '@/plugins/helpers'
import { Component, Mixins, Prop } from 'vue-property-decorator'
import BaseMixin from '@/components/mixins/base'
import { mdiGauge, mdiLightningBoltOutline, mdiFlash, mdiThermometer, mdiMeterElectricOutline } from '@mdi/js'

@Component
export default class MoonrakerSensorValue extends Mixins(BaseMixin) {
convertName = convertName

@Prop({ type: String, required: true }) declare readonly sensor: string
@Prop({ type: String, required: true }) declare readonly valueName: string

mdiGauge = mdiGauge
mdiLightningBoltOutline = mdiLightningBoltOutline
mdiFlash = mdiFlash
mdiThermometer = mdiThermometer
mdiMeterElectricOutline = mdiMeterElectricOutline

get sensorData() {
const sensors = this.$store.state.server.sensor.sensors
if (!(this.sensor in sensors)) return {}

return sensors[this.sensor].values
}

get sensorConfig() {
const name = `sensor ${this.sensor}`
const serverConfig = this.$store.state.server.config?.config ?? {}
if (!(name in serverConfig)) return {}

return serverConfig[name]
}

get parameterConfig() {
const name = `parameter_${this.valueName}`
if (!(name in this.sensorConfig)) return {}

return this.sensorConfig[name]
}

get unit() {
if (!('units' in this.parameterConfig)) return null

return this.parameterConfig.units
}

get value() {
if (!(this.valueName in this.sensorData)) return '--'

return Math.round(this.sensorData[this.valueName] * 1000) / 1000
}

get output() {
if (this.unit === null) return this.value

return `${this.value} ${this.unit}`
}

get name() {
return this.convertName(this.valueName)
}

get symbol() {
if (['wh', 'kwh', 'mwh', 'j'].includes(this.unit?.toLowerCase())) {
return this.mdiLightningBoltOutline
}

if (['w', 'v'].includes(this.unit?.toLowerCase())) {
return this.mdiFlash
}

if (this.unit?.toLowerCase() === 'a') {
return this.mdiMeterElectricOutline
}

if (['°c', 'c', '°f', 'f', '°'].includes(this.unit?.toLowerCase())) {
return this.mdiThermometer
}

return this.mdiGauge
}
}
</script>
21 changes: 15 additions & 6 deletions src/components/panels/MiscellaneousPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
:collapsible="true"
card-class="miscellaneous-panel">
<div v-for="(object, index) of miscellaneous" :key="index">
<v-divider v-if="index"></v-divider>
<v-divider v-if="index" />
<miscellaneous-slider
:name="object.name"
:type="object.type"
Expand All @@ -18,10 +18,10 @@
:pwm="object.pwm"
:off_below="object.off_below"
:max="object.max_power"
:multi="parseInt(object.scale)"></miscellaneous-slider>
:multi="parseInt(object.scale)" />
</div>
<div v-for="(light, index) of lights" :key="'light_' + light.name">
<v-divider v-if="index || miscellaneous.length"></v-divider>
<v-divider v-if="index || miscellaneous.length" />
<miscellaneous-slider
v-if="light.type === 'led' && light.colorOrder.length === 1"
:name="light.name"
Expand All @@ -34,11 +34,15 @@
<miscellaneous-light v-else :object="light" :root="true" />
</div>
<div v-for="(sensor, index) of filamentSensors" :key="'sensor_' + index">
<v-divider v-if="index || miscellaneous.length || lights.length"></v-divider>
<v-divider v-if="index || miscellaneous.length || lights.length" />
<filament-sensor
:name="sensor.name"
:enabled="sensor.enabled"
:filament_detected="sensor.filament_detected"></filament-sensor>
:filament_detected="sensor.filament_detected" />
</div>
<div v-for="(sensor, index) of moonrakerSensors" :key="'moonraker_sensor_' + index">
<v-divider v-if="index || miscellaneous.length || lights.length || filamentSensors.length" />
<moonraker-sensor :name="sensor" />
</div>
</panel>
</template>
Expand All @@ -49,10 +53,11 @@ import BaseMixin from '@/components/mixins/base'
import MiscellaneousSlider from '@/components/inputs/MiscellaneousSlider.vue'
import MiscellaneousLight from '@/components/inputs/MiscellaneousLight.vue'
import FilamentSensor from '@/components/inputs/FilamentSensor.vue'
import MoonrakerSensor from '@/components/panels/Miscellaneous/MoonrakerSensor.vue'
import Panel from '@/components/ui/Panel.vue'
import { mdiDipSwitch } from '@mdi/js'
@Component({
components: { Panel, FilamentSensor, MiscellaneousSlider, MiscellaneousLight },
components: { Panel, FilamentSensor, MiscellaneousSlider, MiscellaneousLight, MoonrakerSensor },
})
export default class MiscellaneousPanel extends Mixins(BaseMixin) {
mdiDipSwitch = mdiDipSwitch
Expand All @@ -69,6 +74,10 @@ export default class MiscellaneousPanel extends Mixins(BaseMixin) {
return this.$store.getters['printer/getLights'] ?? []
}

get moonrakerSensors() {
return this.$store.getters['server/sensor/getSensors'] ?? []
}

get showMiscellaneousPanel() {
return (
this.klipperReadyForGui && (this.miscellaneous.length || this.filamentSensors.length || this.lights.length)
Expand Down
6 changes: 5 additions & 1 deletion src/store/server/sensor/getters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,8 @@ import { GetterTree } from 'vuex'
import { ServerSensorState } from '@/store/server/sensor/types'

// eslint-disable-next-line
export const getters: GetterTree<ServerSensorState, any> = {}
export const getters: GetterTree<ServerSensorState, any> = {
getSensors: (state) => {
return Object.keys(state.sensors)
},
}
4 changes: 3 additions & 1 deletion src/store/server/sensor/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ export const mutations: MutationTree<ServerSensorState> = {
},

updateSensor(state, payload) {
Vue.set(state.sensors, payload.key, payload.value)
if (!(payload.key in state.sensors)) return

Vue.set(state.sensors[payload.key], 'values', payload.value)
},
}
Loading