Skip to content
New issue

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

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

Already on GitHub? # to your account

feat: control printer power via Moonraker #1570

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
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.machineDevicePowerToggle(printerPowerDevice, 'on')
}
}
</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
Loading