mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-17 11:25:48 +02:00
dev
7
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
ebc72e1d41 |
fix(archives): keep the project name when the wrong-plate guard rejects a 3MF (issue #3126)
Bambu Studio files a sliced print on the X2D's internal eMMC, which FTPS does not serve. The bounded probe found a same-named file on the card -- an earlier slice of the same project, plate 4, against a running plate 1 -- and #1204's guard correctly refused it rather than archive another plate's thumbnail, filament and cost. It then blanked subtask_name because swap_plate_suffix returned None. But None also means "this name carries no plate suffix", and such a name holds no stale plate number to be wrong about. The project name was dropped, the row fell through to the gcode_file path, and the archive was titled plate_1. Keep the name for the title only. subtask_name itself stays disowned, because it is what every lookup here is built from and it keys _active_prints, where the cover endpoint's own download of that same name would find this archive and hand the contradicted file to _recover_fallback_archive -- which checks a candidate is a readable 3MF and never which plate it holds. A corrected name is still registered: that one points at the plate actually running. Also name the X2D alongside H2-series and P2S in the Archives banner, the connection diagnostic and the storage-verdict docs -- it stores slicer sends the same way, and an X2D owner was told the explanation did not apply. |
||
|
|
a4cfbd4212 |
fix(archives): come back for a 3MF whose transfer ran out of time (issue #3063)
The reporter's P1S had the sliced file on its card and was serving it. The 19MB transfer just did not finish inside the budget while the printer was also running its camera, its status messages and the upload of the job itself. Bambuddy wrote an empty fallback archive and never looked again -- then downloaded that same file successfully three times over the next two minutes and discarded every copy, because the only code that would have attached one had already run. The recovery machinery was there. It was armed for exactly one give-up, the FTPS cool-off, on the grounds that the three storage verdicts are settled: a job on internal eMMC never appears at any FTPS path, and sweeping for it again is what where the file is demonstrably still on the card. The sweep already had the signal and never used it. A file that is genuinely not there is answered with 550, which surfaces as FileNotOnPrinterError and is caught by name; a timeout returns falsy instead. So "the printer says no such file" and "we never got a straight answer" are distinguishable without guessing, and only the second schedules anything. Not scheduled either for a 3MF that downloaded fine and turned out to be another plate's. Recovery checks that a candidate is a readable 3MF but not which plate it holds, and the names a retry would use are the same stale ones that fetched the contradicted file -- so it would put back exactly what #2957 discards. The ladder follows the cause: a cool-off has to expire, so its first attempt sits past the 300s; nothing has to expire here, and this reporter's file completed 48 seconds after the budget was spent. The archives banner gets its own wording for this, because the old text sends an owner whose card is working to switch on a setting that is already on. It names the Connection Timeout setting instead. |
||
|
|
5dd7bd213f |
Read a print's destination from the report topic, not just the request one (issue #1820)
current_project_url was assigned in exactly one place, _handle_request_message, and _on_message calls that only for the request topic. A print started from the printer's own screen publishes nothing there, so the field stayed None for the one case the storage verdict exists for: the file is already in the printer's model library under /userdata/model/history/, which port 990 does not serve. The verdict then fell through to the sdcard flag, and @ojimpo's H2S reports that flag true -- its "card" is the internal eMMC -- so every such print ran the full sweep before giving up. He measured one: 16 filename-and-directory attempts over 22 FTPS connections, 18 of them refused, 6.4 seconds, then a fallback archive holding a name and nothing else. The printer does announce where the file lives, as an unsolicited project_file *response* on the report topic about two seconds before gcode_state reaches PREPARE. _process_message now reads the url off it, gated on result SUCCESS and a non-empty value so a refused dispatch cannot name a file that was never written. Reading it there rather than only at the request topic also covers an install neither of us had in view: some brokers refuse the request-topic subscription, and on those no print of any kind had ever populated the field. The new branch captures state and nothing else. The "External project_file payload" diagnostic stays with the request-topic handler: our own dispatch is echoed on both topics, the request-topic echo lands first and clears _own_project_file_key, so reusing the diagnostic here would have logged every Bambuddy-started print as somebody else's. A test pins that. What the print names is now what gets tried -- the five directories a copy could be in, rather than the ~110 connections that cannot succeed. The probe is still worth running: an H2S keeps recently used jobs under /cache and archives them in full while they last, which is why the reporter's two prints on the same day behaved differently. Slicer-sent prints are unchanged. The banner no longer describes a step that never happened. With no reason recorded, a blank archive fell back to the original wording -- "Store sent files on external storage" is off in your slicer -- which on that printer is on, and which the internal-storage wording from #2780 already explains would not help on an H2. The archive that most needed that explanation was the only one that could not be given it. So file:///userdata/ now earns its own reason, internal_history, separate from the brtc://emmc dispatch case. A dispatch chose internal storage and can be aimed elsewhere; a print of a file that was already there had no dispatch at all, and telling that operator to pick External in Send names a dialog they never opened. The banner and the connection diagnostic both read the verdict's reason rather than a fixed one, so the two surfaces cannot give the same printer different advice. Thirteen locales, and a wiki section the banner links to. ----- Read the K-profile selection when the mutation runs, not when it is captured Configure Slot sends cali_idx from selectedKProfile, and the mutation read it through its own closure. React Query hands a mutation its options from an effect, so a click landing between a commit and that effect flushing runs the previous render's mutationFn -- one that captured the selection as it was before the K-profile query resolved. The payload then carries cali_idx -1 and the printer binds the default 0.020 instead of the calibrated K, while the dialog shows the right profile selected throughout. It surfaced as an intermittent failure of the per-nozzle K-profile test, about one full-suite run in six. Reproducing it with staggered query resolution showed the divergence directly: the select element held the correct profile immediately before and after the click, and the payload still carried -1. That test's slot is the most exposed case in the file -- a right-hotend slot carrying the left hotend's index, where the "keep showing the active profile" safety net cannot repair an empty recompute. The selection now goes through a ref written during render, so the mutation resolves it at execute time. An effect would have inherited the same flush ordering this exists to escape. The K value and the profile's ids travel in the same payload and had the same exposure, so they move with it. Measured over a staggered-resolution grid: 2 failures in 15 runs before, 0 in 12 after. api.getSlicerPrinterModels was also missing from the test file's mock, so that query ran with no query function and rejected in all 37 tests -- mocked now, though on its own it changed nothing, which is how the ref was confirmed as the fix rather than assumed. |
||
|
|
4e79f9c2f7 |
Fill in a fallback archive when the 3MF finally arrives (issue #2957)
A failed TLS handshake pauses a printer's file service for five minutes, and the archive flow checks that pause at the top of its path loop and gives up before opening a connection. A print that starts inside one gets an empty fallback archive 13 milliseconds later, having never touched the network. Four minutes on, the pause clears and the cover endpoint downloads the same file, parses it, takes a thumbnail out of it, and publishes it to the shared 3MF cache under the exact key the archive flow looks up. Nothing ever looks: all three readers of that cache run before or during the print-start handler that already gave up, and print completion drops the cache as its first act, deleting the file. No path existed by which a fallback archive could become a real one. Offer a later 3MF to the running print's archive, filling the existing row rather than adding a second -- the row id carries the energy reading, the timelapse session and the start notification. That covers the reported case at no network cost, since opening the printer card already downloads the file. Schedule a bounded retry when the pause is what caused the fallback, spending the cache first and the printer only if that misses. Not scheduled for the other cause: a print kept on internal eMMC has no FTPS copy to come back for, and retrying it is the sweep removed in #2780. The two reasons are now recorded separately instead of both landing as "no 3MF". Recovery refuses anything that is not a readable 3MF -- a truncated download would replace an honest empty archive with wrong metadata -- and leaves an archive alone once it has a real file. Three things the recovery path has to get right, each with a test: Reduce every retry candidate to a bare name. MQTT hands `filename` over as "/data/Metadata/plate_1.gcode" on some firmware, and joining that onto the temp directory yields the absolute path itself, so the retry is fed the flow's own sanitised candidate list and strips the path again on its own account. Serialise recovery per printer. The cover endpoint's single-flight coalesces by view, so two views race each other, and the retry task and print completion can land on top of either -- each reads file_path == "" and runs a full copy, leaving the row on one timestamped directory and the rest orphaned. Keep looking for photos in the pre-recovery directory. `archive_dir` derives from `file_path`, so filling the row moves the archive's directory, and a photo uploaded to the empty card while the print ran stays where it was put. |
||
|
|
607b34e94d |
Check the card before writing a print off as internal-storage-only (issue #2856)
A print's dispatch says where the printer put the sliced file: ftp://<name> for external storage, brtc://emmc/<name> for internal. Since that there is then no file to find at any path. That is where the printer chose to put it, which is not the same as where port 990 can read it. The reporter's H2D - firmware 01.03.00.00, card in the slot - reports brtc://emmc and keeps the same file under /cache: his log has every print from 08-12 downloading from there, 19 MB included, until the skip landed and two days of archives came out as a name and nothing else. #2780's P2S and H2C really did 550 on every path, so both are true and the URL alone cannot tell them apart. So ask the printer rather than the model. The dispatch names the exact file, which turns the question into one connection walking five directories - against the sweep's ~110, which is the cost that made skipping worth doing. A hit archives normally and is shared with the cover endpoint; a miss keeps #2780's fallback archive and its reason, so the archives banner still explains itself. Not probed when the printer reports an empty slot, or while its file service is in TLS cool-off: both have already answered the question. The connection diagnostic asked the same question off the URL and warned that the last print was out of reach. On this reporter's printer that warning would have sent him to a setting that was already right, so it now probes too - by directory listing, since the file it is asking about can be tens of megabytes and the answer is a yes or a no. Capped at 6s to stay inside the support bundle's per-printer budget, and "could not check" leaves the warning standing. The probe filename arrives over MQTT and becomes both a remote path and a local temp filename, so names carrying separators, traversal or control characters are declined rather than cleaned. |
||
|
|
2c7df27d1a |
Look for a print's file when the printer says it is on the card
(#2780 regression) A print of a file already on the printer -- a reprint from the touchscreen, from Handy, or a slicer send-to-storage followed by a print -- reports its location as a path rather than as a fresh upload: file:///media/usb0/<name>. Since #2780 landed on 2026-08-14 Bambuddy read anything that was not ftp:// as "the printer kept this internally", skipped the FTPS sweep, and archived the print with a name and timing only. Measured on an H2D: the file was listable and downloadable over FTPS at the moment Bambuddy declared it unreachable. Before that change those prints archived normally, so this is a regression, and it is not confined to the H2 series the change was about -- an X1C reprint from its own screen loses its thumbnail exactly the same way. That module's own rule is to skip only on positive evidence, and a file:// path is not evidence of internal storage. It now reads the path: the printer's model cache under /userdata is a genuine skip, anything else is unknown and sweeps, which is what it did before. Unknown rather than external on purpose -- the empty-slot check still runs ahead of it, so a file:// print on a printer with nothing in the slot reports the missing card instead of sweeping for something that cannot be there. The user-facing copy shipped this morning is corrected in the same change, because it was written before we understood how Bambu Studio actually chooses. Its Print button always uses internal memory; only Send offers Cache or External, and that defaults to Cache too. So the advice now leads with the two routes that take one step -- start the print from Bambuddy, or slice in OrcaSlicer -- and offers Send-with-External and a separate print start as the way to stay in Bambu Studio. The earlier wording named no remedy at all and blamed the printer's firmware for a choice the slicer makes. Banner and diagnostic, thirteen locales, README, bundle rebuilt. |
||
|
|
fffa68ec55 |
Explain a print that never reached the printer's card, instead of sweeping for it (#2780)
Bambuddy reads a print's 3MF, cover and timelapse over FTPS on port 990, which on every Bambu model serves external storage only. Under some configurations H2-series and P2S firmware keeps the sliced file on internal storage, where Bambu Studio put it over the port-6000 service, and then no path on 990 can find it. The print command has always said which of the two it used -- `url` reads ftp://<name> or brtc://emmc/<name>. We discarded it and swept anyway: ~110 connections per print, all certain to fail, ending in an archive card with nothing on it and no stated reason. In the reporter's bundle all 35 dispatches to their H2C and P2S said internal storage, all 25 to their X1C said external, and all 44 empty cards belonged to the first two. Read the field, skip the sweep when it cannot succeed, and record which reason applied. A printer that uses the card is unaffected, and so is one we have no answer for -- silence is not evidence, and reading it as bad news would break archives that work today. The answer is held per print and dropped when that print ends, rather than kept as a standing fact about the printer. Plenty of prints never announce themselves: 14 of the 79 print starts in that bundle arrived with nothing on the request topic, started from the printer's own screen or picked up after a restart. Left standing, one slicer print to internal storage would suppress the lookup for every screen-started print after it, on a printer whose files really are on the card. The sticky reading is kept for the connection diagnostic alone, which is run after the print that prompted it and would otherwise have nothing to report. Two things that pointed the wrong way go with it. The archives banner told everyone to enable "Store sent files on external storage"; the reporter had it on for the whole three weeks and it would not have helped. The diagnostic passed a printer whose slot was empty, because it read only the toggle -- an empty slot is now a failure naming the slot, and a printer that has storage and still used its own is a warning. On P1-series that empty-slot failure yields to the existing unsupported-model skip: the toggle cannot be switched on there at all, so telling the operator to insert a card would promise a fix inserting a card does not deliver (#2524). Also close FTP sockets on the failure paths, which dropped them for the garbage collector -- 1813 in a day in that bundle -- and drop the advice to restart the printer, which the reporter tried twice while a single manual connection to the same printer handshook cleanly. This does not make the affected prints archive in full; that needs the port-6000 protocol tracked in #2762. |