github 3dg1luk43/ha_creality_ws v0.9.8

3 hours ago

[0.9.8] - 2026-09-26

List of issues (0.9.8)

Requires Home Assistant 2026.7.0. The live print card needs the companion
app's Live Activity support, added in that release. HACS will not offer this
version to older cores, and a manual install fails setup with an explicit
message. Stay on 0.9.7 if you cannot update.

Added

  • Live print notifications for Android and iOS. One self-updating card per printer: countdown to finish, progress bar, current layer, G-code preview as the icon. It ends itself when the print does, replaced by a completion notification carrying a camera snapshot.
    • The countdown runs on the phone, so it costs no pushes. State changes push immediately; the rest is rate limited (5 minute refresh, 1% of progress, 30 second floor) because iOS drops Live Activities that update too often.
    • Multiple notify targets. Companion-app targets get the full card; every other platform gets title and message only.
    • Optional Pause / Resume / Stop buttons, off by default. Stop requires device authentication.
    • Tapping opens the camera feed on Android. Set a dashboard path to change that, which is also the only way an iOS tap can deep-link.
  • Write your own notification text. Configure → Notifications → Custom text overrides any of the six notifications; clear a field for the built-in wording.
    • Placeholders: {device}, {filename}, {progress}, {layer}, {total_layers}, {eta}, {elapsed}, {filament}, {nozzle}, {bed}, {state}, {error_code}, {error_key}, {minutes}. Each field lists the ones it accepts and rejects the rest when you submit. Values come from the frame that triggered the notification; nothing is estimated.
    • [...] marks an optional section that disappears whole while a value inside it is unknown, so {filename}[ -- {eta} left] loses the tail rather than leaving a dangling separator. Double them ([[, ]]) for a literal bracket. 0 counts as a value.
    • The title is always the printer's name: Android fixes a live card's title when it starts.
  • Bus events ha_creality_ws_print_started, _print_finished, _print_error and _print_stopped, fired whether or not a notify target is configured. They carry entry_id, host, device_name, filename, progress, layer, total_layers, left_seconds and err_code. This is the supported way to write your own text in a language other than your server's.
  • A cancelled or aborted print now says so, naming the file and the percentage it stopped at, however the stop was made: Home Assistant, the Creality app, or the printer's own screen. Shares the Notify when a print ends toggle.
  • Notification text is translated, Spanish included. It follows the server language (Settings → System → General), not each user's, because an integration is never told which user a notification is for. Use the bus events for per-user text.
  • snapshot_supported attribute on camera entities, saying whether a still image is possible at all.
  • Filament estimate sensors: expected_material_length (cm), expected_material_weight (g) and filament_consumption (%, used over expected, uncapped and deliberately not the same as print progress). The figures are the slicer's own, read from the printer when the running file changes; nothing is derived from an assumed diameter or density. Firmware that does not answer the request leaves the three uncreated rather than permanently unknown. Weight is blank for files the printer did not slice itself, and for multi-material jobs, which are not broken down per filament (#122).
  • Edit filament from the CFS card. Each slot tile gains an edit dialog for material type, name, vendor, colour, temperature range and pressure advance. It writes, then asks the printer to re-report, so the tile only changes once the write lands.
    • Names the box and slot it will write to, and says so when it inferred them from the card layout.
    • Disabled while the printer is busy, and for cards whose entities span more than one printer.
    • Multi-colour spools show their colour read-only; the other fields still save.
    • Colour presets: Creality's palette plus your own, kept in your browser.
  • ha_creality_ws.set_cfs_material service for writing slot metadata from automations. Only supplied fields change; omit one to keep the printer's value.
  • New CFS slot attributes: box_id, slot_id, min_temp, max_temp, pressure. Not every printer reports the temperatures, so treat null as unknown rather than zero.
  • spool_key attribute on every CFS slot (closes #117 part 2). The printer's rfid is a material id, not a tag serial, so spools of the same material shared it and external trackers such as spoolman-sync could not tell them apart. spool_key combines it with the normalised colour. It is derived, not new telemetry: two genuinely identical spools still collide, and raw rfid is passed through unchanged.
  • color_hex_raw attribute: the printer's original colour string, alongside the corrected color_hex.
  • Third card display mode, box: a photo of the CFS unit with a spool overlay per bay. Needs a mapped four-slot box, and falls back to the full view.
  • Optional go2rtc RTSP port under Configure → Camera, for a go2rtc on a non-default RTSP port. 0 keeps auto-detection.
  • Fan entities documented (#114). fan.*_model_fan / *_case_fan / *_side_fan have always supported on/off and speed; the README now covers them, with a chamber-too-hot automation example.

Changed

  • ⚠️ sensor.<printer>_system has been removed. It was a byte-identical duplicate of sensor.<printer>_model and is removed from the registry on upgrade. Point any dashboard or automation at sensor.<printer>_model.
  • ⚠️ The card's compact_view option became view_mode (full | compact | box). Dashboards migrate automatically; no action needed.
  • The Notification Device setting became Notification targets and accepts several. Existing configs migrate on load, and the old value stays on disk so a downgrade works. The live card is opt-in.
  • The Notify when Completed option is now Notify when a print ends and covers stopped prints too. If you had it on, you will now also hear about cancellations.
  • Each options page saves when you submit it. The old Save and apply menu item is gone, so closing the dialog normally no longer discards everything. Done and the window close button both just close.
  • Changing only notification settings no longer reloads the integration, so the connection stays up and no entity blinks while you tune text. Every other page still reloads.
  • Notification messages name the file, not its full path. Sensor attributes still publish the raw value.
  • The built-in notification wording is shorter and leads with the printer: Print "3DBenchy.gcode" completed successfully! became K1C finished. Custom text reproduces the old phrasing exactly if you preferred it.
  • The camera-mode dropdown and the camera and power-switch help text are translatable; they were hardcoded English.
  • Notifications are no longer awaited inside the WebSocket receive loop, which could stall the connection and flicker every entity unavailable.
  • The card only re-renders when something it displays changed, instead of on every state update.
  • Printer status is derived in one place, so the card and the service cannot disagree about whether the printer is busy.
  • The bundled CFS image is 17 kB instead of 509 kB (WebP). www/ was 143 kB, so a PNG would have quadrupled every install.

Fixed

  • Late-discovered entities were scheduled from the wrong thread. A CFS unit or chamber appearing after setup created entities from an executor thread via the non-thread-safe hass.loop.call_soon, racing the event loop.
  • A printer reporting a bare error code took every print-status attribute down with it. Some firmware sends err as a number rather than {errcode: N}; the attribute builder called .get() on it and lost state_raw, left_time_s and the rest to an AttributeError.
  • Pause was sent to printers that had already stopped, because the coordinator counted any job with a file name and a progress value as printing. Pause and resume now use the same state derivation as everything else.
  • A queued pause or resume outlived its job and fired as the next print started. Queued requests are dropped when the job ends.
  • Stopping a print and re-running the same file left notifications dead: the new-job check required a completion, which a stopped print never produces, so the second run got nothing.
  • The G-code preview vanished while a print was paused, and stayed hidden for the rest of a print once the printer set an error code it never cleared.
  • The diagnostic service was re-registered on every printer setup, and dumps always reported the Home Assistant version as unknown. Dumps now carry the real version and a UTC timestamp.
  • The legacy light switch and fan percentage controls could never be created, because the migration removing them ran before platform setup. The dead platform is gone; the cleanup migration stays.
  • The camera advertised a CameraEntityFeature.ON_DEMAND flag that does not exist. It declares STREAM, which is what native WebRTC needs.
  • Every field in the printer card's Style Editor was labelled with its raw config key. The label function sat behind if (form.computeLabel), which ha-form never satisfies, so the translated labels were never used.
  • Saving a colour in the Style Editor changed colours you had not touched. The picker discarded the alpha on the way in and hardcoded 0.9 on the way out, so Save rewrote every colour to 90% opacity: the stop button's .95 and the light-off grey's .35 both became .90. Three-digit hex like #abc also came back invalid. Both directions now keep the alpha and understand shorthand.
  • The printer card had branches for resuming and pausing, states the integration never reports, so a colour and two icon choices were dead.
  • A failure to serve the dashboard cards was logged at debug level, so the cards 404'd with nothing in the log. It is a warning now.
  • A notify target that could not be routed failed silently. The field accepts free text, so a typo simply did nothing; it now logs a warning.
  • Notification state stopped tracking when no target was configured, so enabling notifications mid-print could fire a spurious "completed".
  • The camera snapshot is skipped where it cannot work, rather than rendering an empty grey box. Applies to K2 direct-WebRTC cameras and to the G-code preview when the printer has none.
  • Camera stream API (HLS, recording, casting) failed with TypeError: 'str' object is not callable (closes #116, thanks @Raymondvb1985). A synchronous stream_source property returning the go2rtc stream name shadowed core's async def stream_source(). It is now an async method returning an RTSP URL, with the port detected automatically (18554 built-in, 8554 stand-alone) and overridable. Frontend WebRTC playback is unchanged.
  • Wrong CFS spool colour: the leading pad character was kept (closes #113 and #117 part 1, thanks @raf802). Creality tags store seven hex characters, one of padding then RRGGBB, so 0ffffff was read as #0fffff. The last six digits are used now and normalised to lowercase; non-hex values such as N/A are left alone. The CFS card already compensated, so its rendering is unchanged.
  • Generic Generic PLA in the filament label (closes #115). The vendor is only prepended when the name does not already start with it.
    • ⚠️ A vendor the printer never reported is no longer invented. A slot reporting only PETG was labelled Generic PETG; it now falls back to the material name, then the type. Update any template matching the old value. An empty slot reports Unknown rather than 'Generic '.
  • "Print completed" notification on every Home Assistant restart (closes #112, thanks @chairstacker). The printer reports the finished job indefinitely, so a fresh coordinator read it as new. The first frame carrying print state is now recorded silently, and the same guard covers the error, runout and minutes-to-end notifications.
  • Minutes-to-end notification never fired: it read printTimeLeft, but the printer streams printLeftTime.
  • Chamber-target control missing after a restart while the printer was off. number.<printer>_chamber_target was only created if maxBoxTemp had already arrived, and nothing recreated it later. It now uses the capability cached during onboarding, and late-arriving telemetry fires a discovery signal so capabilities create their entities without a restart.
  • Dynamic CFS discovery relied on a swallowed error: async_add_entities is a synchronous callback, so awaiting it raised TypeError every time, discarded because nothing held the future.
  • Completion notification only ever arrived once per file name, so reprinting the same file never notified again. It re-arms below 90% progress, or on a job-clock restart for a print that never got near the end. (Re-arming on any dip below 100% would fire twice per print: the printer rounds up to 100 a second early, then reports 99 once more.)

Internal

  • The coordinator holds its ConfigEntry rather than the entry id, removing five async_get_entry round trips.
  • The options flow no longer receives the config entry Home Assistant already gives it.
  • typing.Optional/List/Dict replaced with X | None, list, dict; Callable and friends from collections.abc.
  • KEntity's reads of the onboarding cache are covered by tests; they had none.
  • Removed the backwards-compatibility code the 2026.7 minimum makes unreachable: six try/except ImportError blocks, the pre-2024.7 static-path API, the pre-dataclass Lovelace resources access, and positional-argument handling in fan.turn_on. Two import-time shims stay so an ancient core still gets the friendly message.
  • Deleted code nothing called: six functions, a write-only parameter, four constants, a no-op if, and a test asserting "logistics" not in manifest.json.
  • Modernised deprecated APIs: FlowResult → ConfigFlowResult, AddEntitiesCallback → AddConfigEntryEntitiesCallback, dt_util.utcnow(), get_running_loop().
  • The test suite no longer depends on collection order: shared stubs moved to conftest.py, so every module runs on its own.
  • LATE_DISCOVERY_FIELDS in const.py lists the telemetry fields that gate entity creation; the coordinator fires one discovery signal the first time each appears.
  • New shared CFS helpers in utils.py (normalize_color_hex, format_filament_label, build_spool_key) replacing duplicated inline logic across three sensors.
  • Regression tests for all of the above.

Notes

  • The live card needs iOS 17.2+ or Android 16+. Older phones still get a notification that replaces itself in place, without the timer and progress bar.
  • iOS ends any Live Activity after 8 hours, an Apple limit no app can extend. Past that the card continues as an ordinary notification with the remaining time in the text, and the completion notification still arrives. Android has no such limit.
  • The G-code preview does not appear in an iOS Live Activity; that layout has no image slot. It shows on Android and on the plain notifications on both platforms.

Notes for anyone with CFS hardware

Creality does not document the modifyMaterial command. The payload shape comes from @buzato's testing against real hardware and is verified here against the bundled simulator, but two details are unconfirmed: the printer streams colours as seven hex characters yet appears to accept six on write, and the rfid field name is inferred from telemetry. Every write logs the outgoing payload and what the printer reports back. If a material edit does something unexpected, please open an issue with that part of your debug log.

Test server (tools/creality_printer_test_server.py)

Dev tooling only. Several fidelity gaps made the simulator disagree with real hardware.

  • Fan telemetry used names the integration never reads (caseFan rather than caseFanPct and so on), so fan entities looked stuck at 0. It now emits the real names, honours M106 P<ch> S<0-255> over gcodeCmd, and leaves a manually driven fan alone.
  • Video was answered as VP8, which HA's stream component cannot package into HLS, so the playlist blocked forever. It answers H.264 first now (--prefer-codec).
  • Keyframes were up to 25 s apart, inherited from libx264's 250-frame default, long after HA's stream worker gives up. Video is pre-encoded with a 1 s GOP (--video-source auto).
  • Healthy WebRTC sessions were killed after 60 s by an unconditional sleep-then-close. Teardown follows the connection state.
  • --deterministic removes temperature, fan and position randomness so telemetry is reproducible. Progress fields stay time-derived.
  • --cfs-variant edge adds the awkward payloads: a six-character colour, a vendorless slot, a multi-colour spool, shared rfid values, and an empty external slot.
  • Test-control endpoints (POST /test/set, /test/reset, /test/cfs, GET /test/state) pin any telemetry field, so notification scenarios can be driven in seconds. Real printers have no such endpoints.
  • Log lines carry timestamps, and the offer/answer SDP is dumped under --debug.

Don't miss a new ha_creality_ws release

NewReleases is sending notifications on new releases.