Skip to content

Releases: joyfulhouse/brilliant-mqtt

v0.11.4 — recovery settlement, update connect retry, repair code policy

Choose a tag to compare

@btli btli released this 26 Oct 23:11
2fe4a0e

This is a Home Assistant integration release only. The bundled on-panel agent
stays at 0.11.3 with release ordinal 5, so panels already on 0.11.3 need no
update and their Update entities stay current. Installing it does not touch
panels or their retained rollback baselines.

Fixed

  • Repair no longer upgrades a panel's code or bypasses a retained rollback
    baseline. Automatic repair, the Repair button, the brilliant_mqtt.repair
    action (including against the fleet entity), post-OTA refresh, and watchdog
    enablement used to replace installed bridge or watchdog code with a newer
    loaded release without capturing a baseline. That included a panel rolled
    back to its predecessor during a canary rehearsal. These paths now install
    code only where none is installed, and otherwise keep the installed release's
    own code and unit while still restoring configuration and services. Upgrades
    go only through the canaried Update entity or brilliant_mqtt.redeploy, so
    loading a new integration release no longer rolls it out to panels that go
    offline. While a panel holds a retained baseline in any state, these paths
    install no code at all and report baseline_retained_finalize_first where code
    would be needed. Enabling a watchdog whose installed code differs from the
    bundle reports release_update_required. In the stopped pre-ordinal bridge
    recovery, turn the watchdogs back on only after finalizing the baseline.
    (#220)
  • Agent updates from the Update entity or redeploy retry transient SSH connect
    failures before any panel change. Retried failures are host or network
    unreachable, refused or reset connections, connect timeouts, temporary DNS
    failures and connections lost during connect. A failure is retried only if SSH
    authentication never began, so the password is never sent twice. An update
    makes up to 5 attempts with capped, jittered exponential backoff. The 2-minute
    retry budget starts once the first attempt holds the fleet SSH lock, and later
    lock waits are cut off at that deadline. Progress stays at the pre-connect
    stage while it waits, and each retry logs its attempt number and classified
    reason. Authentication, host-key, key-exchange and admission failures fail
    immediately without retry. When every attempt fails, the update reports the
    attempt count. The fleet SSH lock is released during backoff, and the panel
    stays reserved against a concurrent update or repair. An unload or reload
    during the wait stops the update without connecting or raising a Repair issue.
    Resuming after a connection loss during or after remote mutation remains open
    in #219.
  • Panel connect-failure logs record the errno and its symbolic name instead of
    the OS error text, which for a failed TCP connect includes the panel address.
  • An interrupted Add Brilliant panel operation that never created a panel entry
    can be settled again (#214). If its recorded address or password no longer
    works, start Add Brilliant panel with the panel's current address and root
    password. After the pinned SSH identity matches, an explicit confirmation rolls
    the panel back to its recorded prior state. The existing verified-restored
    finalization then follows. Recovery uses the candidate recorded in the
    journal, not the currently bundled release. Fresh credentials are never
    written to retained metadata, and failed or unverified recovery is never
    finalized or erased.
  • Recovery failures before restore intent now record a typed last_error
    (recovery_connection_failed, panel_authentication_failed,
    panel_identity_mismatch, recovery_artifact_invalid) shown in diagnostics
    and the repair, instead of an untyped recovery_failed with
    last_error: null.
  • Other panels' updates and canary actions blocked by an unrecovered journal
    report provisioning_recovery_required, with guidance, instead of
    transaction_in_progress. Operations remain serialized.

Validation

  • Root gate (Python 3.10): 2,819 passed, 1 skipped. Integration gate (Python 3.14): 2,131 passed, 6 skipped. Ruff, formatting and strict mypy clean; all eight hosted checks passed.
  • Each fix had an independent review, and review findings were fixed before merge.

Known limitations

  • #214: the supervised settlement flow is not yet confirmed on the reporter's hardware.
  • #219: only the pre-mutation connect stage is retried; resume after a connection loss during a remote change remains open.

v0.11.3 — recovery hardening, watchdog lease revocation, MQTT durability and safe provisioning diagnostics

Choose a tag to compare

@btli btli released this 23 Oct 09:48

The on-panel agent and Home Assistant integration both move to 0.11.3. The
bundled bridge and watchdog payload carries release ordinal 5; the separately
versioned voice payload remains at 0.1.1. Qualify this release on a canary panel
before updating the remaining panels.

Fixed

  • The bus watchdog remembers an independently observed live writer releasing its
    phase-marker lease, so stale failed-attempt evidence stays revoked after that
    writer exits. Failed continuing bus-attempt writes retain their lease. This
    reduces the read-only-filesystem residual in #143; entirely unsampled recovery
    and watchdog-restart ambiguity still require a separate delivery contract.
  • Watchdog reboot guards reject unsafe state files and preserve their rolling
    reboot limits across clock corrections. Wi-Fi storage refusals log once per
    outage while continuing to retry the storage operation.
  • Scene events and results wait for their own state to persist before MQTT
    delivery. Retained-ledger loading has a deadline, and orphan cleanup preserves
    temporary files belonging to other ledgers.
  • Panel credential repair accepts a changed address and password together while
    preserving the stored SSH identity. Updates explain when an earlier rollback
    baseline needs explicit finalization, and snapshot probe failures include
    safe retry guidance.
  • Onboarding can explicitly finalize a verified restored baseline that has no
    Home Assistant owner, using fresh credentials and the retained SSH identity.
    Interrupted cleanup requires fresh authorization on retry and never persists
    the submitted password in retained rollback metadata.
  • Onboarding bounds operation-lock and recovery waits. Payload uploads perform
    local filesystem work outside Home Assistant's event loop and settle an
    in-flight read before cancellation closes the remote stream.
  • Legacy watchdogs without a VERSION file can inherit a verified same-panel
    pre-0.11.0 bridge version. Admission audit records distinguish admission from
    verified deployment; stopped legacy recovery covers both watchdog units.
  • MQTT connection failures use capped exponential retry delays. Repeated bus
    starts fenced by unresolved cleanup eventually exit for a systemd restart;
    BUS_FENCED_START_LIMIT configures the threshold (default three).
  • Both watchdogs record a persistent UTC shutdown marker on SIGTERM.
  • Ignored transition fields no longer prevent safe partial command merging, and
    discarded folded commands produce a warning without exposing payloads.

Changed

  • BLE mesh peripherals appear as separate Home Assistant devices, with their
    primary and auxiliary entities grouped together. Entity unique IDs and MQTT
    topics remain stable across this change and mesh leader changes.

Validation

  • Agent (Python 3.10): 2,819 passed, 1 skipped. Home Assistant integration (Python 3.14): 2,014 passed, 6 skipped. Ruff, formatting, strict mypy and generated-payload parity pass; all eight hosted checks passed on e790bdd.
  • The published brilliant_mqtt.zip was verified byte-for-byte against the reviewed integration and payload manifests before installation.
  • Live canary: installed through HACS and deployed to a pilot panel through the supported single-panel update (normal ordinal 4 → 5 admission, retained predecessor baseline), then soaked for more than 48 hours with matching component digests, unchanged service processes and no automatic restarts, before the remaining panels were updated.

Known limitations

  • A dedicated rollback rehearsal and responsiveness measurements for this release are still pending (#164).
  • Updates do not yet retry transient panel-connection failures automatically (#219); retry the update once the panel is reachable.
  • The read-only-filesystem watchdog residual (#143) and network return-path investigation (#173) remain open.

Merged to main in #218 (includes #215 and #217).

v0.11.2 — fail-closed watchdog reboot guards, legacy auto-repair canary gate, ledger deadline, lane field merge

Choose a tag to compare

@btli btli released this 01 Oct 05:59
d990adb

The on-panel agent and Home Assistant integration both move to 0.11.2. The
bundled bridge and watchdog payload carries release ordinal 4; the separately
versioned voice payload remains at 0.1.1. Qualify this release on a canary panel
before updating the remaining panels.

Fixed

  • A bus panel whose reboot guard state cannot be written now refuses to
    self-reboot until an operator fixes the storage, preventing an unrecorded
    reboot from being authorized on every boot (#209).
  • The Wi-Fi watchdog no longer crashes when it cannot record a reboot in its
    guard state file. If the state file was already unreadable (for example, a
    directory at that path), the watchdog logs the failure and still reboots,
    at most once per cooldown. If the state reads fine but cannot be written
    (full disk, read-only filesystem, permission denied), the watchdog logs the
    failure and refuses to reboot, because an unrecorded reboot would be
    authorized again on every boot. A panel in that state will not reboot itself
    to recover Wi-Fi until an operator fixes the storage.
    (#195)
  • The manifest uses minimum-version specs for asyncssh and paho-mqtt, so
    hassfest accepts them and the integration still installs on HA 2026.6.x.
  • A partial MQTT setter that supersedes a light or switch write still waiting
    for the device now merges per field, with the later value winning, rather than
    dropping the waiting write's other fields. Writes already issued to the
    device, and commands for other loads, are never merged.
    (#159)
  • A stalled retained-ledger write now fails closed after 10 seconds, matching
    the MQTT acknowledgement bound. Before that deadline, state for loads the
    panel already owns is no longer held up by another load's pending write.
    After it, publishes fail closed until the late write settles; the next
    publish then rewrites the ledger from memory before anything reaches the
    broker, so a late write cannot drop an owned topic or race a later write.
    Session shutdown and process exit are delayed by at most the deadline.
    (#176)
  • A ledger failure during a wired light or switch state publish now reports
    the retained_ledger degraded status on the next session tick instead of
    after the next periodic resync.
    (#177)
  • Background auto-repair, the Repair button, and the repair service no longer
    auto-admit a pre-0.11.0 panel's code. Only the Update entity, redeploy, and
    provisioning, which run the canary and retain a rollback baseline, perform the
    first pre-ordinal upgrade (#181). A release_override cannot waive this, and
    the blocked message now points at a plain update instead of an override.
    Those paths need a baseline, which requires the bridge unit to be active. If
    a pre-0.11.0 panel's bridge is stopped or failed, repair no longer brings it
    back (as in 0.11.0; only 0.11.1 did) and update reports baseline_correlation_unsupported. Start
    brilliant-mqtt on the panel and update. Otherwise turn off the panel's
    watchdog component switches, run brilliant_mqtt.uninstall, update, then turn
    the watchdogs back on. Uninstall stops and removes the agent, so the bridge
    stays offline until the update completes. See "Recovering a stopped pre-ordinal bridge" in
    docs/ha-integration.md.
  • Automatic pre-ordinal admission now logs one INFO line per operation, and a
    failure to write its audit record is reported with an operator-safe detail
    (#182).
  • After the scene state file is found corrupt, only the first scene or mode
    record the agent observes is treated as history and suppressed. Previously a
    second record that arrived while the first one was still being written to
    disk was also suppressed, so a real scene execution could go unreported
    (#112).
  • The Wi-Fi watchdog no longer treats a corrupt, unreadable or wrong-type
    reboot-guard state file as an empty history. It blocks reboots for one
    cooldown period, logs the lost history once at ERROR, then resumes under the
    normal cooldown and cap. A missing state file still counts as a fresh install
    (#140). The
    fail-closed window is held in memory, so a watchdog restart re-arms it, and a
    restart loop faster than one cooldown keeps reboots blocked; this is the
    deliberate fail-closed direction.
  • The bus watchdog now treats corrupt, unreadable, wrong-type, non-finite, or
    future reboot-guard state as lost history and blocks reboots for one cooldown
    before resuming the normal cooldown and rolling cap
    (#193).

Known follow-ups

  • #173: canary connectivity (ARP/neighbor fault) still blocks the soak; a workaround is in place.
  • #208: a refused reboot (unwritable guard state) re-logs every poll during an outage; the ERROR line also claims a reset that did not happen.
  • #188, #191, #201: release-identity audit ordering, the snapshot_probe_failed operator detail, and scene-bridge publish-before-persist.
  • #197–#200, #202–#205: test hardening and hostile-state-file follow-ups.

Reviewed by gpt-6-astra and claude-opus-5-5 (with claude-fable-5-1 on earlier rounds); implemented by claude-opus-5-5 and gpt-6-luna.

v0.11.1 — auto-admit upgrades from pre-ordinal releases

Choose a tag to compare

@btli btli released this 28 Sep 00:10
83904d4

The on-panel agent and Home Assistant integration both move to 0.11.1. The
bundled bridge and watchdog payload carries release ordinal 3; the separately
versioned voice payload remains at 0.1.1. Qualify this release on a canary panel
before updating the remaining panels.

Fixed

  • Panels running a strict pre-0.11.0 release with no ordinal can upgrade to an
    ordinal-bearing release without a manual override. Admission is recorded for
    audit and retains the existing canary rollback baseline.

Known follow-ups

  • #180: panels on 0.10.0 or older whose watchdog has no VERSION file still need a one-time manual override.
  • #181: background auto-repair can move a pre-0.11.0 panel to 0.11.x without the canary or a rollback baseline.
  • #179, #182: release-identity policy clarification and test/audit gaps.

Reviewed by gpt-6-astra and claude-opus-5-5; implemented by gpt-6-sol.

v0.11.0 — reliable command lanes, partial-command merging, wired feedback freshness, verified canary rollback

Choose a tag to compare

@btli btli released this 27 Sep 20:26
65254fb

The on-panel agent and Home Assistant integration both move to 0.11.0. The
bundled bridge and watchdog payload carries release ordinal 2; the separately
versioned voice payload remains at 0.1.1. Update through the per-panel bridge
Update entity after qualifying the release candidate on a canary panel.

Added

  • Panel response diagnostics distinguish command queue/native-write timing,
    outcomes, ticket revocations, and reconnect degradation from basic online
    status in bounded retained bridge metadata. The operational runbooks cover
    Wi-Fi/broadcast response qualification and a diyHue reflection proposal;
    the project documentation also gains a Built with Omnigent badge and footer.
    (#152,
    #157,
    #154)
  • Mesh writes expose pending feedback separately from confirmed physical state;
    cancelled publishes invalidate feedback caches.
    (#156)
  • Canary updates retain a verified predecessor baseline through the soak period,
    with explicit single-panel rollback/finalization and recovery after interrupted
    operations. Release identity admission checks selected code digests and ordinal
    before mutation; same-version but different code cannot silently overwrite an
    incumbent, and legacy unknown-ordinal installations require a bound override.
    (#168;
    #165,
    #166)

Changed

  • Interactive writes take priority over maintenance without breaking target
    ordering; newer waiting intents supersede stale ones, while maintenance
    retries back off after failures. Ticket recovery preserves the newest write
    across a route change and contains benign write cancellation.
    (#158,
    #163)

Fixed

  • Compatible partial MQTT setters now merge before dispatch rather than losing
    earlier fields; unsafe commands remain FIFO barriers.
    (#170;
    #159)
  • Failed or cancelled per-peripheral command workers no longer strand queued
    commands or stall teardown. Bounded recovery, cooldown, and discard logging
    make lane failures and active-fold fallback observable without exposing
    command contents.
    (#171;
    #160,
    #161)
  • Wired light and switch feedback no longer lets a delayed pre-command snapshot
    overwrite the requested state (the ON -> OFF -> ON flicker). Native
    observations are kept separate from a provisional request that expires after
    a fixed 20-second window; contradictions that metadata cannot resolve are
    published as ambiguous rather than suppressed, and the device's own state is
    published once the window ends. Mesh behaviour is unchanged. New
    wired_write_status, wired_requested and wired_write_deadline keys
    appear while a write is pending.
    (#174;
    #172)

Known follow-ups

  • #176: retained-topic ledger persistence has no deadline (pre-existing).
  • #177: wired publisher swallows ledger failures; mutation-coverage gaps (LOW).

v0.10.2 — harden the watchdog relay against marginal-link stalls

Choose a tag to compare

@btli btli released this 10 Sep 18:47
c52be4d

The on-panel agent and Home Assistant integration both move to 0.10.2. The
agent's code is unchanged from 0.10.1; the version bump exists so every panel's
per-panel bridge Update entity offers this release and re-runs the deploy
through the hardened path below. The voice payload remains at 0.1.1 and is
unchanged.

This release hardens the HA-side deploy machinery after a live finding during
the 0.10.1 fleet rollout — nothing in the panel agent changed.

Canary: the hardened watchdog deploy (deploy_bus_watchdog streaming one
tarball + the relay's carried restart) was exercised against the pilot panel
(Office) before release — bus watchdog marker 0.10.1 → 0.10.2, watchdog
restarted, bus-phase marker success, LWT online.

Fixed

  • Integration: on a panel with a marginal Wi-Fi link (guest-bath, during the
    0.10.1 rollout) the bus watchdog's recursive SFTP put_dir stalled past the
    120 s operation timeout while the bridge tarball deployed fine. The relay had
    already swapped the new watchdog tree and stamped its VERSION marker when it
    died at the restart step, so every later converge read "already converged"
    and skipped the restart — leaving the previous process running code it had
    never loaded (a manual systemctl restart fixed it live). Three fixes:
    deploy_wifi_watchdog / deploy_bus_watchdog now ship ONE gzipped tarball
    (built off-loop, streamed in a single SFTP write, extracted into staging,
    then swapped) — the same transport the bridge payload already uses, instead
    of asyncssh's one-round-trip-per-file recursive put; _relay_watchdog
    retries a failed converge once and carries a restart owed by this call's
    deploy across the retry even when the VERSION marker already reads
    converged, and force-restarts once more when both attempts fail while the
    marker says the new code is live; and shell.put_dir pre-walks the local
    tree in an executor (HA's event-loop watchdog had logged a blocking scandir
    for asyncssh's recursive put during the rollout).

v0.10.1

Choose a tag to compare

@btli btli released this 10 Sep 14:56
0b751cf

The on-panel agent and Home Assistant integration both move to 0.10.1. The
agent's code is unchanged from 0.10.0; the version bump exists so every panel's
per-panel bridge Update entity offers this release, and installing it is
what brings the bus-health watchdog on each panel up to the same release as
the bridge (see Fixed). The voice payload remains at 0.1.1 and is unchanged.

Canary: the release's panel recipes (deploy_payload + bus-watchdog
inspect/redeploy/restart, exactly what the Update entity now runs) were
executed against the pilot panel (Office, flat legacy layout) before release —
watchdog marker converged None → 0.10.1, bridge and watchdog restarted
cleanly, bus-phase marker success, LWT online.

Fixed

  • Integration: the per-panel Update entity install (and the
    brilliant_mqtt.redeploy service) shipped the bridge app only, so a fleet
    updated that way kept the previous release's bus-health watchdog code —
    silently breaking the 0.10.0 "upgrade the bridge and the bus watchdog
    together" contract (the old watchdog reads the new bus-phase marker as
    unknown and fails safe to no reboot). The Wi-Fi and bus watchdogs now carry a
    VERSION marker under their /var/brilliant-mqtt/<name>/ directory, and
    every repair, post-OTA refresh and Update-entity install redeploys and
    restarts a selected watchdog whose marker is missing or differs from the
    bundled release. The Update entity converges the companion components before
    restarting the bridge; a companion failure is logged and never fails the
    bridge update.

v0.10.0 — bus-phase watchdog gating, scene delivery guarantees, bounded MQTT backlog

Choose a tag to compare

@btli btli released this 08 Sep 11:58
a1f5939

The on-panel agent and Home Assistant integration both move to 0.10.0. Update
every panel through its per-panel bridge Update entity. The voice payload
remains at 0.1.1 and is unchanged.

Upgrade the bridge and the bus-health watchdog together. The bridge now
stamps a bus-phase marker (BUS_PHASE_FILE, default
/run/brilliant-mqtt/bus-phase) that the bus-health watchdog reads before it
may reboot a panel. The marker's on-disk format is a shared, versioned
contract: writer and reader must be upgraded and rolled back as a pair. If a
deploy or rollback leaves only one side updated, delete the marker before
starting either service: rm -f /run/brilliant-mqtt/bus-phase. Unknown or
version-skewed records fail safe to no reboot. See
docs/reference/deployment.md (bus-watchdog phase-file coupling) and
docs/CONFIGURATION.md (Bus-health watchdog → BUS_PHASE_FILE).

Canary: pilot panel (Office) ran this exact payload under systemd before
release — bus + broker connect, discovery/telemetry, bus-phase marker
stamped and read by the watchdog, and LWT/restart recovery all verified.

Fixed

On-panel agent

  • Bus session teardown no longer leaks resources or lets stale callbacks
    touch the next session.
    The observer and processor are owned before they
    are started and unwound on any startup failure or cancellation (a handshake
    failure used to leave the processor's reconnect work alive, and three
    retries stacked three live peers); teardown is fenced by a session token
    and the shutdown flag, so a callback that outlives shutdown cannot deliver
    the rest of its snapshot or continue reconnect fan-out; observer and
    processor close under one total deadline, with an unresolved close fencing
    the next session's start instead of allocating another peer.
    (#104,
    #135;
    #88,
    #130,
    #131)
  • Quiet panels reconnect promptly after the MQTT reader dies. An
    unexpected end of the MQTT receive loop is consumed on the next session
    tick and rebuilds the session, instead of going unnoticed until the next
    publish or the periodic resync on a panel whose state was not changing.
    (#100;
    #89)
  • Inbound MQTT backlog is bounded, so a stalled bus write plus an
    automation burst can no longer grow memory until the 96 MB service cap
    restarts the agent. The transport queue upstream of the per-peripheral
    command lanes is capped at 64 messages / 256 KiB of payload, with
    latest-wins coalescing for idempotent setters at admission. Exceeding a
    bound is an observable overload: the excess is shed and logged and the
    session is rebuilt through the normal backoff, never dropped silently.
    (#101;
    #90)
  • Scene events and command results survive a disconnect between local
    send and broker receipt.
    The durable outbox publishes at QoS 1 and marks
    a record delivered only after the broker's PUBACK; an unacknowledged record
    is replayed with the same dedup key / command id, including across a
    restart. Broker acknowledgment is a transport guarantee only, not proof
    that Home Assistant processed the message.
    (#107;
    #92)
  • A second scene or mode command after a delivered result reaches the
    bus.
    Outbox pruning could drop an event still referenced by a delivered
    result; the next state snapshot then failed validation, marked the scene
    state untrusted, and routed every later command to health only. Pruning
    now clears the dependency first and persists once per delivery; a state
    file written by the old rule self-heals on load.
    (#136;
    #124,
    #122)
  • Repeated same-mode activations are detected through polling when the
    push is missed.
    The hot-poll change fingerprint includes the
    manual_mode_id timestamp, so re-activating the current mode with a new
    bus timestamp emits its event and confirms a pending command instead of
    timing out. Scene blobs, whose value already embeds the execution time,
    keep their timestamp-only refreshes suppressed.
    (#105;
    #93)
  • Scene and mode commands are confirmed only by executions at or after the
    request.
    Each pending command records a panel-clock baseline; a delayed
    or historical execution newer than the watermark but older than the
    request still emits its native event but no longer returns
    accepted: true. Mode Variable.timestamp is panel-clock epoch-ms and a
    same-value write does not re-stamp, so a request for the already-active
    mode is settled by the successful write RPC rather than waiting for a
    stamp that never comes.
    (#116,
    #141;
    #94,
    #119)
    Operator note: the scene state file gains a confirm_after_ms field
    (no version bump; old files load and are migrated on first save). A state
    file written by 0.10.0 and read by an older agent trips state_untrusted
    (a fail-safe drop, not corruption) until the agent is upgraded again.
  • The liveness heartbeat is stamped before broker-dependent work. Startup
    runs a real bus read and heartbeat before the scene bridge's MQTT
    subscriptions, and reconcile beats before publishing availability, so a
    broker that rejects a publish or never SUBACKs cannot starve the heartbeat
    and provoke a bus-watchdog reboot of a healthy panel. Scene callbacks are
    registered at construction and early executions buffered, so nothing is
    lost during the startup window.
    (#118,
    #139;
    #87,
    #125)

Bus-health watchdog

  • Broker-only outages no longer reboot a healthy panel. A stale
    heartbeat alone is no longer enough: the watchdog also requires the
    bus-phase marker to attribute the stall to the local bus. Broker refusal,
    DNS/TLS/auth failures, and retained-ledger errors never reach the bus, so
    they read as pre_bus and cannot qualify; a sustained bus handshake/read
    failure still reboots under the existing cooldown/cap. A failed stamp
    disables only the reboot guard (logged at WARNING) and never takes the
    bridge down; a marker naming pid <= 1 is rejected. Attribution is timed
    and generation-aware: only an unbroken run of validated bus-attempt
    failures within a 300 s continuity bound counts, a successful read resets
    it, an attempt is not authoritative until its lease is acquired, and
    evidence older than the bridge unit's current systemd start generation is
    discarded. The watchdog needs systemctl show on the bridge unit to
    succeed; a failed or empty query degrades to no reboot.
    (#99,
    #115,
    #139;
    #87,
    #111,
    #126,
    #127,
    #133)
    Operator note: see the paired-upgrade contract at the top of this
    release. Known residual: on a read-only filesystem a recovered-but-
    unrecorded bus whose writer then dies can be honored as a stale attempt
    for up to ~300 s during restart backoff
    (#143).
  • Every probe, recovery, and reboot child process is bounded (ip route, ping, systemctl is-active, systemctl reboot): on timeout the
    whole process group is killed and reaped, the result reads conservatively,
    and the poll loop continues instead of wedging alive-but-stuck.
    (#117;
    #97)

Wi-Fi watchdog

  • A reboot deferred or unconfirmed during an outage is retried. The
    reboot rung used to latch as fired the moment it was wanted, so a reboot
    blocked by the 1 h cooldown or the rolling cap — or one whose systemctl reboot timed out or failed after the GPIO/SDIO reset — was never
    requested again until connectivity returned or the daemon restarted. The
    rung now stays re-armable on every guard-eligible poll, every destructive
    attempt is charged to the persisted cooldown/cap (the sole rate limiter),
    and a blocked reboot logs its deferral once rather than looping.
    Soft-reconnect and service-restart rungs remain one-shot.
    (#106,
    #138;
    #91,
    [#128](https://github.com/joyfulhouse/brilliant...
Read more

v0.9.3 — Ring live-view bus-stall tolerance

Choose a tag to compare

@btli btli released this 05 Sep 16:55
5fb2987

Agent-only release. Fixes #83 (PR #84): bounded hot-poll backoff (30 s) after a first bus read timeout, periodic resync deferred while the backoff is active and retried once after the window; a second consecutive miss still rebuilds the session. Operator note: a genuinely dead bus is now detected in ~40–45 s instead of ~12–20 s. Integration and voice payload (0.1.1) unchanged. See CHANGELOG [0.9.3].

v0.9.2 — MQTT subscription hardening, connect diagnostics, honest recovery reasons

Choose a tag to compare

@btli btli released this 03 Sep 16:23
637d86e

The on-panel agent and Home Assistant integration move to 0.9.2. Update every
panel through its per-panel bridge Update entity. The voice payload remains
at 0.1.1 and is unchanged.

Fixed

  • Connect-stage failures now carry actionable diagnostics. All four
    integration connect-stage handlers log the panel identity and exception
    class; OSError includes its errno and strerror, while AsyncSSH failures
    include their class and message. User-facing Repairs summaries and the
    allow-listed panel-operation path are unchanged.
    (#79; #75)
  • MQTT subscription hardening prevents avoidable session rebuilds. SUBACK
    reason codes are validated, command-topic subscriptions are deduplicated per
    session, and periodic resync gets one retry before two consecutive subscribe
    failures rebuild the session; initial reconcile remains fail-fast. This
    directly targets the multi-minute availability outages observed on weak-Wi-Fi
    Guest Bathroom and Office Bathroom panels after SUBACK-timeout session
    rebuilds.
    (#78; #76)
  • Post-update and repair recovery reports its true origin and tolerates
    reconnect activity.
    Timeout reasons now name whether an update or repair
    failed to recover, and append the API-drift diagnosis only when the journal
    contains its signature. A reconnecting panel receives one bounded 90 s
    extension after the existing 60 s window; a silent panel still escalates at
    60 s. Recovery timers use monotonic generations, cannot be orphaned, snapshot
    await-race state consistently, and classify diagnostics against the actual
    recovery origin. This changes the post-update/repair health-escalation reason
    text and caps the extended recovery window at 150 s.
    (#80; #77)