From a7f7622f9fede91af990a7ec4ba85aee1abe3b09 Mon Sep 17 00:00:00 2001 From: Mathis Mensing Date: Sat, 3 Feb 2024 21:11:30 +0100 Subject: [PATCH] feat(spoolman): multi-tool support (#1324) Signed-off-by: Mathis Mensing Co-authored-by: Pedro Lamas --- docs/assets/images/spoolman-multitool.png | Bin 0 -> 34219 bytes docs/features/spoolman.md | 43 +++++++ .../widgets/spoolman/SpoolSelectionDialog.vue | 43 ++++++- .../widgets/spoolman/SpoolmanCard.vue | 109 +++++++++++++++++- .../widgets/toolhead/ToolChangeCommands.vue | 24 +++- src/locales/de.yaml | 5 +- src/locales/en.yaml | 5 +- src/scss/misc.scss | 9 ++ src/store/spoolman/actions.ts | 1 - src/store/spoolman/getters.ts | 6 +- src/store/spoolman/state.ts | 3 +- src/store/spoolman/types.ts | 10 ++ 12 files changed, 237 insertions(+), 21 deletions(-) create mode 100644 docs/assets/images/spoolman-multitool.png diff --git a/docs/assets/images/spoolman-multitool.png b/docs/assets/images/spoolman-multitool.png new file mode 100644 index 0000000000000000000000000000000000000000..ac85254f6bd1739fef5a73a5f8153aa8fba3fada GIT binary patch literal 34219 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 NV(+Ad3Iuh({C^879t8jZ literal 0 HcmV?d00001 diff --git a/docs/features/spoolman.md b/docs/features/spoolman.md index e8627dd741..7c0e3b948b 100644 --- a/docs/features/spoolman.md +++ b/docs/features/spoolman.md @@ -42,3 +42,46 @@ When starting a print or changing spools, Fluidd will automatically perform thes 1) a spool is selected 2) the selected spool has enough filament left on it to finish the print job 3) the selected spool's filament type matches the one selected in the slicer + +### Toolchanger Support +Fluidd supports selecting spools for individual toolchange macros. +For toolchange macros to show up in the "Change Spool" dropdown, simply add a `spool_id` +variable to your toolchange `gcode_macro`s with a default value of `None`. +You will also need to call the [`SET_ACTIVE_SPOOL`](https://moonraker.readthedocs.io/en/latest/configuration#setting-the-active-spool-from-klipper) +macro in an appropriate place in your toolchange macro. + +```yaml +[gcode_macro T0] +variable_spool_id: None +gcode: + ... + SET_ACTIVE_SPOOL ID={ printer['gcode_macro T0'].spool_id } + ... +``` + +![screenshot](/assets/images/spoolman-multitool.png) + +#### Remembering associated spools across restarts +By default, Klipper does not keep track of Gcode macro variables across restarts. +If Fluidd detects a [`[save_variables]`](https://www.klipper3d.org/Config_Reference.html#save_variables) +section in your configuration, it will automatically emit a `SAVE_VARIABLE` command +on spool selection, saving the selected spool to the `__SPOOL_ID` variable. + +You can use the following macro to restore the previous selection after a restart: +{% raw %} +```sh +[delayed_gcode RESTORE_SELECTED_SPOOLS] +initial_duration: 0.1 +gcode: + {% set svv = printer.save_variables.variables %} + {% for object in printer %} + {% if object.startswith('gcode_macro ') and printer[object].spool_id is defined %} + {% set macro = object.replace('gcode_macro ', '') %} + {% set var = (macro + '__SPOOL_ID')|lower %} + {% if svv[var] is defined %} + SET_GCODE_VARIABLE MACRO={macro} VARIABLE=spool_id VALUE={svv[var]} + {% endif %} + {% endif %} + {% endfor %} +``` +{% endraw %} diff --git a/src/components/widgets/spoolman/SpoolSelectionDialog.vue b/src/components/widgets/spoolman/SpoolSelectionDialog.vue index 1f857c42dd..7b58c58104 100644 --- a/src/components/widgets/spoolman/SpoolSelectionDialog.vue +++ b/src/components/widgets/spoolman/SpoolSelectionDialog.vue @@ -6,7 +6,7 @@ title-shadow > @@ -198,7 +198,7 @@ import { Component, Mixins, Watch } from 'vue-property-decorator' import StateMixin from '@/mixins/state' import { SocketActions } from '@/api/socketActions' -import type { Spool } from '@/store/spoolman/types' +import type { MacroWithSpoolId, Spool } from '@/store/spoolman/types' import BrowserMixin from '@/mixins/browser' import QRReader from '@/components/widgets/spoolman/QRReader.vue' import type { CameraConfig } from '@/store/cameras/types' @@ -224,6 +224,10 @@ export default class SpoolSelectionDialog extends Mixins(StateMixin, BrowserMixi onOpen () { if (this.open) { this.selectedSpoolId = this.$store.state.spoolman.activeSpool ?? null + if (this.targetMacro) { + const macro: MacroWithSpoolId | undefined = this.$store.getters['macros/getMacroByName'](this.targetMacro.toLowerCase()) + this.selectedSpoolId = macro?.variables.spool_id ?? null + } if (this.currentFileName) { // prefetch file metadata @@ -327,6 +331,10 @@ export default class SpoolSelectionDialog extends Mixins(StateMixin, BrowserMixi return this.$store.getters['files/getFile'](filepath ? `gcodes/${filepath}` : 'gcodes', filename) } + get targetMacro (): string | undefined { + return this.$store.state.spoolman.dialog.targetMacro + } + get cameras () { const cameras = this.$store.getters['cameras/getEnabledCameras'] .filter((camera: CameraConfig) => camera.service !== 'iframe') @@ -444,6 +452,30 @@ export default class SpoolSelectionDialog extends Mixins(StateMixin, BrowserMixi } } + if (this.targetMacro) { + // set spool_id via SET_GCODE_VARIABLE + const commands = [ + `SET_GCODE_VARIABLE MACRO=${this.targetMacro} VARIABLE=spool_id VALUE=${this.selectedSpool ?? 'None'}` + ] + + const supportsSaveVariables = this.$store.getters['printer/getPrinterConfig']('save_variables') + if (supportsSaveVariables) { + // persist selected spool across restarts + commands.push(`SAVE_VARIABLE VARIABLE=${this.targetMacro.toUpperCase()}__SPOOL_ID VALUE=${this.selectedSpool ?? 'None'}`) + } + + await SocketActions.printerGcodeScript(commands.join('\n')) + + const macro: MacroWithSpoolId | undefined = this.$store.getters['macros/getMacroByName'](this.targetMacro.toLowerCase()) + if (macro?.variables.active) { + // selected tool is active, update active spool + await SocketActions.serverSpoolmanPostSpoolId(this.selectedSpool ?? undefined) + } + + this.open = false + return + } + await SocketActions.serverSpoolmanPostSpoolId(this.selectedSpool ?? undefined) if (this.filename) { await SocketActions.printerPrintStart(this.filename) @@ -452,6 +484,7 @@ export default class SpoolSelectionDialog extends Mixins(StateMixin, BrowserMixi this.$router.push({ path: '/' }) } } + this.open = false } diff --git a/src/components/widgets/spoolman/SpoolmanCard.vue b/src/components/widgets/spoolman/SpoolmanCard.vue index fbeba57a47..fc1b394dc1 100644 --- a/src/components/widgets/spoolman/SpoolmanCard.vue +++ b/src/components/widgets/spoolman/SpoolmanCard.vue @@ -7,13 +7,87 @@ > $filament @@ -134,8 +209,9 @@ diff --git a/src/components/widgets/toolhead/ToolChangeCommands.vue b/src/components/widgets/toolhead/ToolChangeCommands.vue index 748b3b3668..48175394c3 100644 --- a/src/components/widgets/toolhead/ToolChangeCommands.vue +++ b/src/components/widgets/toolhead/ToolChangeCommands.vue @@ -22,8 +22,15 @@ v-on="on" @click="sendGcode(macro.name)" > + + $filament +