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

fix(spoolman): improve sanity check logic #1411

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
122 changes: 67 additions & 55 deletions src/components/widgets/spoolman/SpoolSelectionDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ import QRReader from '@/components/widgets/spoolman/QRReader.vue'
import type { WebcamConfig } from '@/store/webcams/types'
import QrScanner from 'qr-scanner'
import type { AppTableHeader } from '@/types'
import getFilePaths from '@/util/get-file-paths'

@Component({
components: { QRReader }
Expand Down Expand Up @@ -230,7 +231,15 @@ export default class SpoolSelectionDialog extends Mixins(StateMixin, BrowserMixi

if (this.currentFileName) {
// prefetch file metadata
SocketActions.serverFilesMetadata(this.currentFileName)
if (!this.currentFile && this.currentFileName.includes('/')) {
// if the file is in a subdirectory and isn't cached
// we need to populate the cache
const { rootPath } = getFilePaths(this.currentFileName, 'gcodes')
SocketActions.serverFilesGetDirectory('gcodes', rootPath)
} else {
// otherwise just refresh the corresponding file
SocketActions.serverFilesMetadata(this.currentFileName)
}
}

if (this.hasDeviceCamera && this.preferDeviceCamera) {
Expand Down Expand Up @@ -323,10 +332,8 @@ export default class SpoolSelectionDialog extends Mixins(StateMixin, BrowserMixi
}

get currentFile () {
const splitFilepath = this.currentFileName.split('/')
const filename = splitFilepath.pop()
const filepath = splitFilepath.join('/')
return this.$store.getters['files/getFile'](filepath ? `gcodes/${filepath}` : 'gcodes', filename)
const { filename, rootPath } = getFilePaths(this.currentFileName, 'gcodes')
return this.$store.getters['files/getFile'](rootPath, filename)
}

get targetMacro (): string | undefined {
Expand Down Expand Up @@ -383,11 +390,40 @@ export default class SpoolSelectionDialog extends Mixins(StateMixin, BrowserMixi
}
}

if (this.targetMacro) {
// no need to run sanity checks or start a print when we target a macro, so we return early

// 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
}

const spool = this.availableSpools.find(spool => spool.id === this.selectedSpool)
if (spool && this.filename && (this.warnOnFilamentTypeMismatch || this.warnOnNotEnoughFilament)) {
let requiredLength = 0 // l[mm]
if (spool && this.currentFileName && (this.warnOnFilamentTypeMismatch || this.warnOnNotEnoughFilament)) {
// trigger sanity checks when we have an active file
// (current print or new print) and sanity checks are enabled.

if (this.currentFile && (this.filename || !['complete', 'cancelled'].includes(this.printerState))) {
// if we're tracking a file and starting a new print or the current one hasn't ended yet

if (this.currentFile) {
if (this.warnOnFilamentTypeMismatch) {
const fileMaterials = this.currentFile.filament_type?.toLowerCase()
.split(';').map((x: string) => x.replace(/"/g, ''))
Expand All @@ -406,71 +442,47 @@ export default class SpoolSelectionDialog extends Mixins(StateMixin, BrowserMixi
}
}

requiredLength = this.currentFile?.filament_total ?? 0
if (this.$store.getters['printer/getPrinterState'] !== 'idle') {
// subtract already printed length
let requiredLength = this.currentFile?.filament_total
if (requiredLength && ['printing', 'paused'].includes(this.printerState)) {
// if we're currently running a print job, subtract the already printed amount from the required length
requiredLength -= this.$store.state.printer.printer.print_stats?.filament_used ?? 0
requiredLength = Math.max(requiredLength, 0)
}
}

if (!requiredLength) {
// missing file metadata

const confirmation = await this.$confirm(
this.$tc('app.spoolman.msg.no_required_length'),
{ title: this.$tc('app.general.label.confirm'), color: 'card-heading', icon: '$warning' }
)

if (!confirmation) {
return
}
}

if (this.warnOnNotEnoughFilament) {
let remainingLength = spool.remaining_length
if (!remainingLength && spool.remaining_weight) {
// l[mm] = m[g]/D[g/cm³]/A[mm²]*(1000mm³/cm³)
remainingLength = spool.remaining_weight / spool.filament.density / (Math.PI * (spool.filament.diameter / 2) ** 2) * 1000
}

if (typeof remainingLength === 'number' && requiredLength >= remainingLength) {
// not enough filament
if (!requiredLength) {
// missing file metadata

const confirmation = await this.$confirm(
this.$tc('app.spoolman.msg.no_filament'),
this.$tc('app.spoolman.msg.no_required_length'),
{ title: this.$tc('app.general.label.confirm'), color: 'card-heading', icon: '$warning' }
)

if (!confirmation) {
return
}
}
}
}

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'}`
]
if (this.warnOnNotEnoughFilament) {
let remainingLength = spool.remaining_length
if (!remainingLength && spool.remaining_weight) {
// l[mm] = m[g]/D[g/cm³]/A[mm²]*(1000mm³/cm³)
remainingLength = spool.remaining_weight / spool.filament.density / (Math.PI * (spool.filament.diameter / 2) ** 2) * 1000
}

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'}`)
}
if (typeof remainingLength === 'number' && requiredLength >= remainingLength) {
// not enough filament

await SocketActions.printerGcodeScript(commands.join('\n'))
const confirmation = await this.$confirm(
this.$tc('app.spoolman.msg.no_filament'),
{ title: this.$tc('app.general.label.confirm'), color: 'card-heading', icon: '$warning' }
)

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)
if (!confirmation) {
return
}
}
}
}

this.open = false
return
}

await SocketActions.serverSpoolmanPostSpoolId(this.selectedSpool ?? undefined)
Expand Down
2 changes: 1 addition & 1 deletion src/store/printer/getters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const getters: GetterTree<PrinterState, RootState> = {
// If the idle state says we're printing, but the print_stats say otherwise - then
// we're probably busy moving the toolhead or doing some other process.
// Possible values are;
// printing, busy, paused, ready, idle, standby
// printing, busy, paused, cancelled, ready, idle, standby
if (state1 && state2) {
if (
state2.toLowerCase() === 'paused' ||
Expand Down