# Changelog ## [Unreleased] ### Fixed - **Slot kept showing/printing a stale filament type after a spool swap.** The per-slot profile override (config.ini `[filament_profiles]`) stores only vendor+name and was sticky: swapping the physical filament updated the AMS colour and type live, but the saved profile persisted, so a slot that held e.g. "KINGROON PETG Basic" kept showing/sending PETG in the panel and the OrcaSlicer lane hint even after yellow PLA was loaded — and survived restarts. The override is now applied only while its material *family* still matches the loaded AMS material (PLA / PLA+ / PLA SILK / PLA MATTE are one family, so within-family swaps never invalidate a valid profile). On a family change the slot falls back to the generic default; the override is not deleted, so reloading the original material reactivates it. - **Filament profiles not isolated between printers in a multi-printer bridge** (issue #74). The slot→profile mapping and `visible_vendors` were stored in a single global `[filament_profiles]` section, so configuring one printer overwrote the other and after a restart both loaded the same mapping. Each printer now persists to its own `[filament_profiles_]` section, with a read-fallback to the legacy global section (single-printer setups unchanged). - **Printer dropdown showed the other printer's filament profiles** (issue #74). The header dropdown and the printers-management "switch" link navigated within the same port (`/printerN`), so viewing another printer pulled its profile names cross-instance from the local origin. The links now point at each printer's own `bridge_url`, so every printer is viewed same-origin on its own port. ## [0.9.26] – 2026-06-21 ### New - **Italian language support** (PR #66, @Alex_M). The bridge UI is now fully available in Italian. ### Fixed - **Camera always started at print begin** (issue #50). `camera_on_print` was missing from the `/api/state` response — JavaScript read `undefined` and started the camera regardless of the setting. Now correctly exposed in state. - **Auto-leveling setting ignored in Moonraker print path** (issue #57). `handle_print_start` read the value only from bridge args, not from the request body, so the dialog checkbox and the per-print override had no effect. Now behaves identically to the direct print path. - **Filament mapping free-text fields replaced by dropdowns** (issue #57). A mistyped vendor/name broke profile matching silently; fields are now dropdowns (vendor → profile, vendor-filtered) so only valid combinations can be saved. - **Dashboard showed generic material type instead of profile name** (issue #57). AMS slot cards now display the mapped profile name (e.g. "eSUN PLA-Basic") instead of just "PLA". Falls back to the generic type when no profile is mapped. - **Ghost profile shown on empty slot** (issue #57). Stale mappings for empty slots were still rendered; empty slots now correctly show "–". - **Skip-Objects panel missing in Orca upload flow** (issue #57). Panel now appears in all print flows; on fresh upload the bridge requests `fileDetails` from the printer and retries the object list for up to 6 s. - **Banner and dialog appeared simultaneously** (issue #57). Settings save now resets the dialog cancel state so the slot mapper reliably opens after toggling Start Print Behavior. - **"Clear" reloaded idle file on next poll** (issue #57). Clear now immediately resets local state (`file_ready`, `filename`, `thumbnail`) and clears all dialog locks — the preview and action buttons disappear instantly and do not return. - **Material matching for "PLA Silk", "Matte PLA" etc.** (PR #64, @p2l). Modifier+base patterns in any word order are now normalised to the base type; dash-suffix variants (PLA-CF) remain correctly incompatible with their base. ## [0.9.25] – 2026-06-17 ### Fixed - **Random crashes / container restarts — segfault in `libcrypto.so.3` (issue #53).** The MQTT-over-TLS client shared a single SSL socket between the reader thread (`recv`) and the sender threads (`sendall`) without serializing them. CPython's `ssl` module does not allow concurrent read and write on the same socket — the overlap corrupted OpenSSL's internal state, causing a heap corruption and a segfault that manifested reliably on some hosts (timing-dependent). All socket access (recv / sendall / close / reconnect) is now serialized under a single lock; the reader probes readiness with `select()` outside the lock so senders are never starved. Reconnect and disconnect now swap the socket atomically. Thanks to @BasK for the detailed fault-handler trace that pinpointed this. - **File browser accepted non-GCode uploads (issue #59).** Drag & drop bypassed the file picker's `accept` filter, so e.g. a JPG could be uploaded. Uploads are now validated both client- and server-side; only `.gcode`, `.gcode.3mf`, `.3mf` and `.bgcode` are accepted. Thanks @gangoke. ## [0.9.24] – 2026-06-16 ### New - **Skip Objects available in every print flow (issue #57).** The "Skip objects" panel in the Slot Mapper used to appear only when printing from the Browser tab. It now shows in all flows (upload / print bar included), collapsed by default behind a `✂ Skip objects (N)` header to keep the dialog compact, expanding on click with the object preview and checklist. - **Slot Mapper shows the specific profile name (issue #57).** Each slot now displays its mapped filament profile (e.g. "PolyTerra PLA — Polymaker") in the dropdown options and as a hover tooltip on the slot marker, instead of just the generic type. Falls back to the generic type when no profile is mapped. ## [0.9.23] – 2026-06-16 ### New - **Auto-open print dialog after upload.** A new `print_start_dialog` setting (Settings → Printer → "Start Print Behavior") controls what happens after a file is uploaded while the printer is idle: `Print Dialog` opens the slot-assignment dialog automatically, `Print Bar` keeps the previous banner behaviour. Based on PR #56 by @gangoke. - **Per-print auto-leveling toggle.** The print dialog now has its own auto-leveling checkbox that overrides the global default for a single print. ### Fixed - **Object skip was silently ignored at print start (PR #56, @gangoke).** The skip command was sent *before* the printer entered the `printing` state, so it was dropped. The skip is now re-applied in a retry loop once the print is confirmed running, with a pending-lock so the UI doesn't reset the skip state prematurely. - **Upload during an active print overwrote the running job's preview.** Uploading a new file while printing no longer replaces the thumbnail / file_ready of the job currently on the bed. ## [0.9.22] – 2026-06-16 ### New - **Restructured Settings panel.** The settings modal has been replaced by a persistent Master-Detail panel with five categories: Connection, Printer, Appearance, Filament, and System. Poll interval is now adjustable live. - **Vendor visibility filter (issue #41).** A new checklist in the Filament settings lets you restrict the slot profile dropdown to specific manufacturers. "Generic" and your own imported profiles are always visible. The list updates automatically after a profile import. - **Idle file actions in the progress card (issue #55).** After uploading a file while the printer is idle, three quick-action buttons appear directly in the progress card: ▶ Print, ⚙ Map Slots, and ✕ Clear — matching the file browser workflow without navigating away. ### Fixed - **Mobileraker: app crashed with `Null is not a subtype of Object` in `ConfigExtruder.fromJson` (issue #48).** `configfile.config` was returned as an empty object `{}`. Mobileraker parses both `configfile.settings` and `configfile.config` through the same strict Dart parser — both are now populated with the same extruder/bed/stepper stub. - **Mobileraker: app hung indefinitely on refresh (issue #48).** The WebSocket `server.files.metadata` handler called a non-existent store method (`get_file_by_filename`), always returning empty metadata. Mobileraker retried this thousands of times per second. Both the HTTP and WS paths now share a single `_build_file_metadata()` method. - **Mobileraker: ETA / remaining time not shown (issue #48).** A side effect of the metadata loop fix — once `currentFile` resolves, Mobileraker can calculate ETA from `estimated_time`. - **Mobileraker: `notify_status_update` triggered repeated `ConfigFile.parse` (issue #48).** Static objects (`configfile`, `webhooks`, `heaters`, `history`) were included in every live status push. They are now filtered out; only live telemetry is broadcast. - `motion_report` (`live_position`, `live_velocity`) added to printer objects for Mobileraker motion display. - Saving filament slot profiles no longer silently drops the `visible_vendors` setting from `config.ini`. ## [0.9.21] – 2026-06-14 ### Fixed - **Camera stream not visible on Android (Chrome / Firefox).** Android browsers do not support `multipart/x-mixed-replace` (MJPEG). The UI now detects Android and falls back to snapshot-polling at 5 fps (`/api/camera/snapshot` every 200 ms) — no server-side change needed. ### Changed - Docker image now pinned to **Debian 12 (Bookworm)** (`python:3.11-slim-bookworm`) to avoid glibc 2.41 compatibility issues introduced by the Debian 13 base image that `python:3.11-slim` recently started pulling. - MQTT and HTTP connections now **force IPv4** (`AF_INET`) to prevent connection failures on hosts where the printer is only reachable via IPv4 but the OS prefers IPv6. - Extruder stub in the Moonraker `configfile` response now includes `sensor_type` and `filament_diameter` — fixes a Mobileraker crash (`Null is not a subtype of Object`, issue #48). ## [0.9.20] – 2026-06-08 ### New - **French language support (PR #45 by @Nathacks)** - **Z height display in the print UI (PR #49 by @Nathacks).** Shows current Z position in mm below the layer counter. ### Fixed - **Camera auto-start ignored "Enable camera on print start" setting after a bridge restart (issue #50).** The setting was cached in the process environment — after saving it in the UI, the old value survived the restart and the new value from `config.ini` was never read. - **Camera restarted automatically after manual stop during a print (issue #50).** A new `_camera_user_stopped` flag suppresses auto-restart for the current print session. It resets when the print ends. - **Spurious "stream unavailable" error toast when stopping the camera manually.** The image error handler was still registered when `img.src` was cleared. - **JS error (`ReferenceError: br is not defined`) when toggling the light.** Variable was referenced from the wrong scope. - Webcam URLs are now absolute so that Mobileraker/Obico clients can reach them. ## [0.9.19.1] – 2026-06-04 ### Fixed - Standalone binaries (Linux/Windows) reported `vunknown` as their version. The `VERSION` file is now embedded into the PyInstaller onefile bundle. - When the TLS certificates (`anycubic_slicer.crt`/`.key`) were missing, the bridge only logged the raw `[Errno 2] No such file or directory`. It now states clearly where the files need to be placed and that `anycubic-certs.zip` from the Gitea release is the source. ### Changed - Filament profile list re-curated: 209 entries instead of 399. Profiles that only exist inside printer-specific vendor bundles (e.g. Eryone Thinker X400, Artillery M1 Pro, WonderMaker ZR, Tiertime, Cubicon, CoLiDo, Afinia, Snapmaker) were dropped — OrcaSlicer wouldn't have found them in a default Kobra X setup anyway, because the matching vendor bundle is only loaded when the corresponding printer vendor is active. For those filaments the custom profile import (issue #41) remains the way. ## [0.9.19] – 2026-06-02 ### New - **🎯 Filament sync with OrcaSlicer now picks the right preset** instead of always falling back to "Generic PLA". Requires an OrcaSlicer build with the [PR #13719](https://github.com/SoftFever/OrcaSlicer/pull/13719) receive-side patch (included in the OrcaSlicer-KX build). The bridge sends `name` + `vendor_name` per AMS slot on the lane path AND `gate_filament_name` per gate on the Happy-Hare MMU path (OrcaSlicer switches to the HH path automatically for AMS setups). - **Import your own OrcaSlicer profiles into the bridge (issue #41).** Settings → "OrcaSlicer Profiles" or directly in the slot-edit dialog ("★ Import own profiles…") lets you upload `.json` files from `~/.config/OrcaSlicer/user//filament/` — single files or as a ZIP. They show up in the slot dropdown under "★ Own profiles" and are passed through to Orca on sync as user matches. Works over HTTP so the bridge can run in Docker on a Raspi/NAS while OrcaSlicer lives on a desktop. Override-only profiles with just `inherits: "Generic PLA @System"` + a few tweaks are detected correctly — the bridge resolves the inherited fields from the system parent. ### Fixes - **AMS sync stuck on "Generic PLA":** the Orca data model has 68 duplicate `filament_id` values (`OGFL99` alone shared by 136 profiles), and the bridge often picked an ID that was not `is_compatible` with the Kobra X (e.g. `GFL92` from the Kobra-2 profile → Orca rejected it). The generator now prioritises Kobra-X variants and filters out phantom profiles (cross-vendor overrides) — `orca_filaments.json` dropped from 1035 to 400 clean profiles. - **Slot without an explicit override now sends `Generic `** instead of an implicit vendor guess. Library generic profiles have `compatible_printers: []` (= all printers), so they are always visible and match reliably. - **Slot card shows the vendor right after save** without a browser reload. `poll()` was async, the re-render only happened on the next tick. - **ACE dryer toggle threw a 502 even though the dryer worked (PR #42 by @gangoke):** `setDry` is now fire-and-forget like `setAutoFeed`. The printer answers on that push topic with `code: 0` instead of `code: 200`, which the bridge wrongly treated as an error. ### Data model / API - `orca_filaments.json` regenerated: only real vendor profiles and OrcaFilamentLibrary profiles. Bambu/Polymaker/SUNLU library profiles in, Qidi cross-bundles out. - New endpoints: `POST /kx/filament/profiles/user` (ZIP/JSON upload), `GET /kx/filament/profiles/user` (list user imports), `DELETE /kx/filament/profiles/user[?vendor=…&name=…]`. Persisted in `/orca_filaments.user.json` (volume — survives image updates). ### Build - New module `bridge/orca_filaments.py` (shared parser helpers used by the generator and the import endpoint). - Dockerfile + release.sh updated to include `orca_filaments.py`. ## [0.9.18] – 2026-05-31 ### New - **🎉 Push filament material and colour from the bridge to the printer:** The values you pick in the slot-edit dialog now actually reach the printer and stick — the printer display shows the same slot setup as the bridge UI right away. In 0.9.17 the command was sent over the wrong MQTT topic (`slicer/printer/…`) and the printer silently dropped it. It now goes via `web/printer/…` like the Anycubic Slicer Next does (verified by live MQTT sniff + Workbench-Vue source). **Note:** the printer must be idle, and empty slots can not be labelled. - **Spanish translation reviewed by a native speaker (PR #40 by @pezfisk):** missing accents (impresión, cámara, después, animación, …) and term consistency (Pause → Pausa, Start → Iniciar, Layer → Capa). New `README.es.md` and cross-links between the three READMEs. - **Z-height now shows up in Obico.** The printer does not report a real Z position over MQTT (live-sniff confirmed), so the bridge estimates it from `current_layer × layer_height + first_layer_height`. Layer heights are parsed from the gcode header at upload time and persisted in the gcode store; fallback for prints started directly from the slicer is the OrcaSlicer default filename pattern (`…_0.2_…gcode`). `/server/files/metadata` also serves `object_height` (total Z) so Obicos `mmProgress` widget can render `current Z / total Z`. - **Slot card shows the OrcaSlicer profile vendor** under the material (e.g. `PLA / Polymaker`), with the profile name + internal ID as tooltip. Lets you see at a glance which slot override is active. ### Fixes - **Slot profile picker in the AMS dialog (issue #39 by @harrygeier):** three separate bugs in 0.9.17 caused the chosen brand to disappear after save and a different material to show up on re-open. - `multiColorBox/setInfo` was sent on the wrong MQTT topic — see above. - Save fired two parallel requests (profile override + material/ colour) → race. Now sequential, and the local state is reloaded before the dialog closes. - OrcaSlicer filament IDs are not unique — `orca_filaments.json` has 68 duplicate IDs, `OGFL99` alone is shared by 136 vendor profiles (caught by @gangoke). The primary selector is now `(vendor, name)` — unique across all 1002 profiles. - **MQTT reconnect (issue #33 by @icebear):** if the printer was powered off overnight the bridge gave up after 5 reconnect attempts (~60 s total) — filament sync still worked in the morning (its HTTP), but starting a print failed with `connection refused` and the user had to restart the bridge itself. The reader thread now reconnects **forever** (backoff caps at 60 s) until the printer responds again, with logs dropping to DEBUG after the first 5 attempts so an overnight outage does not spam the log. - **`Unknown child pid` warnings in the log:** the camera ffmpeg helpers were killed without awaiting their `wait()` — children lingered as zombies and asyncio reported them every ~20 s. Fixed in CameraCache + `/api/camera/stream`. ### UI polish - **Pause button is now a toggle:** while printing → `⏸ Pause`, while paused → `▶ Resume`. The separate resume button is gone. - **Pause + stop hidden when the printer is idle** — both used to be visible at all times, which was confusing on a standby printer. ### Build - **gcode store migration:** new columns `layer_height` + `first_layer_height` on `gcode_files` (added automatically on first start of 0.9.18). ## [0.9.17] – 2026-05-30 ### New - **🧪 Obico integration (experimental):** The bridge now exposes a Moonraker-compatible surface that the [moonraker-obico](https://github.com/TheSpaghettiDetective/moonraker-obico) plugin accepts. Time-lapses, layer-aligned first-layer scan and WebRTC live streaming work against a (self-hosted or cloud) Obico server. **Note:** the spaghetti-detection ML model is trained on side-view cameras (Ender/Voron); how well it works with the Kobra X's top-down camera is still to be evaluated empirically (it already looked promising in our tests). Stream, time-lapse and telemetry work — the failure-detection side stays flagged as experimental for now. - **Multi-language UI (PR #37 by @gangoke):** Inline translations have moved into JSON files; a globe-icon dropdown lets you switch language. Browser locale is auto-detected; manual choice persists in LocalStorage. Languages: 🇩🇪 🇬🇧 🇪🇸 🇨🇳 (ES + ZH-CN are AI-translated and not verified by native speakers yet). - **OrcaSlicer filament profile per AMS slot:** The slot-edit dialog now lets you pick a concrete OrcaSlicer profile (e.g. "PolyTerra PLA — Polymaker") per slot; the bridge sends it along on AMS sync instead of just "Generic PLA". Profile list is generated from the OrcaSlicer source (~1000 profiles, 43 vendors). A matching patch in OrcaSlicer-KX is on the way so OrcaSlicer fully honours the hint. - **H.264 direct stream:** New `/api/camera/h264` endpoint serves the printer camera stream as MPEG-TS without re-encoding — dramatically reduces latency, bridge CPU during Obico streaming drops from ~13 % to ~3 %. ### Fixes - **Setting temperature via bridge UI / Obico caused a printer system error:** Fixed via live MQTT capture from Anycubic Slicer Next — the `tempature/set` command needs a `type` field (0=nozzle, 1=bed, 2=both) and must go over the `web/printer/…` topic, not `slicer/printer/…`. Nozzle/bed heating from the bridge now works. - **Large GCode uploads (>50 MB) timed out:** The socket connect timeout was active during `sendall()` too — pushing ~200 MB over LAN took more than 30 s and was falsely aborted. Connect / send / read phases are now timed out separately. - **Camera snapshots were slow and could collide with the live stream:** The bridge now keeps a central camera cache (one ffmpeg pulls from the printer, all consumers share it). Snapshots return in ~1.3 ms from RAM instead of 1–2 s per spawned ffmpeg. Also resolves the single-client limit on the printer (HTTP 429 on parallel access). - **Language switch did not refresh the GCode browser:** Strings baked into the file cards ("Print", "Estimate", "Download") stayed in the previous language. Cards are now re-rendered on language switch. - **GCode web upload + download + verify dialog (PR #32 by @gangoke):** Files can be uploaded / downloaded directly in the browser, with a warning dialog when starting a GCode that was not uploaded via OrcaSlicer. ### CI/Build - Multi-arch Docker image (amd64 + arm64) automated via Gitea Actions. - Release builds for all three targets (linux-amd64, linux-arm64, windows.exe) via the local CodeBuilder. ## [0.9.16] – 2026-05-22 ### New - **Auto-start camera on print:** new setting "Turn camera on at print start" — when enabled, the bridge starts the camera stream automatically when a print begins (works for both OrcaSlicer and the Bridge UI). ### Fixes - **Single-color print blocked by an empty AMS slot:** OrcaSlicer writes all configured filaments into the GCode header even when the model uses only one, so the bridge told the printer it needed every color — and an empty unused slot aborted the print. The bridge now maps only the filaments actually used by the GCode. - **Filament sync now position-accurate:** with an empty slot in the middle (e.g. slot 1 yellow, 2 empty, 3 red, 4 white) OrcaSlicer showed the colors shifted onto the wrong slots. Fixed — empty slots keep their position, and the sync color format follows the Happy Hare convention (RRGGBB without `#`). - **Slicer time + thumbnail missing after a browser reload** (or when a print was started directly from OrcaSlicer): both are now restored from the GCode store by filename instead of relying on volatile state. - **German translation gaps** in the ACE dryer dialog fixed. ### Logging - Repeated log lines are collapsed into a counter ("×N") instead of spamming the console; status-poll traffic is no longer logged at INFO. - New log level filter (All / Errors / Warnings), a toast on new errors, full tracebacks forwarded to the browser log, and a timestamped download filename. ## [0.9.15] – 2026-05-21 ### Fixes (Issue #29) - **UI in the OrcaSlicer device tab was broken:** OrcaSlicer's embedded webview only loads the bare HTML and ignores external `