Skip to content

Commit

Permalink
feat: control printer power via Moonraker
Browse files Browse the repository at this point in the history
Signed-off-by: Pedro Lamas <[email protected]>
  • Loading branch information
pedrolamas committed Jan 9, 2025
1 parent 70e58da commit 96a1ca5
Show file tree
Hide file tree
Showing 8 changed files with 127 additions and 7 deletions.
15 changes: 14 additions & 1 deletion src/components/common/KlippyStatusCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,20 @@
>
<v-row>
<v-col
v-if="klippyStateMessage !== 'Printer is ready'"
v-if="printerPoweredOff"
cols="12"
>
<v-alert
text
dense
type="error"
class="ma-0"
>
<span v-html="$t('app.general.error.printer_powered_off')" />
</v-alert>
</v-col>
<v-col
v-else-if="klippyStateMessage !== 'Printer is ready'"
cols="12"
>
<v-alert
Expand Down
25 changes: 25 additions & 0 deletions src/components/common/SystemControl.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,24 @@
</v-tooltip>
</template>

<template v-else-if="printerPoweredOff">
<v-tooltip bottom>
<template #activator="{ on, attrs }">
<app-btn
v-bind="attrs"
block
color="primary"
class="mb-2"
v-on="on"
@click="printerPowerOn"
>
{{ $t('app.general.btn.power_on_printer') }}
</app-btn>
</template>
<span>{{ $t('app.general.tooltip.power_on_printer') }}</span>
</v-tooltip>
</template>

<template v-else>
<v-tooltip bottom>
<template #activator="{ on, attrs }">
Expand Down Expand Up @@ -87,6 +105,7 @@ import { Component, Mixins } from 'vue-property-decorator'
import FilesMixin from '@/mixins/files'
import StateMixin from '@/mixins/state'
import ServicesMixin from '@/mixins/services'
import { SocketActions } from '@/api/socketActions'
@Component({})
export default class SystemControl extends Mixins(StateMixin, FilesMixin, ServicesMixin) {
Expand All @@ -97,5 +116,11 @@ export default class SystemControl extends Mixins(StateMixin, FilesMixin, Servic
getMoonrakerLog () {
this.downloadFile('moonraker.log', '')
}
printerPowerOn () {
const printerPowerDevice: string = this.$store.state.config.uiSettings.general.printerPowerDevice ?? 'printer'
SocketActions.machineDevicePowerSetDevice(printerPowerDevice, 'on')

Check failure on line 123 in src/components/common/SystemControl.vue

View workflow job for this annotation

GitHub Actions / Build

Property 'machineDevicePowerSetDevice' does not exist on type '{ machineServicesRestart(service: string): Promise<void>; machineServicesStart(service: string): Promise<void>; machineServicesStop(service: string): Promise<...>; ... 73 more ...; serverSpoolmanProxyGetAvailableSpools(): Promise<...>; }'. Did you mean 'machineDevicePowerDevices'?
}
}
</script>
8 changes: 6 additions & 2 deletions src/components/layout/AppBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ export default class AppBar extends Mixins(StateMixin, ServicesMixin, FilesMixin
case 'klipper': {
const device = this.$store.getters['printer/getPinByName'](name) as OutputPin | undefined
if (!device) return null
return {
type,
name: device?.prettyName ?? name,
Expand All @@ -273,11 +275,13 @@ export default class AppBar extends Mixins(StateMixin, ServicesMixin, FilesMixin
}
default: {
const device = this.$store.getters['power/getDeviceByName'](topNavPowerToggle) as Device
const device = this.$store.getters['power/getDeviceByName'](topNavPowerToggle) as Device | undefined
if (!device) return null
return {
type: 'moonraker' as const,
name: topNavPowerToggle,
name: this.$filters.prettyCase(topNavPowerToggle),
device
}
}
Expand Down
64 changes: 60 additions & 4 deletions src/components/settings/GeneralSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -99,14 +99,27 @@

<v-divider />

<app-setting :title="$t('app.setting.label.printer_power_device')">
<v-select
v-model="printerPowerDevice"
filled
dense
single-line
hide-details="auto"
:items="printerPowerDevicesList"
/>
</app-setting>

<v-divider />

<app-setting :title="$t('app.setting.label.power_toggle_in_top_nav')">
<v-select
v-model="topNavPowerToggle"
filled
dense
single-line
hide-details="auto"
:items="[{ text: $tc('app.setting.label.none'), value: null }, ...powerDevicesList]"
:items="topNavPowerToggleDevicesList"
/>
</app-setting>

Expand Down Expand Up @@ -373,6 +386,39 @@ export default class GeneralSettings extends Mixins(StateMixin) {
})
}
get printerPowerDevice (): string | null {
return this.$store.state.config.uiSettings.general.printerPowerDevice
}
set printerPowerDevice (value: string | null) {
this.$store.dispatch('config/saveByPath', {
path: 'uiSettings.general.printerPowerDevice',
value,
server: true
})
}
get printerPowerDevicesList () {
const devices = this.$store.getters['power/getDevices'] as Device[]
const deviceEntries = devices.map(device => ({
text: `${this.$filters.prettyCase(device.device)} (${device.type})`,
value: device.device
}))
const autoDeviceName = devices.some(device => device.device.toLowerCase() === 'printer')
? 'Printer'
: this.$tc('app.setting.label.none')
return [
{
text: `${this.$tc('app.setting.label.auto')} (${autoDeviceName})`,
value: null
},
...deviceEntries
]
}
get topNavPowerToggle (): string | null {
return this.$store.state.config.uiSettings.general.topNavPowerToggle
}
Expand All @@ -385,24 +431,34 @@ export default class GeneralSettings extends Mixins(StateMixin) {
})
}
get powerDevicesList () {
get topNavPowerToggleDevicesList () {
const devices = this.$store.getters['power/getDevices'] as Device[]
const deviceEntries = devices.length
? [
{ header: 'Moonraker' },
...devices.map(device => ({ text: device.device, value: device.device }))
...devices.map(device => ({
text: `${this.$filters.prettyCase(device.device)} (${device.type})`,
value: device.device
}))
]
: []
const pins = this.$store.getters['printer/getPins'] as OutputPin[]
const pinEntries = pins.length
? [
{ header: 'Klipper' },
...pins.map(outputPin => ({ text: outputPin.prettyName, value: `${outputPin.name}:klipper` }))
...pins.map(outputPin => ({
text: outputPin.prettyName,
value: `${outputPin.name}:klipper`
}))
]
: []
return [
{
text: this.$tc('app.setting.label.none'),
value: null
},
...deviceEntries,
...pinEntries
]
Expand Down
7 changes: 7 additions & 0 deletions src/locales/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ app:
more_information: More information
multiply: Multiply
pause: Pause
power_on_printer: Power On Printer
preheat: Preheat
presets: Presets
preview_gcode: Preview Gcode
Expand Down Expand Up @@ -238,6 +239,9 @@ app:
failed_components: >-
Moonraker has failed plugins, please check your logs, update your
configuration and restart moonraker.
printer_powered_off: >-
The printer is currently powered off.<br/><br/>
To power on the printer, please click the button on the left.
label:
accel_to_decel: Accel to Decel
acceleration: Acceleration
Expand Down Expand Up @@ -480,6 +484,7 @@ app:
estop: Emergency Stop
managed_by_moonraker: Managed by your moonraker configuration
notifications: Notifications
power_on_printer: Turns on the power to the printer
reload_klipper: Reloads klipper configuration.
reload_restart_klipper: Reloads klipper configuration and restarts MCU's.
restart_klipper: Restarts the klipper system service.
Expand Down Expand Up @@ -557,6 +562,7 @@ app:
auto_follow_on_file_load: Automatically follow progress on file load
auto_load_on_print_start: Automatically load file on print start
auto_load_mobile_on_print_start: Automatically load file on mobile devices
auto: Auto
axes: Axes
camera_flip_x: Flip horizontally
camera_flip_y: Flip vertically
Expand Down Expand Up @@ -627,6 +633,7 @@ app:
print_in_progress_layout: Print in Progress layout
print_progress_calculation: Print Progress calculation
printer_name: Printer Name
printer_power_device: Printer power device
reset: Reset settings
retraction_icon_size: Retraction Icon Size
right_y: Right Y-Axis
Expand Down
13 changes: 13 additions & 0 deletions src/mixins/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Vue from 'vue'
import { SocketActions } from '@/api/socketActions'
import { Component } from 'vue-property-decorator'
import type { Macro } from '@/store/macros/types'
import type { Device } from '@/store/power/types'

@Component
export default class StateMixin extends Vue {
Expand Down Expand Up @@ -74,6 +75,18 @@ export default class StateMixin extends Vue {
return this.printerState.toLowerCase() === 'printing'
}

get printerPoweredOff (): boolean {
if (this.klippyConnected) {
return false
}

const printerPowerDevice: string = this.$store.state.config.uiSettings.general.printerPowerDevice ?? 'printer'

const device = this.$store.getters['power/getDeviceByName'](printerPowerDevice) as Device | undefined

return device?.status === 'off'
}

/**
* Indicates if we have a valid wait(s).
* Supports a single string or a list of.
Expand Down
1 change: 1 addition & 0 deletions src/store/config/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ export const defaultState = (): ConfigState => {
showUploadAndPrint: true,
flipConsoleLayout: false,
cameraFullscreenAction: 'embed',
printerPowerDevice: null,
topNavPowerToggle: null,
showManualProbeDialogAutomatically: true,
showBedScrewsAdjustDialogAutomatically: true,
Expand Down
1 change: 1 addition & 0 deletions src/store/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export interface GeneralConfig {
showUploadAndPrint: boolean;
flipConsoleLayout: boolean;
cameraFullscreenAction: CameraFullscreenAction;
printerPowerDevice: null | string;
topNavPowerToggle: null | string;
showManualProbeDialogAutomatically: boolean;
showBedScrewsAdjustDialogAutomatically: boolean;
Expand Down

0 comments on commit 96a1ca5

Please sign in to comment.