Skip to main content

Homeassistant

@magistr/homeassistantv2026.08.19.1· 3d agoMODELS
01README

Home Assistant integration for swamp — query entity states, call services, list and update automations, and fetch history and long-term sensor statistics over the REST and WebSocket APIs.

Model:

  • @magistr/homeassistantlist-entities, get-state, call-service, list-services, list-automations, get-automation-config, update-automation, get-history (JSON + CSV), get-statistics (long-term WebSocket aggregates), and backfill-to-vm (bulk-import HA statistics into VictoriaMetrics).

Authenticates with a long-lived access token, supports http/https, and writes typed resources for every method so results are queryable as swamp data.

02Models1
@magistr/homeassistantv2026.08.19.1extensions/models/homeassistant.ts

Global Arguments

ArgumentTypeDescription
hoststringHome Assistant host (e.g., homeassistant.local)
tokenstringLong-lived access token - use vault: ${{ vault.get(my-vault, HA_TOKEN) }}
protocol?stringProtocol (http or https, default: https)
wsTimeoutMsnumberWebSocket statistics request timeout in ms (default: 60000)
03Previous Versions4
2026.08.02.1

2026.08.02.1

Real-fixes the seven remaining MED/LOW findings (LB3–LB9) that the 2026.08.01.1 test backfill characterized but did not fix, in the local homeassistant-latent-bugs issue-lifecycle model (never a Lab issue). Every former "pinned-to-buggy" test is flipped to prove the corresponding fix; every benign/frozen contract, methods, and property pin stays BYTE-IDENTICAL.

  • LB3 — non-JSON WS frame (MED): fetchStatistics's message handler no longer silently swallows a malformed frame (catch { return; }, waiting out the full 60s timeout). It now fast-rejects with a static "WebSocket received a non-JSON frame" error (never echoes the server-controlled ev.data, preserving the LB4 no-leak invariant).
  • LB4 — server-echoed token redaction (MED): added redactToken/ redactedCause helpers (value-based, telegram-send/headphones precedent). Applied at every server-echo throw site: WS auth_invalid, WS error event, WS !success result, haFetch's non-ok response body AND a caught network-layer fetch() rejection (redacted .message + a fresh single-level redacted cause — never the raw error, since Deno.inspect/ console formatting walks .cause including its .stack), and the VM import non-ok error. Redaction is a strict no-op on any message that doesn't contain the token, so every benign error-path pin (auth_invalid with no token echo, native WS errors, the error.json contract body, all REST 404/500 pins) stays byte-identical.
  • LB5 — raw REST path interpolation (MED): wrapped every interpolated path segment in encodeURIComponentget-state, call-service, get-automation-config, update-automation, and the per-entity /states lookup inside backfill-to-vm. Identity for benign ids (letters, digits, dots, underscores are unreserved), so every frozen URL contract pin stays byte-identical; only a literal / (or other reserved char) is now escaped into one opaque %2F segment instead of injecting an extra path segment.
  • LB6 — token not marked sensitive (LOW): InputSchema.token now carries .meta({ sensitive: true }) (matches telegram-send's botToken).
  • LB7 — asymmetric backfill fan-out (LOW): backfill-to-vm's per-entity fetchStatistics call is now guarded exactly like the existing /states guard (headphones onboard-artists / seadex summary.errors precedent): a failure records a redacted error on that entity's backfill-report summary, logs a redacted warning, skips its samples, and the fan-out CONTINUES to the next entity instead of tearing down the whole method. Added an additive, optional entities[].error field to the backfill-report resource schema.
  • LB8 — statistics missing-key vs. empty-range (LOW): replaced (msg.result && msg.result[statisticId]) || [] with an explicit four-way branch: (1) the requested statisticId key is present → resolve it verbatim (including an explicit []); (2) result is an object with ZERO keys → resolve [] — Home Assistant omits the key entirely for a legitimately empty range, so this is NOT an error; (3) result has OTHER keys but not ours → reject "Statistics response omitted requested statistic '<id>'" (anomalous — we only ever request one id); (4) result is falsy/not an object → reject "Statistics response missing result payload" (malformed). A new test pins the empty-object-is-legit-empty case explicitly so a future change can't accidentally make it throw.
  • LB9 — hardcoded WS timeout + swallowed close errors (LOW): added a defaulted wsTimeoutMs global argument (z.number().int().positive() .default(60000)) threaded into fetchStatistics; both get-statistics and backfill-to-vm read context.globalArgs.wsTimeoutMs ?? 60000. The default renders the byte-identical "WebSocket timeout after 60s" message. Every try { ws.close() } catch {/*ignore*/} call site is replaced by a closeQuietly helper that still NEVER re-throws or changes the rejection reason, but now surfaces the (redacted) close failure via context.logger.warning.
  • Pin flips: adversarial :415 (malformed frame, drop FakeTime), :475/:584 (WS/REST token echo → asserts redacted), :499/:518/:533 (raw path injection → asserts %2F-escaped); coverage :251/:269 (statistics wrong-key/falsy-result → asserts the new rejection messages) and :767 (token meta → asserts sensitive === true); methods :724 (backfill fan-out → asserts the method now RESOLVES with a per-entity error). New

Notes trimmed at a line boundary to fit the registry's 4900-byte per-version cap. Full section: https://github.com/umag/swamp-workspace/blob/d850d8e8372d4c0008c9245959a090b37095de7a/homeassistant/CHANGELOG.md

2026.07.16.2

Release 2026.07.16.2 — align model versions with manifests

Maintenance release across the @magistr extensions. For most packages this carries no functional change: the only edit is the model's version: field, brought back in line with its manifest version so the published model type version and the package version no longer drift.

Functional changes in this release are limited to:

  • anime-cron: normalizeTitle now strips a ": subtitle" suffix and a trailing parenthesized year before comparison, fixing dedup false-misses where the torrent title carries a subtitle or year that the AniList romaji does not.

  • arckit: first publish. Standalone ArcKit port — a 12-phase architecture governance state machine with 65 bundled templates, driven by a bundled skill.

Also tracks three extensions (kaiten, observability-agent, music-library) that previously existed only as untracked working-tree directories, recovered from stashes.

2026.07.16.1

Maintenance version bump. No functional changes.

Added 1 models

2026.05.25.1

Merge pull request #5 from umag/extensions/jscad-stl-pair

extensions: add 15 more @magistr extensions + auto-discover CI

04Stats
A
100 / 100
Downloads
58
Archive size
17.2 KB
  • Has README or module doc2/2earned
  • README has a code example1/1earned
  • README is substantive1/1earned
  • Most symbols documented1/1earned
  • No slow types (deprecated)1/1earned
  • Dependencies pass trust audit2/2earned
  • Has description1/1earned
  • Platform support declared (or universal)2/2earned
  • License declared1/1earned
  • Verified public repository2/2earned
05Platforms
06Labels