Skip to content

Releases: bjan/pycentauri

v0.9.0 — opt-in dashboard update check

Choose a tag to compare

@bjan bjan released this 16 Jul 05:22

Adds an optional "update available" indicator to the web dashboard.

Added

  • centauri server --check-updates (off by default). When enabled, the server does one cached PyPI lookup every 12 h and the dashboard shows a subtle ↑ vX.Y.Z badge next to the version when a newer release exists, linking to its notes.
  • Fail-silent, and the only outbound (non-printer) call in the whole tool — so the default still "talks only to your printer."
  • /api/info gains latest_version + update_available (inert unless opted in). PEP 440 comparison, so a local dev build ahead of PyPI never false-nags.

No new dependencies.

v0.8.0 — CC1 file management (list/delete/history) + safety guards

Choose a tag to compare

@bjan bjan released this 16 Jul 00:27

CC1 file browsing is local SDCP, not cloud — this release overturns the prior belief. The SDK's commented-out Cmds work with the right payload (258 list, 259 delete, 320+321 history), confirmed live on V0.3.0-o.

Added

  • CC1 file management — list_files, delete_files, print_history now work on the original Centauri Carbon, matching the CC2. History status normalised across both printers.
  • Web dashboard Files + Print-history panels (both models); light toggle + delete wired through with --enable-control.

Safety & robustness

  • Delete refuses the currently-printing file (both models) — verified live against a running print; reads confirmed safe mid-print.
  • Transient timeouts on /history·/disk·/files/delete map to 504 (not 501/502) so a blip doesn't permanently hide a panel.
  • /files/delete validates filenames is a list; uploads hash/read off the event loop so a large gcode can't stall the status stream.

Stock CC1 firmware (V1.1.46) was not re-tested for these Cmds; behaviour there is inferred from the shared app binary.

Full notes: see CHANGELOG.md.

v0.7.0 — file management, upload, light control, camera + speed-mode fixes

Choose a tag to compare

@bjan bjan released this 15 Jul 05:15

Fixed

  • CC2 speed mode no longer flips, and the pin no longer misfires on
    firmware 02.01.00.00.
    The newer firmware streams
    gcode_move.speed_mode in its real-time (method 6000) pushes as the
    current gcode move's speed factor, which oscillates 1↔2 as the head
    runs different features — it is no longer the stable "set" mode the
    older firmware exposed. This caused two problems: the UI flipped
    ~1×/sec, and the old wire-observation pin logic mistook a long
    balanced-speed feature stretch for a human choosing balanced and
    spuriously released the pin (and could re-learn/re-apply the wrong
    mode). The speed pin is now explicit only: set via
    set_print_speed, re-applied once when a Canvas filament switch
    completes (the point the firmware historically reset it — harmless if
    already correct), and cleared when the print ends. pycentauri never
    infers or sends a speed command from wire observation. The displayed
    mode reflects the pin (or a debounced wire value when unpinned), so it
    stays stable. Backward compatible: the switch-completion re-apply
    covers the older firmware's post-switch reset without depending on the
    wire value.
  • CC2 web UI now shows the current layer. The CC2's status payload
    has no total-layer field (only current_layer), so the UI — which
    required both — showed nothing. CC2Printer now looks up the printing
    file's layer count from its metadata (method 1044) once per file and
    caches it, so the UI shows "layer N / total". The layer also renders
    with just the current number when the total isn't yet known.
  • Webcam no longer stalls after a second / on refresh. The printer's
    MJPEG camera server has very few connection slots and releases them
    badly (closed connections linger in FIN-WAIT-2, still holding a
    slot). The old /stream opened a fresh upstream connection per request
    — every tab, and every client-side reload — which exhausted the slots
    and starved the stream (observed live 2026-07-08 on CC1: a sole fresh
    client got zero frames). /stream now shares a single upstream
    connection across all browsers via a CameraBroadcaster, so the
    printer only ever sees one camera connection regardless of tabs,
    refreshes, or reloads. Verified live: 4 concurrent clients → 1 printer
    connection, ~10 fps sustained, no connection pileup.
  • The camera broadcaster detects a stale upstream (TCP alive but no
    frames for 15 s) and reconnects automatically, instead of silently
    hanging forever (observed 2026-07-09 on CC1).

Added

  • File management (CC2, firmware 02.01.00.00+). Four new MQTT methods
    reverse-engineered from Orca's live wire traffic (2026-07-10):
    • list_files(storage, offset=, limit=) — method 1044, params
      {"storage_media": "local"|"u-disk", "offset", "limit"}. Returns
      file_list with filename, size, create_time, layers, print_time,
      color_map, total_filament_used. Surfaced as centauri files,
      GET /files, and MCP list_files.
    • delete_files(filenames, storage=) — method 1047, params
      {"storage_media", "file_path": [...]} (batch delete, array of
      names). Surfaced as centauri delete, POST /files/delete, and
      MCP delete_files. Requires enable_control.
    • disk_info() — method 1048. Returns total_bytes, used_bytes.
      Surfaced as centauri disk, GET /disk, and MCP disk_info.
    • print_history() — method 1036. Returns history_task_list.
      Surfaced as centauri history, GET /history, and MCP
      print_history.
      All four are CC2-only; CC1 raises PrinterError (SDCP Cmd 258 for
      file listing is disabled in the firmware). Full upload-list-delete
      cycle verified live on CC2.
  • Chamber light on/off (both models). set_light(on) — surfaced as
    centauri light on|off, POST /light, MCP set_light, and a Light
    toggle in the web UI. Requires enable_control. CC2 uses MQTT method
    1029 {"power": 0|1} (captured from Orca's wire traffic); CC1 uses
    SDCP Cmd 403 {"LightStatus": {"SecondLight": 0|1}} (verified live
    on V0.3.0-o). Both field names were commented out in Elegoo's SDK.
  • File upload across every surface. upload_file() pushes a local
    file to the printer's internal storage over chunked HTTP (port 80),
    independent of the control channel. CC1 uses multipart
    POST /uploadFile/upload; CC2 uses PUT /upload with Content-Range
    • X-Token. Surfaced as centauri upload (with --start),
      POST /files/upload (multipart), MCP upload_file, and a web UI
      upload control. Requires enable_control. Verified live on CC2.

v0.6.5 — surface CC2 'LAN Only' requirement

Choose a tag to compare

@bjan bjan released this 07 Jul 04:58

Fixed

  • CC2 connect now surfaces a clear error when the printer's HTTP API is
    unreachable instead of leaking a raw httpx.ConnectError. The CC2
    gates its local API behind "LAN Only" mode — with it off, the
    printer works through Elegoo's cloud and leaves port 80 closed, so the
    serial-number bootstrap fails even though MQTT :1883 answers. The
    error now says exactly that and names the setting to change. (Reported
    by a user on firmware 02.00.02.00 whose connection worked the moment
    they enabled LAN Only.)

Documentation

  • README and docs/PROTOCOL.md now document that "LAN Only" mode must
    be enabled on the CC2 for local control, and note that firmware
    02.00.02.00 is a lockdown release (removes SSH, blocks downgrades)
    with a community repacked v01.03.02.51 available if needed.

v0.6.4 — fix /openapi.json 500

Choose a tag to compare

@bjan bjan released this 06 Jul 00:49

Fixed

  • GET /openapi.json (and therefore the /docs Swagger UI) returned a
    500 instead of the API schema. The Canvas RefillBody request model
    was defined inside create_app(), so under
    from __future__ import annotations its forward references couldn't be
    resolved at schema-generation time (request validation still worked,
    which is why nothing else surfaced it). Moved it to module scope with
    the other request-body models; added a test that renders the schema.

v0.6.3 — auto-detect human balanced vs firmware reset

Choose a tag to compare

@bjan bjan released this 05 Jul 23:35

Changed

  • CC2 speed pinning now tells a human's balanced apart from a firmware
    reset — no more Auto escape hatch.
    The firmware resets speed_mode to
    balanced as the leading edge of every Canvas filament switch, a few
    seconds before the head parks; measured reset→park lead times are
    tight (6–8 s, never above ~9 s). pycentauri uses that: a drop to
    balanced followed by a park within ~12 s is the firmware and the
    pinned mode is re-applied when the switch completes; a drop that sits
    at balanced for ~12 s with no park is a human tapping balanced on the
    touchscreen, so the pin is released and balanced is honored. A
    sustained non-balanced touchscreen mode is still adopted as the pin
    outright. Both paths live-verified 2026-07-05 (firmware re-apply and
    human release, each with journal-logged decisions).
  • Removed the auto speed mode / Auto button. It existed only to
    release the pin for the touchscreen-balanced case, which is now
    detected automatically. speed auto, {"mode": "auto"}, and the web
    UI Auto button are gone.

v0.6.2 — pin-and-enforce speed mode, with Auto release

Choose a tag to compare

@bjan bjan released this 05 Jul 22:25

Changed

  • CC2 speed-mode persistence redesigned as pin-and-enforce. The
    0.6.1 snapshot-per-switch restore lost an arms race with the
    firmware: after eight consecutive successful restores, a reset
    arriving outside the covered window (late after a restore, or
    mid-print with no switch at all — observed 2026-07-05 ~15:00)
    poisoned the baseline and silently disabled every restore after it.
    The firmware only ever resets TO balanced, so the model is now: the
    mode you set is pinned (immediately via pycentauri; after holding
    15 s when set from the touchscreen, since a non-balanced mode can
    only come from a human), and any disagreement lasting 12 s while
    printing is re-applied, at most every 30 s. One consequence,
    deliberate: while a mode is pinned, selecting balanced from the
    touchscreen is indistinguishable from a firmware reset and will be
    reverted — switch to balanced through pycentauri instead, which
    re-pins. Pins clear when the print ends, and speed auto (CLI),
    {"mode": "auto"} (HTTP), or the web UI's Auto button release the
    pin explicitly, returning speed control to the printer.
  • Root cause fully mapped (wire captures, 2026-07-05): every reset is
    a service operation — full filament switches, plus brief nozzle
    wipe / purge operations at the chute that are too short to register
    as "switching" — and a human's touchscreen tap is byte-identical to
    a firmware reset on the wire, so balanced-from-touchscreen cannot be
    auto-detected while a pin is active. Use Auto or set balanced via
    pycentauri instead.

v0.6.1 — speed mode survives Canvas filament switches

Choose a tag to compare

@bjan bjan released this 05 Jul 21:37

Fixed

  • CC2: the user's speed mode now survives Canvas filament switches.
    The firmware resets speed_mode to balanced on every mid-print
    switch and leaves it there (verified 2026-07-05: mode stayed reset
    after the switch completed). CC2Printer now snapshots the mode in
    effect when a switch begins and re-applies it once printing resumes —
    regardless of whether the mode was set via pycentauri or the
    touchscreen. Requires enable_control; read-only sessions log the
    reset instead. The restore baseline is debounced (a mode must hold
    15 s to count) because the firmware fires its reset several seconds
    before the head parks — without the debounce, that transient
    poisoned the snapshot. Verified across two hands-free switch cycles
    with journal-logged restores ~3 s after each resume.
  • centauri server now surfaces pycentauri's own log lines (speed-mode
    restores, reconnects) in its output — previously only uvicorn's
    loggers were configured and library INFO logs were invisible.

v0.6.0 — Centauri Carbon 2 + Canvas multi-filament

Choose a tag to compare

@bjan bjan released this 05 Jul 19:10

Added

  • Centauri Carbon 2 support. The CC2 uses MQTT on port 1883
    (instead of the CC1's WebSocket SDCP on 3030) with a JSON-RPC
    envelope, X-Token auth, and a completely different command set
    (1001/1002/1020–1031 vs 0/1/128–512). This release adds:
    • CC2Printer — async MQTT client that subclasses Printer,
      translating CC2 payloads into the same Status / Attributes
      models so every surface (CLI, HTTP, MCP, web UI) works unchanged.
    • connect_auto(host, access_code=...) — factory that detects the
      model (probes :1883 only — a CC1 answers with a harmless kernel
      RST, and the CC1's real WebSocket connect doubles as its own probe)
      and returns the right Printer subclass. Callers never need to
      know which model they're talking to.
    • --access-code / PYCENTAURI_ACCESS_CODE on every CLI command
      and MCP launch (required for CC2, ignored for CC1).
    • paho-mqtt>=2.0 added to core dependencies.
  • CC2 status exposes gcode_move.speed — live head speed as the
    commanded speed of the current move, in mm/min (÷60 matches the
    printer screen's mm/s readout)
    and speed_mode (integer 0–3) — fields the CC1 lacks entirely. Both
    are preserved in Status.raw["_cc2"] alongside remaining_time_sec,
    filament_detected, external_device, and exception_status.
  • CC2 methods 1028 (SET_TEMPERATURE), 1029 (SET_LIGHT), 1030
    (SET_FAN_SPEED), 1031 (SET_PRINT_SPEED), 1023 (RESUME), and 1036
    (PRINT_TASK_LIST) all confirmed working. 1042 (VIDEO_STREAM) and
    1044 (GET_FILE_LIST) are non-responsive on firmware 01.03.02.51.
  • Canvas multi-filament system integration (CC2 only):
    • Printer.canvas_status() — returns CanvasStatus with connected
      units, tray list (filament name/type/color/brand/temp range/loaded
      status), active tray, and auto-refill state. Method 2005.
    • Printer.set_auto_refill(enabled) — toggles auto-refill. Method
      2004. Gated by enable_control.
    • CLI: centauri canvas (read) + centauri refill --on/--off
      (write, requires --enable-control).
    • HTTP: GET /canvas (always) + POST /canvas/refill (control-gated).
    • MCP: get_canvas_status (always) + set_auto_refill (control-gated).
    • CanvasStatus, CanvasUnit, CanvasTray model classes exported
      from the package for typed access.

Fixed (pre-release hardening — none of these shipped in an earlier release)

  • CC1 status()/watch() self-heal through a wedged push
    scheduler.
    Discovered live 2026-07-04 on V0.3.0-o: the firmware can
    enter a state where Cmd 512 subscribes are accepted but no status
    frames are ever pushed, while the request path stays healthy — and a
    reboot does not clear it (verified 2026-07-05). Both methods now fall
    back to explicit Cmd 0 status requests (documented to emit a
    one-shot status frame) whenever a subscribe produces no push within
    one period, instead of hanging forever. See docs/PROTOCOL.md
    "Operational quirks".
  • CC2Printer.watch() now polls method 1002 inline whenever pushes go
    quiet instead of silently terminating after one push period — CC2
    centauri watch and the SSE stream no longer die on an idle printer.
  • MQTT responses are correlated by the client's exact api_response
    topic and non-push method. Previously any client's response — or the
    printer's own 6000/6008 broadcasts, which reuse small auto-increment
    ids — could resolve a pending request future with the wrong payload
    (including reporting success for a control command).
  • Registration is re-published from _on_connect, so paho's automatic
    MQTT reconnect re-registers with the printer and pushes survive a
    printer reboot without restarting centauri server.
  • All MQTT-callback work that touches futures, events, queues, or the
    merged status dict is marshalled onto the asyncio loop (fixes the
    cross-thread delta merge and late set_result races).
  • GET /stream uses a bounded connect timeout (read stays unbounded
    for MJPEG) instead of hanging forever against a wedged camera port.
  • GET /canvas returns 504 for printer timeouts, reserving 501 for
    "no Canvas on this printer"; the web UI now retries transient Canvas
    failures instead of hiding the panel until a page reload.
  • A wrong CC2 access code now raises a clear auth error (MQTT reason
    code / HTTP 401 hint) instead of a generic timeout or raw traceback.
  • connect_auto() and centauri rtsp no longer probe :3030 — the CC1
    WebSocket connect doubles as the probe, avoiding the connect/close
    churn that port is sensitive to. centauri rtsp and the HTTP server
    both pick the right MJPEG port (CC1 :3031 / CC2 :8080) automatically,
    including reconnects after starting with the printer offline.
  • Unknown CC2 machine_status values map to sentinel code 99 instead
    of leaking raw values into the CC1 status-code space; PrintStatus
    gains constants for the CC2 codes 27/28/29.
  • CanvasStatus.from_payload survives malformed/absent canvas_info
    payloads; CanvasUnit/CanvasTray are exported from the package
    root; typing_extensions declared as a direct dependency.
  • CC2 sessions send the app-level {"type": "PING"} keepalive every
    30 s.
    The firmware expires a client's registration after several
    quiet minutes and then silently stops answering that session's
    requests — the MQTT connection stays up, responses just never come
    (verified 2026-07-05: a dashboard went request-deaf after ~6 minutes
    while a fresh session answered instantly). MQTT-level keepalive does
    not prevent this; only the app-level PING does.
  • centauri server bounds uvicorn's graceful shutdown at 5 s. Open
    SSE/MJPEG streams never close on their own, and without the bound a
    stopped server lingered forever as a zombie still holding a printer
    connection (observed 2026-06-23 and 2026-07-05).
  • CC2 lifecycle commands (start/pause/stop/resume) use a 90 s timeout —
    the firmware answers only after the mechanical sequence completes
    (observed 2026-07-05: a resume succeeded but its confirmation
    arrived after the old 15 s window, surfacing a false error). When a
    confirmation still doesn't arrive, POST /print/* returns 504
    ("sent, unconfirmed — check printer status") instead of 502, and the
    web UI shows it as a warning rather than a failure.

Tests

  • New tests/test_cc2_mapping.py: pure dict-in/dict-out coverage of
    the CC2→CC1 translation layer — machine_status/sub_status mapping
    (including purge-zone filament-switch detection and its progress
    guard), partial-delta deep merge, full 1002 payload round-trip, and
    Canvas parsing. Plus a server test pinning GET /canvas → 501 on
    CC1.

Documentation

  • docs/PROTOCOL.md gains a full CC2 section: MQTT transport, topic
    structure, connection/registration dance, the confirmed method table
    (12 probed, 10 working), error codes, the complete status payload,
    and a CC1-vs-CC2 comparison table. Probed on 2026-06-30 through
    2026-07-04 against firmware 01.03.02.51 (Canvas methods 2004/2005
    verified live with a 4-slot Canvas attached; CC2 webcam confirmed
    unauthenticated MJPEG on :8080).
  • docs/ARCHITECTURE.md rewritten for the two-transport reality:
    module map with cc2/connect, per-model ports, CC1-vs-CC2
    /status and SSE flow differences, and an honest test-architecture
    section (no automated live suite exists; live verification is manual
    CLI runs).

v0.5.1 — CLI + MCP parity for live print-parameter adjust

Choose a tag to compare

@bjan bjan released this 05 Jul 19:13

Added

  • CLI parity with the new live-adjust API. Three new top-level
    commands matching the library and HTTP surfaces shipped in 0.5.0:
    • centauri speed <silent|balanced|sport|ludicrous|50|100|130|160>
    • centauri fan [--model N] [--aux N] [--chamber N]
    • centauri temp [--nozzle N] [--bed N] [--chamber N]
      All require --enable-control and accept any subset of fan/heater
      flags (omitted axes are left untouched).
  • MCP tool parity: three new tools (only registered with
    --enable-control) — set_print_speed, set_fan_speed,
    set_temperatures. Same shapes as the HTTP endpoints; not marked
    "DESTRUCTIVE" because live runtime adjustment is their entire
    purpose.

Fixed

  • 0.5.0 shipped the live-adjust API to the library, HTTP server, and
    web UI but missed the CLI and MCP server. This release closes that
    parity gap — every surface now exposes the same control set.