Skip to content

Commit 48520e2

Browse files
authored
feat: control printer power via Moonraker (#1570)
Signed-off-by: Pedro Lamas <[email protected]>
1 parent 70e58da commit 48520e2

File tree

8 files changed

+127
-7
lines changed

8 files changed

+127
-7
lines changed

src/components/common/KlippyStatusCard.vue

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,20 @@
1818
>
1919
<v-row>
2020
<v-col
21-
v-if="klippyStateMessage !== 'Printer is ready'"
21+
v-if="printerPoweredOff"
22+
cols="12"
23+
>
24+
<v-alert
25+
text
26+
dense
27+
type="error"
28+
class="ma-0"
29+
>
30+
<span v-html="$t('app.general.error.printer_powered_off')" />
31+
</v-alert>
32+
</v-col>
33+
<v-col
34+
v-else-if="klippyStateMessage !== 'Printer is ready'"
2235
cols="12"
2336
>
2437
<v-alert

src/components/common/SystemControl.vue

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,24 @@
3434
</v-tooltip>
3535
</template>
3636

37+
<template v-else-if="printerPoweredOff">
38+
<v-tooltip bottom>
39+
<template #activator="{ on, attrs }">
40+
<app-btn
41+
v-bind="attrs"
42+
block
43+
color="primary"
44+
class="mb-2"
45+
v-on="on"
46+
@click="printerPowerOn"
47+
>
48+
{{ $t('app.general.btn.power_on_printer') }}
49+
</app-btn>
50+
</template>
51+
<span>{{ $t('app.general.tooltip.power_on_printer') }}</span>
52+
</v-tooltip>
53+
</template>
54+
3755
<template v-else>
3856
<v-tooltip bottom>
3957
<template #activator="{ on, attrs }">
@@ -87,6 +105,7 @@ import { Component, Mixins } from 'vue-property-decorator'
87105
import FilesMixin from '@/mixins/files'
88106
import StateMixin from '@/mixins/state'
89107
import ServicesMixin from '@/mixins/services'
108+
import { SocketActions } from '@/api/socketActions'
90109
91110
@Component({})
92111
export default class SystemControl extends Mixins(StateMixin, FilesMixin, ServicesMixin) {
@@ -97,5 +116,11 @@ export default class SystemControl extends Mixins(StateMixin, FilesMixin, Servic
97116
getMoonrakerLog () {
98117
this.downloadFile('moonraker.log', '')
99118
}
119+
120+
printerPowerOn () {
121+
const printerPowerDevice: string = this.$store.state.config.uiSettings.general.printerPowerDevice ?? 'printer'
122+
123+
SocketActions.machineDevicePowerToggle(printerPowerDevice, 'on')
124+
}
100125
}
101126
</script>

src/components/layout/AppBar.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ export default class AppBar extends Mixins(StateMixin, ServicesMixin, FilesMixin
265265
case 'klipper': {
266266
const device = this.$store.getters['printer/getPinByName'](name) as OutputPin | undefined
267267
268+
if (!device) return null
269+
268270
return {
269271
type,
270272
name: device?.prettyName ?? name,
@@ -273,11 +275,13 @@ export default class AppBar extends Mixins(StateMixin, ServicesMixin, FilesMixin
273275
}
274276
275277
default: {
276-
const device = this.$store.getters['power/getDeviceByName'](topNavPowerToggle) as Device
278+
const device = this.$store.getters['power/getDeviceByName'](topNavPowerToggle) as Device | undefined
279+
280+
if (!device) return null
277281
278282
return {
279283
type: 'moonraker' as const,
280-
name: topNavPowerToggle,
284+
name: this.$filters.prettyCase(topNavPowerToggle),
281285
device
282286
}
283287
}

src/components/settings/GeneralSettings.vue

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,14 +99,27 @@
9999

100100
<v-divider />
101101

102+
<app-setting :title="$t('app.setting.label.printer_power_device')">
103+
<v-select
104+
v-model="printerPowerDevice"
105+
filled
106+
dense
107+
single-line
108+
hide-details="auto"
109+
:items="printerPowerDevicesList"
110+
/>
111+
</app-setting>
112+
113+
<v-divider />
114+
102115
<app-setting :title="$t('app.setting.label.power_toggle_in_top_nav')">
103116
<v-select
104117
v-model="topNavPowerToggle"
105118
filled
106119
dense
107120
single-line
108121
hide-details="auto"
109-
:items="[{ text: $tc('app.setting.label.none'), value: null }, ...powerDevicesList]"
122+
:items="topNavPowerToggleDevicesList"
110123
/>
111124
</app-setting>
112125

@@ -373,6 +386,39 @@ export default class GeneralSettings extends Mixins(StateMixin) {
373386
})
374387
}
375388
389+
get printerPowerDevice (): string | null {
390+
return this.$store.state.config.uiSettings.general.printerPowerDevice
391+
}
392+
393+
set printerPowerDevice (value: string | null) {
394+
this.$store.dispatch('config/saveByPath', {
395+
path: 'uiSettings.general.printerPowerDevice',
396+
value,
397+
server: true
398+
})
399+
}
400+
401+
get printerPowerDevicesList () {
402+
const devices = this.$store.getters['power/getDevices'] as Device[]
403+
404+
const deviceEntries = devices.map(device => ({
405+
text: `${this.$filters.prettyCase(device.device)} (${device.type})`,
406+
value: device.device
407+
}))
408+
409+
const autoDeviceName = devices.some(device => device.device.toLowerCase() === 'printer')
410+
? 'Printer'
411+
: this.$tc('app.setting.label.none')
412+
413+
return [
414+
{
415+
text: `${this.$tc('app.setting.label.auto')} (${autoDeviceName})`,
416+
value: null
417+
},
418+
...deviceEntries
419+
]
420+
}
421+
376422
get topNavPowerToggle (): string | null {
377423
return this.$store.state.config.uiSettings.general.topNavPowerToggle
378424
}
@@ -385,24 +431,34 @@ export default class GeneralSettings extends Mixins(StateMixin) {
385431
})
386432
}
387433
388-
get powerDevicesList () {
434+
get topNavPowerToggleDevicesList () {
389435
const devices = this.$store.getters['power/getDevices'] as Device[]
390436
const deviceEntries = devices.length
391437
? [
392438
{ header: 'Moonraker' },
393-
...devices.map(device => ({ text: device.device, value: device.device }))
439+
...devices.map(device => ({
440+
text: `${this.$filters.prettyCase(device.device)} (${device.type})`,
441+
value: device.device
442+
}))
394443
]
395444
: []
396445
397446
const pins = this.$store.getters['printer/getPins'] as OutputPin[]
398447
const pinEntries = pins.length
399448
? [
400449
{ header: 'Klipper' },
401-
...pins.map(outputPin => ({ text: outputPin.prettyName, value: `${outputPin.name}:klipper` }))
450+
...pins.map(outputPin => ({
451+
text: outputPin.prettyName,
452+
value: `${outputPin.name}:klipper`
453+
}))
402454
]
403455
: []
404456
405457
return [
458+
{
459+
text: this.$tc('app.setting.label.none'),
460+
value: null
461+
},
406462
...deviceEntries,
407463
...pinEntries
408464
]

src/locales/en.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ app:
183183
more_information: More information
184184
multiply: Multiply
185185
pause: Pause
186+
power_on_printer: Power On Printer
186187
preheat: Preheat
187188
presets: Presets
188189
preview_gcode: Preview Gcode
@@ -238,6 +239,9 @@ app:
238239
failed_components: >-
239240
Moonraker has failed plugins, please check your logs, update your
240241
configuration and restart moonraker.
242+
printer_powered_off: >-
243+
The printer is currently powered off.<br/><br/>
244+
To power on the printer, please click the button on the left.
241245
label:
242246
accel_to_decel: Accel to Decel
243247
acceleration: Acceleration
@@ -480,6 +484,7 @@ app:
480484
estop: Emergency Stop
481485
managed_by_moonraker: Managed by your moonraker configuration
482486
notifications: Notifications
487+
power_on_printer: Turns on the power to the printer
483488
reload_klipper: Reloads klipper configuration.
484489
reload_restart_klipper: Reloads klipper configuration and restarts MCU's.
485490
restart_klipper: Restarts the klipper system service.
@@ -557,6 +562,7 @@ app:
557562
auto_follow_on_file_load: Automatically follow progress on file load
558563
auto_load_on_print_start: Automatically load file on print start
559564
auto_load_mobile_on_print_start: Automatically load file on mobile devices
565+
auto: Auto
560566
axes: Axes
561567
camera_flip_x: Flip horizontally
562568
camera_flip_y: Flip vertically
@@ -627,6 +633,7 @@ app:
627633
print_in_progress_layout: Print in Progress layout
628634
print_progress_calculation: Print Progress calculation
629635
printer_name: Printer Name
636+
printer_power_device: Printer power device
630637
reset: Reset settings
631638
retraction_icon_size: Retraction Icon Size
632639
right_y: Right Y-Axis

src/mixins/state.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Vue from 'vue'
22
import { SocketActions } from '@/api/socketActions'
33
import { Component } from 'vue-property-decorator'
44
import type { Macro } from '@/store/macros/types'
5+
import type { Device } from '@/store/power/types'
56

67
@Component
78
export default class StateMixin extends Vue {
@@ -74,6 +75,18 @@ export default class StateMixin extends Vue {
7475
return this.printerState.toLowerCase() === 'printing'
7576
}
7677

78+
get printerPoweredOff (): boolean {
79+
if (this.klippyConnected) {
80+
return false
81+
}
82+
83+
const printerPowerDevice: string = this.$store.state.config.uiSettings.general.printerPowerDevice ?? 'printer'
84+
85+
const device = this.$store.getters['power/getDeviceByName'](printerPowerDevice) as Device | undefined
86+
87+
return device?.status === 'off'
88+
}
89+
7790
/**
7891
* Indicates if we have a valid wait(s).
7992
* Supports a single string or a list of.

src/store/config/state.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export const defaultState = (): ConfigState => {
5858
showUploadAndPrint: true,
5959
flipConsoleLayout: false,
6060
cameraFullscreenAction: 'embed',
61+
printerPowerDevice: null,
6162
topNavPowerToggle: null,
6263
showManualProbeDialogAutomatically: true,
6364
showBedScrewsAdjustDialogAutomatically: true,

src/store/config/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ export interface GeneralConfig {
9494
showUploadAndPrint: boolean;
9595
flipConsoleLayout: boolean;
9696
cameraFullscreenAction: CameraFullscreenAction;
97+
printerPowerDevice: null | string;
9798
topNavPowerToggle: null | string;
9899
showManualProbeDialogAutomatically: boolean;
99100
showBedScrewsAdjustDialogAutomatically: boolean;

0 commit comments

Comments
 (0)