Skip to content

0.2.2 — survive an HA restart; never forward an empty allowlist

Choose a tag to compare

@GabrielGoldsteinAnidea GabrielGoldsteinAnidea released this 24 Aug 00:46
· 3 commits to main since this release
Immutable release. Only release title and notes can be modified.

Update strongly recommended. This release fixes a bug that inverted the add-on's purpose on every fresh install.

Huge thanks to @maxi1134, who diagnosed both headline bugs on a live ~3,600-entity instance and sent the fix in #11.

An empty allowlist was being relayed as no filter

HA parses subscribe_entities as set(msg.get("entity_ids", [])) or None. An empty entity_ids is therefore not "subscribe to nothing" — the or None makes it no filter at all.

config.yaml shipped with dashboards defaulting to fridge-status / home-status / dashboard-deck. Those are my own dashboards. On anyone else's instance all three return config_not_found, the union came back empty, and the add-on then streamed every entity on the instance — the exact firehose it exists to prevent. On the reporting instance that hit Node's 2 GB heap limit every 30–130 seconds in a Supervisor restart loop. Because reinstalling an add-on resets options to their defaults, a fresh install landed straight in it.

  • dashboards now defaults to [].
  • /api/websocket is refused whenever the allowlist is empty, with the reason named in the log. A second guard in the relay drops the connection rather than ever sending an empty entity_ids.
  • A failed dashboard fetch now logs the dashboards that do exist, so config_not_found answers its own question.
  • No dashboards configured no longer exits — that just moved the restart loop into the Supervisor.

⚠️ If you never set the dashboards option

You were silently running with no trimming at all. After updating, the add-on will refuse /api/websocket and say so in the log until you set dashboards to your own url_path values (Settings → Dashboards). That is the fix working, not a regression.

Surviving a Home Assistant restart

Restarting HA killed the add-on and left it crash-looping until started by hand. Three causes:

  • Unhandled socket error on an in-flight ws upgrade. A raw upgrade socket arrives with no 'error' listener, and http-proxy only attaches one after HA answers 101. An HA restart resets every in-flight stream at once (camera, Assist), and a reset in that window reached Node as a fatal unhandled 'error'.
  • process.exit(2) when the first allowlist couldn't be built. The add-on and core restart together, so each restarted container died in ~300 ms until the Supervisor gave up. It now retries on the same backoff used for later drops.
  • The proxy now listens before HA is reachable, so it serves the moment core answers. Until the first allowlist exists, /api/websocket gets a 503 and the frontend retries on its own.

A restarting HA also returns in stages, which used to leave the allowlist wrong:

  • A rebuild after reconnect merges rather than replaces, so a half-loaded core can't shrink a good allowlist. Real dashboard/registry edits still replace, so removals still take effect.
  • buildAllow() bails when every dashboard fails (HA authenticating but not yet serving lovelace) so the caller retries. A single dashboard failing is still tolerated — that's a typo'd url_path.
  • The control connection has a handshake timeout, so a core that accepts TCP but never completes the handshake still triggers a reconnect.

Also

  • EADDRINUSE / EACCES on startup now exits naming the port option instead of printing a raw stack (#6).
  • auth_invalid no longer exits; it logs loudly and retries slowly.
  • Repeated failures are collapsed in the log instead of flooding hundreds of identical lines per second.
  • DOCS.md no longer claims the allowlist is computed only at startup — live recompute has been in since 0.2.0.
  • Test suite grown to 44, covering an HA restart, a cold boot against a down HA, a half-started core, and the empty-allowlist guard.

Local add-on reminder: code is baked into the image at build time, so this needs a Rebuild, not a Restart.

Full changelog: v0.2.1...v0.2.2