mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-04 05:01:37 +02:00
6e6c0e06449775565ea7725a264b08806fd232b3
10
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
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. |
||
|
|
91acac2b35 |
Stop retrying a printer whose FTPS handshake fails, and name the cause (#2780)
Two printers went on printing while every archive they produced held nothing but a filename. Bambuddy opened port 990, the printer accepted the connection and answered with something that was not TLS, and connect() logged a warning and returned False -- indistinguishable, to every caller, from "the file is not at this path". So the 3MF lookup walked all six filename variants across five directories with four retries each, the cover endpoint ran its own sixteen-path sweep, and the timelapse scan added four more, all against a sixteen-path sweep, and the timelapse scan added four more, all against a printer that could not have answered any of them. One reporter's log carried 1813 identical handshake failures, another's 3511. The evidence says this is the printer's own file service getting stuck, not a model, firmware or TLS-configuration problem. In #2780's bundle the same two printers ran clean from 22 July to 4 August and failed again from the 5th; a second bundle shows an X2D serving files for five days, flipping on 19 July, then failing every connection for eight days with zero successes. The same models and firmware appear in roughly twenty other bundles with no occurrences at all. Both bundles show it happening with cap_tls_v1_2 in effect -- the X2D and H2C entries in ftp_profiles were added on analogy with P2S to fix exactly this symptom, and the reporter's own debug line proves they do not. An ssl.SSLError from connect() now opens a five-minute cool-off for that printer. Subsequent connects return False without touching the network, so a wedged printer is contacted twice an hour instead of hundreds of times a minute, and the single warning that is logged names the remedy. The cool-off is dropped on expiry rather than kept, so the map holds one key per currently wedged printer. ftps_handshake_blocked() lets the sweeps stop: the 3MF lookup abandons the remaining paths and skips the directory-walk fallback, the cover endpoint returns 503 naming the file service instead of a 404 that reads as "this print has no thumbnail", and the timelapse scan separates 503 (cannot reach the printer) from 404 (no timelapse directory) -- one 500 used to cover both, which is what the reporter hit when reproducing. The Connection Diagnostic completed a bare TCP connect to 990, which is why it reported the port green throughout: the port is open, it is what is behind it that is broken. It now completes a real implicit-TLS handshake using the model's own ftp_profiles cap, so a pass means the FTP client would also get through. An open port that cannot negotiate reports warn with reason no_tls, selecting a new message in all 13 locales that points at a printer restart rather than at the firewall. No login is attempted, so this stays valid in the pre-save Add Printer flow. The cool-off tests run against a real socket that accepts on 990 and replies with a plaintext FTP banner, reproducing WRONG_VERSION_NUMBER rather than mocking ssl. The autouse fixture clearing _mode_cache now clears the cool-off map too -- every test here talks to 127.0.0.1, so one left behind would make the next test's connect() a no-op. |
||
|
|
3abab1fd45 |
fix(printers): recover MQTT sessions that stopped reconnecting (#2732)
The reporter's printer lost its session to a keep-alive timeout at 02:19 and did not come back until 11:24 — nine hours offline, with the web UI open throughout. check_staleness() was never going to catch it. Its first line is `if self.state.connected and self.is_stale()`, so it only ever handles the half-broken session that is still connected but has gone quiet. This client had connected=False from 02:19:42 (the offline notification fired a minute later), so every call returned immediately, and paho's own retry was the only thing left watching. When that stopped making progress nothing noticed. Adds a sweep every 60s that rebuilds a client when all four hold: it is disconnected, it had a working session before, it has been silent for five minutes, and its MQTT port still answers. The port check is what keeps this from becoming a nuisance — a switched-off printer is left to paho, so a farm powering down overnight causes no client churn and no log spam. The five-minute grace sits well past the 60s stale timeout and the 30s max reconnect backoff, so a session recovering on its own is never interrupted. The rebuild goes through force_reconnect_stale_session from async context, which takes the hard-reset path: fresh client_id and paho's QoS 1 queue dropped, so a project_file left unacked on the dead session cannot replay into the new one and trip 0500_4003 (#1136). Rate-limited per printer, cooldown cleared when the printer returns, and the sweep continues past a client that throws rather than abandoning the rest of the farm. The log line names how long the printer was gone and the last connect error, so a session that dies repeatedly leaves a trail. check_port gains a public alias in printer_diagnostic rather than having the watchdog reach for the private name. Also corrects the Developer Mode path added in the previous commit: the wiki documents it under Settings > Network, not Settings > General. The menu path is dropped from the translated string entirely, since it varies by model and firmware and the wiki carries the detail. |
||
|
|
91269f14fe |
fix(mqtt): report why a printer refused the connection instead of looping silently
A printer with a wrong access code gave no explanation anywhere. The connect callback's failure branch was a bare `state.connected = False`, discarding the CONNACK reason code the printer had just sent, so the only trace was paho's follow-up disconnect -- logged every 30 seconds as "rc=Unspecified error", which is exactly what a powered-off printer produces. In the report behind this fix one of three printers had been in that loop for the whole capture, and neither the log nor the support bundle could say why. Bambu speaks MQTT 3.1.1, whose CONNACK return codes 4 and 5 paho maps onto reason codes 134 and 135. Both are now logged with the printer's own reason string and, for those two, the remedy: the access code is regenerated whenever LAN Only or Developer Mode is toggled, so it has to be re-read from the screen. The access code itself is never logged -- it would land in every bundle. The reason is kept on the client as a stable slug and plumbed through test_connection into the connection diagnostic, which now distinguishes two cases it previously conflated. "The printer refused our credentials" is asserted only when the printer said so; when all Bambuddy knows is that there is no session, the text hedges and names the alternatives (rebooting, or already at its limit of simultaneous connections). The old wording claimed the access code was most likely wrong in both cases. Frontend needed no change -- ConnectionDiagnostic already renders `<status>_<reason>` variants with fallback to the plain per-status text, so an unrecognised slug degrades to today's wording rather than a missing key. |
||
|
|
6127e30abf |
fix(diagnostic): skip external-storage check on P1S/P1P instead of fail (#2524)
P1-series printers have a MicroSD slot but no reachable control to enable "Store sent files on external storage": current P1 firmware (through 01.10.00.00) never publishes support_save_remote_print_file_to_storage, so the Bambu Studio toggle never renders, and the P1S has no screen — leaving store_to_sdcard stuck False with no way for the user to change it. The external_storage check reported a permanently-unresolvable fail. Add NO_REMOTE_STORAGE_TOGGLE_MODELS (P1S, P1P) + has_remote_storage_toggle(), kept distinct from the no-slot NO_EXTERNAL_STORAGE_MODELS. When a model has a slot but no reachable toggle and the option is off, the check now emits skip with params reason=unsupported_model rather than fail, and overall no longer escalates. A P1S reporting the option on still passes. Model-scoped and default-open, so X1/P2S/H2 (where the fail is actionable) are unaffected; if a future firmware surfaces the capability, drop the model and it reactivates. The frontend DiagnosticChecklist renders a reason-specific message variant (external_storage.skip_unsupported_model) so P1 users see an accurate explanation instead of the generic "needs a live MQTT connection" skip text. The fix propagates to the support-bundle diagnostic snapshot automatically. |
||
|
|
271560f7cb | Fix camera port diagnostic for A1/P1 printers (#1799) | ||
|
|
e737c84c6e |
fix(diagnostic): skip external_storage check on A1 / A1 Mini (#1703)
A1 and A1 Mini ship without a MicroSD slot at all - there is no firmware-side "Store sent files on external storage" toggle and the slicers don't surface a slicer-side equivalent either. The connection diagnostic was reading state.store_to_sdcard (home_flag bit 11), which is never set on these models, so the check fell through to fail for every A1-series user. Combined with the absent slicer UI it left users thinking Bambuddy was wrong about a setting their hardware does not have. New NO_EXTERNAL_STORAGE_MODELS frozenset in utils/printer_models.py enumerates A1, A1 Mini, and their internal codes (N1, N2S, A04, A11, A12). has_external_storage() returns False for those, True for everything else. Unknown models default to True so the check stays active for future Bambu lineup additions - new no-slot models must be added to the set explicitly. The diagnostic now short-circuits to skip before reading store_to_sdcard when printer.model is in the set. X1, P1, P2S, H2, and X2D are unchanged - the bit-off -> fail signal is still the right read for them. The companion FTP-upload-timeout symptom in the same bug report (ftp code 28 from BambuStudio when sending to the proxy VP) is a separate Docker-bridge-mode networking constraint, not addressed here. |
||
|
|
60e31634b8 |
feat(diagnostic): add "Store sent files on external storage" check (install step 4)
Detects the printer-side variant of install step 4 — many users (esp. on clean installs) forget to enable this and only notice when their archive cards have no thumbnails. The diagnostic now catches it upfront. Detection: read state.store_to_sdcard, which Bambuddy already parses from MQTT push_status home_flag bit 11 (bambu_mqtt.py:153). Instant, no I/O. An FTP upload-and-verify probe was tried first and rejected. /cache is always writable from Bambuddy regardless of the slicer setting — only BambuStudio's own behaviour changes when the toggle flips, not the printer's acceptance policy. Confirmed empirically against X1C + H2D with the slicer option toggled off: probe succeeded, home_flag bit 11 stayed True. So the only reliable signal is what the printer actually reports about its own state. Limitation: the printer-side variant only exists on newer firmware (P2S 01.02 / Bambu Studio 2.6+). On older versions the toggle lives only in the slicer and the printer never hears about it, so this check will pass even when the user is missing step 4 in BambuStudio. The skip-text and the wiki call this out explicitly. A reactive banner on the no-3MF archive-fallback path is planned as a follow-up to cover that case. Statuses: - pass: state.store_to_sdcard is True - fail: state.store_to_sdcard is False (-> overall escalates to problems) - skip: no live state, disconnected, or field never populated |
||
|
|
c571ad86dd |
feat(diagnostic): printer_publishing check + countdown UI (#1622)
The existing connection diagnostic proved TCP + TLS + auth + SUBSCRIBE but not that the printer was actually publishing reports. A wrong-cased serial passes mqtt_auth because the broker accepts the subscription regardless; the user-visible symptom is empty AMS / no K-profiles / no custom filaments in the slicer Device tab because the VP cached state is empty. Bambuddy already logged the actionable hint at bambu_mqtt.py:498 but only to container logs. New printer_publishing check turns that warning into a structured diagnostic result. Pass = bridge has seen at least one report since the last (re)connect; fail = zero reports across the wait window with fix-text pointing at the case-sensitive serial. Bounded 10s poll on the on-demand UI route, no wait on the support-package gathering path so bundling stays fast. Exits the moment a message arrives — typical wall-clock is 1-2s. Frontend renders an elapsed-seconds counter plus a "Listening for status report — up to 10s" hint during the pending state so the wait doesn't look hung. PUBLISH_WAIT_DEFAULT_SECONDS pinned on both sides. report_messages_since_connect exposed as a public property on BambuMQTTClient so the diagnostic doesn't reach into private state. |
||
|
|
76e327f4a1 |
feat: connection diagnostic for "printer won't connect" triage
A triage review of the last 200 closed issues found ~1/3 were
user-side setup errors — printer not in LAN developer mode, blocked
ports, Docker bridge networking, wrong access code, cross-subnet —
each costing a multi-round-trip support exchange.
Add a Connection Diagnostic that runs those checks automatically:
- backend/app/services/printer_diagnostic.py: TCP probes of MQTT
8883 / FTPS 990 / RTSPS 322, LAN developer mode, Docker network
mode, printer/host subnet match, MQTT credential class; each
check returns pass/fail/warn/skip with a localized fix.
- Routes: GET /printers/{id}/diagnostic (saved printer) and
POST /printers/diagnostic (pre-save Add-Printer flow).
- ConnectionDiagnostic.tsx: modal + shared checklist, surfaced from
the printer card actions menu, an offline-printer quick button,
the Add-Printer dialog, and a new System-page section.
- The in-app bug reporter scans configured printers when the form
opens and always shows the result inline — a healthy confirmation,
or the detected problem and its fix.
- config.yml troubleshooting link repointed to the rendered wiki
page; bug_report.yml gains a diagnostic checkbox.
Diagnostic strings translated across all 8 locales. Backend service
unit tests (15) + frontend modal tests (3). Ruff clean, frontend
build clean, i18n parity green.
|