Files
alexei.dolgolyov 22127e2a59 feat: Home Assistant provider — WebSocket subscription + bot commands
Adds Home Assistant as a service provider with two coordinated surfaces:

Notifications (subscription):
- Long-lived WebSocket client (aiohttp ws_connect) with auth handshake,
  exponential-backoff reconnect, bounded event queue, and area-registry
  enrichment cached per (re)connect
- ServiceProvider ABC gains an optional `subscribe()` method for push-style
  providers; HomeAssistantServiceProvider uses it via a per-provider
  supervisor task started in the FastAPI lifespan
- 4 event types (state_changed, automation_triggered, call_service,
  event_fired), 4 default Jinja templates (en + ru), HA-specific
  tracker filters (entity_glob, domain_allowlist, exact entity ids)
- Extracted shared dispatch pipeline (api/webhooks.py → services/
  event_dispatch.py) so subscription and webhook ingest share the same
  event_log + deferred-dispatch + quiet-hours code path

Bot commands:
- /status, /entities [glob], /state <entity_id>, /areas
- Multi-command WS session so /status and /areas cost one handshake
- Sensitive-attribute blocklist (camera access_token, entity_picture, etc.)
  and 30-attribute cap to keep /state output safe and within Telegram's
  message size
- Error-message redaction strips URL userinfo before surfacing to chat

Frontend:
- HA descriptor with toggle ConfigField type (new) and tag-input filter
  mode for free-text glob/domain lists (new TagInput component)
- 15 command slots + 4 notification slots wired into the existing
  template-config UI
2026-05-13 14:31:56 +03:00

7.9 KiB

Feature Backlog

Curated feature ideas, narrowed from a brainstorming pass on 2026-05-13. Order is rough sequencing preference, not strict priority — adjust as we go.


1. Quiet Hours — close the gaps in the existing system

Reality check (verified 2026-05-13). Quiet hours are already shipped under the "deferred dispatch" name in v0.8.0. The pipeline lives at packages/server/src/notify_bridge_server/services/deferred_dispatch.py with helpers in dispatch_helpers.py and tests in tests/test_deferred_dispatch.py. What exists:

  • Per-tracking-config window: tracking_config.quiet_hours_enabled, quiet_hours_start, quiet_hours_end.
  • Per-link override: notification_tracker_target.quiet_hours_start, quiet_hours_end.
  • Smart coalescing (asset add + asset remove during a window cancels each other out, set-union merge for repeated adds).
  • Post-window drain via APScheduler one-shot date jobs.
  • Wall-clock event types (scheduled_message) drop instead of deferring.
  • Frontend status surface: deferred, deferred_then_dropped, deferred_then_failed, with deferred_until and deferred_for_seconds fields exposed in the event log.

What's NOT there (the actual gaps):

Gap Sketch
Target-level windows Today, hours bind to the watcher (tracking config / link). Users naturally think of DND at the destination ("don't ping my phone at night, regardless of source"). New column on notification_target + dispatcher gate.
Multiple windows per row Today is a single HH:MM range. Real schedules want weekday-evening + weekend-all-day. JSON list of windows.
Days-of-week Same window every day. Need days: ["mon", "tue", ...] filter per window.
Per-window timezone Uses the global app TZ. Multi-traveller / multi-target setups want per-window TZ.
Silent mode Modes today are defer-or-drop. Telegram disable_notification=true ("send but don't ring") is a third useful mode.
Per-receiver windows One bot → multiple chats, each potentially with its own DND. Today it's all-or-nothing per target.

Recommended cut for v1 of "extend quiet hours":

  • Add target-level quiet hours (new column notification_target.quiet_hours_json = list of {days, start, end, mode, tz}).
  • Modes: drop, defer, silent. defer reuses the existing deferred-dispatch pipeline (just changes who decides). silent maps to disable_notification=true for Telegram; other targets fall through to normal send (or we treat silent as defer for non-Telegram targets — TBD).
  • Dispatcher precedence: target window wins over link/tracking-config window when both are configured. Document this explicitly.
  • Frontend: new "Quiet hours" fieldset in the target editor (Aurora cassette style). Reuses Timezone picker; new day-picker chip row.
  • Skip days-of-week + multi-window in v1 if scope grows — ship the target-level cut first, then iterate.

Open questions.

  • How exactly do target / link / tracking-config windows combine? Proposal: any window covering "now" wins (drop > defer > silent precedence).
  • Should silent for non-Telegram targets degrade to normal send or to defer? Defer is the safer default.
  • Does the event log need a new status (silenced / dropped_by_target_qh) to make precedence visible?

2. Immich Smart Actions (expand beyond Auto-Organize)

What. Extend the existing Smart Actions pattern (currently: Immich Auto-Organize) with more rule-driven actions against the Immich API.

Why. Auto-Organize already proves the descriptor → rule editor → executor pipeline. Adding actions is mostly authoring new executors + small UI rule shapes, not new infra.

Candidates (pick in this order).

  1. Auto-favorite by person — when an asset is detected containing person X (or any of a set), mark it favorite.
  2. Auto-archive by age / album — assets older than N days in a given album get archived. Pair with a "dry-run shows count" UX like Auto-Organize already has.
  3. Duplicate cluster nudge — periodically run Immich's duplicate API and send a digest notification with inline buttons ("review", "ignore for 30d"). Depends on inline-button work (see backlog item 4 dependencies).
  4. Share-link rotation — for an album, regenerate the share link every N days; notify with the new URL.
  5. Pending-delete review — push a weekly digest of trash contents before Immich's auto-purge fires.

Shape.

  • Reuse the existing action descriptor layer (packages/core/src/notify_bridge_core/providers/actions.py, action_executor.py) and the frontend rule editor used by Auto-Organize.
  • Each new action = (a) executor in core, (b) rule schema in the descriptor, (c) frontend descriptor extension for the rule editor fields.
  • Persist as provider_actions rows (already exists for Auto-Organize) with a discriminator + JSON config.

Open questions.

  • Does "auto-favorite by person" need a confirmation queue or run silently? Default to silent + event_log entry.
  • How do we surface "this action moved/changed X assets" in the dashboard? Probably a per-action stat tile on the provider detail page.

3. Home Assistant Provider

Full plan: feature-home-assistant.md.

One-line summary. New WebSocket-based service provider with a 3-phase ship: subscribe + dispatch (Phase 1), bot commands (Phase 2), HA service calls as Smart Actions (Phase 3). Chosen over webhook ingest because Phases 2 + 3 force a long-lived API connection anyway; consolidating on WS avoids a refactor.

Status: planned, not started.


4. Block-Based Template Builder

What. A visual, drag-and-drop builder for notification and command templates that compiles down to Jinja2. Lives alongside (not instead of) the current JinjaEditor. Author can flip between views.

Why. The current Jinja editor is powerful but unforgiving. A block UI lowers the floor for new users and provides a discovery surface for the variables documented in template_configs.py.

Shape.

  • Frontend-only feature for v1 — compiles to the same Jinja strings the backend already accepts.
  • Blocks: Text, Variable, If, For, Link, Image, Icon, Caption, Group (HTML span/group). Each block knows its serialized Jinja representation.
  • Round-trip: variables, simple {% if %} / {% for %} blocks, and string literals parse back to blocks; arbitrary Jinja stays in a "Raw" block that the user can edit as text.
  • Variable picker reads get_template_variables(provider_type, slot). This is the same data already shown in the template-help panel.
  • Preview pane unchanged — reuses services/sample_context.py server rendering.
  • Toggle in the template editor: Visual / Code.

Open questions.

  • Round-tripping arbitrary Jinja is hard. v1: parseable subset → blocks, anything else → single Raw block. Show a banner explaining.
  • Locale handling: same compiled Jinja, just authored per locale tab.
  • Do we want a marketplace of pre-built block compositions? Out of scope for v1 — bundle import/export is a separate backlog item.

  1. Quiet Hours per Target — small, isolated, immediate user value.
  2. Immich Smart Actions — incremental on existing pattern; ship one action at a time (start with auto-favorite by person).
  3. Home Assistant Provider — multi-file, follows new-provider checklist; biggest user-base expansion.
  4. Block-Based Template Builder — largest frontend lift; benefits from the variable-doc work that the other features will exercise.

Dependencies are loose — 1 and 2 are independent of 3 and 4. The block builder pairs nicely with Home Assistant because HA's rich context surfaces the value of an easier authoring UX.


Decision log

  • 2026-05-13 — Backlog seeded with these four items selected from a broader brainstorm. Not started.