Files
notify-bridge/packages/server/src/notify_bridge_server/commands/registry.py
T
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

29 lines
994 B
Python

"""Command definitions — categories, rate limit grouping, and defaults."""
from __future__ import annotations
# Map commands to rate limit categories
_RATE_CATEGORY: dict[str, str] = {
# Immich
"search": "search", "find": "search", "person": "search",
"place": "search", "favorites": "search", "people": "search",
# Gitea (API calls share a category)
"repos": "api", "issues": "api", "prs": "api", "commits": "api",
# Planka (API calls share a category)
"boards": "api", "cards": "api", "lists": "api",
# Home Assistant (WebSocket queries share a category)
"entities": "api", "state": "api", "areas": "api",
}
def get_rate_category(cmd: str) -> str:
return _RATE_CATEGORY.get(cmd, "default")
DEFAULT_COMMANDS_CONFIG = {
"enabled": ["help", "status", "albums", "events", "latest", "random", "favorites", "summary", "memory"],
"response_mode": "media",
"default_count": 5,
"rate_limits": {"search": 30, "api": 15, "default": 10},
}