fix(vp): emit FINISH after FTP upload so Print-flow slicers unwedge (#1280)

Bambuddy's VP supports two slicer flows: Send (file upload only — what
  queue/immediate/review modes are designed for) and Print (file upload
  + start-print, intended for proxy mode). When a user clicks Print
  against a non-proxy mode the VP must still respond gracefully — the
  file is fine to receive, just the start-print never happens. Instead
  the slicer wedged at "Downloading...(0%)" and blocked the next
  dispatch with "The printer is busy with another print job".

  Cause: on_file_received transitioned gcode_state PREPARE -> IDLE
  directly. Print-flow slicers watch the state cycle and only release
  their in-flight-job lock on PREPARE -> ... -> FINISH (or FAILED).
  PREPARE -> IDLE looks like "printer abandoned my job" and keeps the
  prior job pinned in the slicer's memory.

  Fix: transition PREPARE -> FINISH with prepare_percent=100. The 1-Hz
  periodic status push broadcasts the new state to every connected
  slicer within a second. Send-flow slicers don't watch this state so
  the change is a no-op for them; Print-flow slicers see the FINISH
  they were waiting for and unwedge.
This commit is contained in:
maziggy
2026-05-12 10:19:34 +02:00
parent 7596725550
commit 0d6171dc9a
3 changed files with 48 additions and 2 deletions
@@ -217,9 +217,18 @@ class VirtualPrinterInstance:
else:
await self._queue_file(file_path, source_ip)
# Reset MQTT status back to IDLE
# Signal job completion to the slicer. Send-flow slicers don't watch the
# post-upload state and would be happy with anything; the Print flow
# (intended for proxy-mode VPs, but users sometimes click it against
# queue/immediate/review modes too — #1280) watches the gcode_state
# cycle and only releases its in-flight-job lock when it sees FINISH.
# Going PREPARE → IDLE wedges the slicer's UI at "Downloading...(0%)"
# and blocks the next dispatch with "busy with another print job".
# PREPARE → FINISH satisfies both flows. prepare_percent=100 also
# unfreezes the slicer's "Downloading X%" progress bar which it ticks
# against the same field during the upload window.
if self._mqtt and file_path.suffix.lower() == ".3mf":
self._mqtt.set_gcode_state("IDLE")
self._mqtt.set_gcode_state("FINISH", filename=file_path.name, prepare_percent="100")
async def on_print_command(self, filename: str, data: dict) -> None:
"""Handle print command from MQTT."""