Skip to content

Commit 4833e0f

Browse files
committed
v2.26.0 — add your Bambu Lab printers by signing in
An email address, the code Bambu sends back, and every printer on the account is offered with its picture — ticked one or several at a time, each arriving with the LAN access code the cloud hands over, so nothing is read off the machine's screen. Printers added this way are reached through the account's broker and report from anywhere; they learn their own address from their telemetry, so the camera starts unattended on the same network. The cloud sends the very same push_status the LAN broker does, so the parser, the cards and every control are reused untouched. REST goes through Electron's net because api.bambulab.com is behind Cloudflare, which reads the TLS fingerprint. The account token is stored apart from the machines, never on a record meant to be displayed. A printer reached through the cloud now says so: its status dot IS a cloud, same colour code, for Bambu Lab and Anycubic alike. Fixes, all found on live hardware: a Bambu printer stopped reporting anything the moment a print FAILED (state is a number on this firmware and the normaliser lowercased it, from the first line of the merge); its AMS was then recorded as absent in Firestore and stayed missing across restarts; prints showed no preview and carried the gcode path instead of the project name; resizing a camera opened the machine's side panel. Also: i18n:add was silently writing "[object Object]" into all nine locales for any plural, which is how bulkHiddenWarn shipped broken in v2.16.0 and stayed broken for nine releases. Both the tool and the key are repaired.
1 parent 3b21a52 commit 4833e0f

36 files changed

Lines changed: 2047 additions & 80 deletions

‎CHANGELOG.md‎

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,40 @@ Versions follow [Semantic Versioning](https://semver.org/).
55

66
---
77

8+
## v2.26.0 — 2026-08-31
9+
10+
### Added
11+
12+
- **Add a Bambu Lab printer with your account** — a third way in beside scanning the network and typing an IP, and the easy one. An email address, the code Bambu sends back, and every machine on the account appears, each already carrying its own LAN access code because the cloud simply hands it over: nothing has to be read off the printer's screen. Machines added this way are reached through Bambu's cloud, so they report from anywhere rather than only from the same network. The decisive economy is that the cloud broker sends the very same `print.push_status` the LAN one does, so cloud telemetry is emitted on the SAME renderer channel and the parser, the cards, the job block, the temperatures, the AMS and every control are reused untouched; what differs is ONE client for the ACCOUNT rather than one per printer, and an account token instead of a per-machine code. REST goes through Electron's `net` rather than node or global fetch, deliberately: `api.bambulab.com` sits behind Cloudflare, which judges callers by their TLS fingerprint and answers plain HTTP clients with a 403 challenge (the reference Python implementation reaches for `cloudscraper`/`curl_cffi` for exactly this) — Electron's `net` IS Chromium's stack, so no impersonation is needed. Region is `us` first with an `eu` fallback on refusal, and `pushall` is asked for on every (re)connection because a P1 sends only deltas. Expired and wrong codes are told apart (`code: 1` vs `code: 2`), one needing a new code and the other a better one. The account session — token, uid, region — is stored ONCE under `printers/bambulab/secrets/`, never on a machine's own record: Firestore serves documents whole, so a secret sitting in a printer's record would travel with it the day printers become friend-visible. Sign-in, uid resolution and the machine list are verified end to end against a live account. Protocol reference: `renderer/printers/bambulab/PROTOCOL.md` §17 — `main.js`, `preload.js`, `renderer/printers/bambulab/{index,add-flow,probe,settings}.js`, `renderer/printers/context.js`, `renderer/inventory.js`, `renderer/css/40-printers.css`.
13+
- Machines are **ticked, one or several, and added together** by a single key carrying the count. Adding one per click closed the panel each time, so taking three meant signing in three times over — and the emailed code is single-use. A run where some fail says so and stays open rather than closing over a half-done job.
14+
- They are offered **with their picture**, laid out like a network-scan result, so an X1C is told from a P1P at a glance rather than by reading serials. A raw dump of the account's machine list sits beneath them in debug mode only, with a copy key.
15+
- **A cloud printer picks up its own LAN credentials, and its camera comes on by itself.** The cloud hands over the access code and the serial; the machine's own telemetry carries its address — advertised in its camera URL, or as a LITTLE-ENDIAN integer in `net.info[0].ip`, where the first byte of the address is the low byte of the number (`1846847680` → `192.168.20.110`, agreeing with the camera URL in the same payload). The address is re-checked on every report rather than adopted once, because it is a DHCP lease; on a real change the stream is torn down before it is restarted.
16+
- A cloud printer arrives with its **real model**, resolved from the code the cloud reports with the serial's prefix as fallback — it decides both the picture and the camera transport. `BL-P001`, what the cloud calls an X1 Carbon, was missing from the code table. A printer whose model never resolved now corrects itself from its serial on the first report.
17+
18+
### Changed
19+
20+
- **A printer reached through the cloud says so: its status dot IS a cloud.** Same colour code — green when it answers, grey when it does not — a different shape, on the board card and in the side panel, for BOTH brands that have a cloud mode (Bambu Lab and Anycubic), keyed off the `mode: "cloud"` they both already store. Nothing distinguished them before in either brand, and the two do not behave alike once you leave the house: a LAN machine simply becomes unreachable while a cloud one keeps answering, so when one goes quiet, knowing which you are looking at is what says whether anything is wrong. The glyph is drawn by a pseudo-element rather than by the dot itself — masking is applied AFTER filtering, so a glow put on a masked element (`box-shadow` or `drop-shadow` alike) is clipped away with everything outside the silhouette; left unmasked, the dot carries the halo it already had and reuses `printer-name-dot-pulse` unchanged. The icon is a new FILLED cloud (`icon_cloud_filled.svg`): masking the outline one painted only the outline, giving a hollow ring. Anycubic carried a `connLan` field whose comment claimed the card already did this; nothing read it — `renderer/inventory.js`, `renderer/css/40-printers.css`, `renderer/css/70-detail-misc.css`.
21+
- **Add-a-product refuses a zero where a zero is not a measurement.** Weight, both nozzle temperatures, both bed temperatures and the drying pair floor at 1, corrected AS YOU TYPE rather than refused at save: a lone `0` becomes `1` on the spot. The floor is read from each field's own `min`, mirroring the ceiling already applied from `max`, so a field's bounds stay declared in one place; typing is not fought, since reaching 50 by typing `5` then `0` leaves `50`, already above the floor. Empty stays empty — the drying pair is optional and blank is how "needs no drying" is said. The save path enforces the same floor for values that never passed through the keyboard: picking a material seeds these fields, and 7 of the 113 recommend a 0 — `renderer/inventory.js`, `renderer/inventory.html`.
22+
- The **+ beside the inventory search is a filled accent button** with a white glyph (`--primary` / `--on-accent`) instead of a grey `+` on nothing. It is the way in to adding a spool and it sits inside a field that reads as somewhere to type, so it has to look like a button — `renderer/css/70-detail-misc.css`.
23+
24+
### Fixed
25+
26+
- **A Bambu printer stopped reporting anything the moment a print FAILED** — filament, temperatures, job, all of it. `print.state` is a NUMBER on this firmware (7 on an X1C) and the state normaliser called `.toLowerCase()` on it, from the FIRST line of the merge, so the exception took the whole message down and nothing after it was ever read; the board fell back to the external spool alone. It only fires in the branch that looks for a second opinion when the printer reports FAILED or ERROR, which is why it lay dormant for months and surfaced the day a print failed. Only string candidates are considered now — `renderer/printers/bambulab/index.js`.
27+
- **A Bambu printer's AMS was recorded as ABSENT and stayed that way across restarts.** The units a driver reports are treated as the whole truth by the layer that stores them: anything unmentioned is written `present: false` onto the machine's record. But a printer sends one complete state and then DELTAS, and a delta carries no filament — so a connection questioned before its full state arrived answered with the external spool alone and the AMS was filed as gone, in Firestore, where reloading could not undo it. Units are reported only once AMS data is held or a full state has been seen (`msg: 0`, or any payload carrying an AMS block, since some firmwares omit the field); the stored record is shown meanwhile, marked stale, and repairs itself on the next complete state — `renderer/printers/bambulab/index.js`.
28+
- **A Bambu print showed no preview, and carried the wrong name.** The hint used to find the model was `gcode_file` — a path INSIDE the archive, `/data/Metadata/plate_1.gcode` — while the `.3mf` on the printer is named after the job (`TigerPod_Mini_A1.3mf`). The lookup searched for `plate_1.3mf`, which exists nowhere; the same value put `plate_1.gcode` on the card where Bambu's own app shows the project name. The job name comes first now, the gcode path remaining the fallback — `renderer/printers/bambulab/index.js`.
29+
- **A cloud printer's filament slots vanished moments after connecting.** Learning its own address made the renderer read it as a different machine on the next tick — the record held no address until Firestore echoed the write back — so the session was torn down and rebuilt with empty data, repeatedly, writing to Firestore on every status push. A cloud connection is now exempt from the address check outright: it runs on the account's broker, never on an address. The address is written only when it actually differs from the record — `renderer/inventory.js`, `renderer/printers/bambulab/index.js`.
30+
- **Resizing a camera opened — or closed — its machine's side panel.** The drag already guarded against this; the resize grip never did, so the click the release produces landed on the card. The guard goes up on the first MOVEMENT and is lowered on a timer scheduled BEFORE the write is awaited — lowered after it, a slow write would leave the guard up and swallow the next honest click — `renderer/inventory.js`.
31+
- The shared cloud MQTT client is re-pointed at the window that asks for it: it lives in the main process and outlives a renderer reload, so it went on posting telemetry to a page that no longer existed — `main.js`.
32+
- **`npm run i18n:add --json` was silently writing `"[object Object]"` into all nine locales.** Its JSON path coerced every value with `String(v)`, which turns a `{one, other}` plural into that literal text — no error, no warning, nine files corrupted at once. It now emits plurals as real multi-line objects, REFUSES anything that is neither a string nor a plural rather than coercing it, and replaces an existing plural as a whole block so a second run cannot orphan its remaining lines — `scripts/i18n-add.mjs`.
33+
- **`bulkHiddenWarn` shipped broken in v2.16.0 and stayed broken for nine releases**, caught by the fix above: selecting rows and then filtering showed the literal text `[object Object]` where the warning belongs — the warning that stands between you and a destructive action aimed at items you cannot see. Restored as a proper plural in 9 locales — `renderer/locales/*.json`.
34+
35+
### i18n
36+
37+
- Added: `printerCloudMode`, `bblCloudChoice`, `bblCloudChoiceHint`, `bblCloudTitle`, `bblCloudSub`, `bblCloudEmailPh`, `bblCloudSendCode`, `bblCloudCodePh`, `bblCloudSignIn`, `bblCloudChangeEmail`, `bblCloudCodeSent`, `bblCloudErrCode`, `bblCloudErrExpired`, `bblCloudErrBlocked`, `bblCloudErrGeneric`, `bblCloudNoPrinters`, `bblCloudPick`, `bblCloudAddSelected`, `bblCloudAddFailed` — 9 locales.
38+
- Repaired: `bulkHiddenWarn` — 9 locales.
39+
40+
---
41+
842
## v2.25.0 — 2026-08-30
943

1044
### Changed

‎CLAUDE.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ Each brand under `renderer/printers/<brand>/PROTOCOL.md` is a **self-contained a
384384

385385
| Brand | PROTOCOL.md highlights | index.js status |
386386
|-------|------------------------|-----------------|
387-
| **Bambu Lab** | MQTTS 8883 TLS, AMS 16-slot, SSDP+TLS scan, JPEG TCP 6000 / RTSP 322 | ✅ implemented |
387+
| **Bambu Lab** | LAN: MQTTS 8883 TLS, AMS 16-slot, SSDP+TLS scan, JPEG TCP 6000 / RTSP 322. Cloud (§17): REST behind Cloudflare — needs Electron's `net` — + one account MQTT broker; same `push_status`, so the LAN parser is reused | ✅ implemented (LAN + cloud) |
388388
| **Creality** | WS 9999, heartbeat `"ok"`, CFS boxsInfo type 0/1, WebRTC port 8000 | ✅ implemented |
389389
| **Elegoo** | MQTT 1883, UDP spray port 52700, filament 4 slots canvas/tray | ✅ implemented |
390390
| **FlashForge** | HTTP poll 8898, TCP M-codes 8899, UDP multicast 225.0.0.9:19000 | ✅ implemented |

‎CODEMAP-main.md‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,15 @@ L3810-3870 App lifecycle (whenReady, window-all-closed, activate)
112112
| 3276-3365 | JPEG-TCP camera, port 6000 (`bambulab:cam-start` / `cam-stop`) — 80-byte auth packet, retry/timeout | `_bambuCamAuthPacket` |
113113
| 3366-3483 | RTSP camera via ffmpeg, port 322 (`bambulab:cam-start-rtsp` / `cam-stop-rtsp`) — 30 fps + low-latency flags; the spawn is guarded (it throws synchronously on a bad CPU type) | — |
114114

115-
## Anycubic LAN — MQTT, provisioning, FLV camera (L3484-3815)
115+
## Bambu Lab cloud — REST + shared cloud MQTT (L3484-3801)
116+
117+
| L | What | Anchors / IPC |
118+
|---|---|---|
119+
| 3484-3576 | Tolerant REST helper over ELECTRON's `net` — Chromium's stack on purpose, because the login sits behind Cloudflare, which reads the TLS fingerprint | `_bblFetch`, `_bblHeaders` |
120+
| 3577-3700 | Auth: `cloud-send-code`, `cloud-login` (code / password, `verifyCode` + `tfa` branches), `cloud-tfa` (token arrives in a COOKIE), `cloud-uid` (token is NOT a JWT), `cloud-bind` (machines + their LAN access codes), `cloud-device-version` | — |
121+
| 3701-3801 | ONE cloud-MQTT client per ACCOUNT: `cloud-connect` (us→eu fallback), `cloud-subscribe` (+ `pushall`), `cloud-publish`, `cloud-unsubscribe`, `cloud-disconnect`. Telemetry is emitted on the LAN `bambulab:message` channel — same payload, same parser | `_bblCloudOpen`, `_bblCloudPushAll` |
122+
123+
## Anycubic LAN — MQTT, provisioning, FLV camera (L3802-4133)
116124

117125
| L | What | Anchors / IPC |
118126
|---|---|---|
@@ -121,7 +129,7 @@ L3810-3870 App lifecycle (whenReady, window-all-closed, activate)
121129
| 3213-3235 | Slicer on-disk credential reader (`anycubic:read-slicer-config`) — keyless deobfuscation | `_acuDeobfuscate`, `_acuConfCandidates` |
122130
| 3236-3343 | LAN scan: TCP probe (`anycubic:tcp-probe`), FLV liveness (`anycubic:flv-probe`, accepts 200/206), `/info` (`anycubic:http-info`) | — |
123131

124-
## Anycubic cloud — REST + cloud MQTT (L3738-4099)
132+
## Anycubic cloud — REST + cloud MQTT (L4134-4599)
125133

126134
| L | What | Anchors / IPC |
127135
|---|---|---|
@@ -131,8 +139,8 @@ L3810-3870 App lifecycle (whenReady, window-all-closed, activate)
131139
| 3668-3704 | Cloud-uploaded files (§9c): `cloud-files-list` (POST `/work/index/files`), `cloud-file-delete` (POST `/work/index/delFiles`); print reuses `cloud-send-order` order 1 | — |
132140
| 3705-3809 | Shared cloud-MQTT client (one per user): `cloud-connect` / `subscribe` / `publish` / `unsubscribe`; RSA-encrypted token login | `_buildCloudLogin`, `_routeCloudMessage`, `_ensureCloudClient` |
133141

134-
## App lifecycle (L3810-3870)
142+
## App lifecycle (L4600-4665)
135143

136144
| L | What |
137145
|---|---|
138-
| 3810-3870 | `app.whenReady` (img cache dir, server, window, NFC/TD1S/updater init), `window-all-closed`, `activate` |
146+
| 4600-4665 | `app.whenReady` (img cache dir, server, window, NFC/TD1S/updater init), `window-all-closed`, `activate` |

‎FEATURES.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Tiger Studio Manager — Feature Catalogue
22

3-
Tiger Studio Manager is the Electron desktop companion to the TigerTag ecosystem: a filament-inventory manager built around RFID/NFC-tagged spools ("TigerTag" chips), a fully-digital "TigerData" tier (and its catalogue-identified "TigerData+" rung), live 3D-printer integration across six brands, physical storage/rack management, a Firebase-backed social layer (friends, shareable wishlists, public profiles), and companion hardware (TD1S color sensor, TigerScale, TigerPOD dual-reader stand). This document catalogues every **shipped** feature, grouped by domain, current as of **v2.25.0**. Per-version release detail lives in `CHANGELOG.md`; forward-looking / in-progress work lives in `ROADMAP.md`.
3+
Tiger Studio Manager is the Electron desktop companion to the TigerTag ecosystem: a filament-inventory manager built around RFID/NFC-tagged spools ("TigerTag" chips), a fully-digital "TigerData" tier (and its catalogue-identified "TigerData+" rung), live 3D-printer integration across six brands, physical storage/rack management, a Firebase-backed social layer (friends, shareable wishlists, public profiles), and companion hardware (TD1S color sensor, TigerScale, TigerPOD dual-reader stand). This document catalogues every **shipped** feature, grouped by domain, current as of **v2.26.0**. Per-version release detail lives in `CHANGELOG.md`; forward-looking / in-progress work lives in `ROADMAP.md`.
44

55
---
66

@@ -175,7 +175,7 @@ Tiger Studio Manager is the Electron desktop companion to the TigerTag ecosystem
175175

176176
Live integrations across six brands, each with real-time temperatures, per-slot filament, active print job data, and (where hardware supports it) a camera feed and machine controls:
177177

178-
- **Bambu Lab** — MQTTS 8883 (TLS), LAN mode; job/temp/AMS cards, camera (JPEG-TCP + RTSP by model), full machine controls (jog/home/light/fans/speed/heated chamber where supported), print-plate thumbnails via FTPS+3mf extraction, H2-series dual-nozzle display (v1.6.0; full controls v1.10.7; thumbnails v2.1.0).
178+
- **Bambu Lab** — LAN (MQTTS 8883 TLS) **and cloud**: sign in with a Bambu account and every printer on it is offered with its picture, ticked one or several at a time, arriving with the LAN access code the cloud hands over; cloud machines report from anywhere and learn their own address from telemetry, so their camera starts unattended on the same network (cloud v2.26.0). Job/temp/AMS cards, camera (JPEG-TCP + RTSP by model), full machine controls (jog/home/light/fans/speed/heated chamber where supported), print-plate thumbnails via FTPS+3mf extraction, H2-series dual-nozzle display (v1.6.0; full controls v1.10.7; thumbnails v2.1.0).
179179
- **Creality** — WebSocket 9999 with heartbeat; job/temp cards, CFS colour-box grid, WebRTC camera, full machine controls (jog/home/temps/fans), per-slot CFS load/unload (v1.4.15; controls v1.10.13).
180180
- **Elegoo** — MQTT 1883 + UDP discovery 52700; job/temp/filament (mono + 4-slot Canvas) cards, XY-jog control card, fan cards, files/history sheet, filament edit sheet (v1.6.0).
181181
- **FlashForge** — HTTP polling 8898 + MJPEG camera; 5-slot matlStation grid, tool-changer support (Creator 5 Pro), official 24-swatch colour-palette constraint, lifetime-stats info panel (v1.4.11; monitoring & controls v1.10.10).

‎README.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,9 @@ The **TigerTag SDK** is the low-level library that handles all NFC chip operatio
128128
- **Find a colour by pointing at it** — a rainbow bar and a white-to-black bar with a window you drag along them; spools in range stay lit and the rest fade, so you see *where* that orange actually sits. Works in Inventory, Favorites, Search and Storage alike
129129

130130
### 🖨 3D Printer integration
131-
Live integrations for 6 brands — real-time temperatures, filament per slot, active print job, camera:
131+
Live integrations for 6 brands — real-time temperatures, filament per slot, active print job, camera. **Bambu Lab printers can be added by signing in with your Bambu account**: your email, the code they send back, and every machine on the account is offered with its picture — reachable from anywhere, not only from your own network.
132+
133+
Every brand at a glance:
132134

133135
| Brand | Protocol | Status |
134136
|---|---|---|

0 commit comments

Comments
 (0)