feat: Home Assistant integration — WebSocket connection, automation conditions, UI

Add full Home Assistant integration via WebSocket API:
- HARuntime: persistent WebSocket client with auth, auto-reconnect, entity state cache
- HAManager: ref-counted runtime pool (like WeatherManager)
- HomeAssistantCondition: new automation trigger type matching entity states
- REST API: CRUD for HA sources + /test, /entities, /status endpoints
- /api/v1/system/integrations-status: combined MQTT + HA dashboard indicators
- Frontend: HA Sources tab in Streams, condition type in automation editor
- Modal editor with host, token, SSL, entity filters
- websockets>=13.0 dependency added
This commit is contained in:
2026-03-27 22:42:48 +03:00
parent f3d07fc47f
commit 2153dde4b7
26 changed files with 1912 additions and 119 deletions
@@ -1784,6 +1784,43 @@
"weather_source.geo.error": "Geolocation failed",
"weather_source.geo.not_supported": "Geolocation is not supported by your browser",
"streams.group.weather": "Weather",
"streams.group.home_assistant": "Home Assistant",
"ha_source.group.title": "Home Assistant Sources",
"ha_source.add": "Add Home Assistant Source",
"ha_source.edit": "Edit Home Assistant Source",
"ha_source.name": "Name:",
"ha_source.name.placeholder": "My Home Assistant",
"ha_source.name.hint": "A descriptive name for this Home Assistant connection",
"ha_source.host": "Host:",
"ha_source.host.hint": "Home Assistant host and port, e.g. 192.168.1.100:8123",
"ha_source.token": "Access Token:",
"ha_source.token.hint": "Long-Lived Access Token from HA (Profile > Security > Long-Lived Access Tokens)",
"ha_source.token.edit_hint": "Leave blank to keep the current token",
"ha_source.use_ssl": "Use SSL (wss://)",
"ha_source.entity_filters": "Entity Filters (optional):",
"ha_source.entity_filters.hint": "Comma-separated glob patterns, e.g. sensor.*, binary_sensor.front_door. Leave empty for all.",
"ha_source.description": "Description (optional):",
"ha_source.test": "Test Connection",
"ha_source.test.success": "Connected",
"ha_source.test.failed": "Connection failed",
"ha_source.connected": "Connected",
"ha_source.disconnected": "Disconnected",
"ha_source.error.name_required": "Name is required",
"ha_source.error.host_required": "Host is required",
"ha_source.error.token_required": "Access token is required",
"ha_source.error.load": "Failed to load Home Assistant source",
"ha_source.created": "Home Assistant source created",
"ha_source.updated": "Home Assistant source updated",
"ha_source.deleted": "Home Assistant source deleted",
"ha_source.delete.confirm": "Delete this Home Assistant connection?",
"section.empty.ha_sources": "No Home Assistant sources yet. Click + to add one.",
"automations.condition.home_assistant": "Home Assistant",
"automations.condition.home_assistant.desc": "HA entity state",
"automations.condition.home_assistant.ha_source": "HA Source:",
"automations.condition.home_assistant.entity_id": "Entity ID:",
"automations.condition.home_assistant.state": "State:",
"automations.condition.home_assistant.match_mode": "Match Mode:",
"automations.condition.home_assistant.hint": "Activate when a Home Assistant entity matches the specified state",
"color_strip.clock": "Sync Clock:",
"color_strip.clock.hint": "Link to a sync clock to synchronize animation timing across sources. Speed is controlled on the clock.",
"graph.title": "Graph",