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:
@@ -21,7 +21,9 @@ from wled_controller.storage.value_source_store import ValueSourceStore
|
||||
from wled_controller.storage.automation_store import AutomationStore
|
||||
from wled_controller.storage.scene_preset_store import ScenePresetStore
|
||||
from wled_controller.storage.sync_clock_store import SyncClockStore
|
||||
from wled_controller.storage.color_strip_processing_template_store import ColorStripProcessingTemplateStore
|
||||
from wled_controller.storage.color_strip_processing_template_store import (
|
||||
ColorStripProcessingTemplateStore,
|
||||
)
|
||||
from wled_controller.storage.gradient_store import GradientStore
|
||||
from wled_controller.storage.weather_source_store import WeatherSourceStore
|
||||
from wled_controller.storage.asset_store import AssetStore
|
||||
@@ -30,6 +32,8 @@ from wled_controller.core.weather.weather_manager import WeatherManager
|
||||
from wled_controller.core.backup.auto_backup import AutoBackupEngine
|
||||
from wled_controller.core.processing.sync_clock_manager import SyncClockManager
|
||||
from wled_controller.core.update.update_service import UpdateService
|
||||
from wled_controller.storage.home_assistant_store import HomeAssistantStore
|
||||
from wled_controller.core.home_assistant.ha_manager import HomeAssistantManager
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
@@ -136,6 +140,14 @@ def get_asset_store() -> AssetStore:
|
||||
return _get("asset_store", "Asset store")
|
||||
|
||||
|
||||
def get_ha_store() -> HomeAssistantStore:
|
||||
return _get("ha_store", "Home Assistant store")
|
||||
|
||||
|
||||
def get_ha_manager() -> HomeAssistantManager:
|
||||
return _get("ha_manager", "Home Assistant manager")
|
||||
|
||||
|
||||
def get_database() -> Database:
|
||||
return _get("database", "Database")
|
||||
|
||||
@@ -157,12 +169,14 @@ def fire_entity_event(entity_type: str, action: str, entity_id: str) -> None:
|
||||
"""
|
||||
pm = _deps.get("processor_manager")
|
||||
if pm is not None:
|
||||
pm.fire_event({
|
||||
"type": "entity_changed",
|
||||
"entity_type": entity_type,
|
||||
"action": action,
|
||||
"id": entity_id,
|
||||
})
|
||||
pm.fire_event(
|
||||
{
|
||||
"type": "entity_changed",
|
||||
"entity_type": entity_type,
|
||||
"action": action,
|
||||
"id": entity_id,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
# ── Initialization ──────────────────────────────────────────────────────
|
||||
@@ -193,31 +207,37 @@ def init_dependencies(
|
||||
weather_manager: WeatherManager | None = None,
|
||||
update_service: UpdateService | None = None,
|
||||
asset_store: AssetStore | None = None,
|
||||
ha_store: HomeAssistantStore | None = None,
|
||||
ha_manager: HomeAssistantManager | None = None,
|
||||
):
|
||||
"""Initialize global dependencies."""
|
||||
_deps.update({
|
||||
"database": database,
|
||||
"device_store": device_store,
|
||||
"template_store": template_store,
|
||||
"processor_manager": processor_manager,
|
||||
"pp_template_store": pp_template_store,
|
||||
"pattern_template_store": pattern_template_store,
|
||||
"picture_source_store": picture_source_store,
|
||||
"output_target_store": output_target_store,
|
||||
"color_strip_store": color_strip_store,
|
||||
"audio_source_store": audio_source_store,
|
||||
"audio_template_store": audio_template_store,
|
||||
"value_source_store": value_source_store,
|
||||
"automation_store": automation_store,
|
||||
"scene_preset_store": scene_preset_store,
|
||||
"automation_engine": automation_engine,
|
||||
"auto_backup_engine": auto_backup_engine,
|
||||
"sync_clock_store": sync_clock_store,
|
||||
"sync_clock_manager": sync_clock_manager,
|
||||
"cspt_store": cspt_store,
|
||||
"gradient_store": gradient_store,
|
||||
"weather_source_store": weather_source_store,
|
||||
"weather_manager": weather_manager,
|
||||
"update_service": update_service,
|
||||
"asset_store": asset_store,
|
||||
})
|
||||
_deps.update(
|
||||
{
|
||||
"database": database,
|
||||
"device_store": device_store,
|
||||
"template_store": template_store,
|
||||
"processor_manager": processor_manager,
|
||||
"pp_template_store": pp_template_store,
|
||||
"pattern_template_store": pattern_template_store,
|
||||
"picture_source_store": picture_source_store,
|
||||
"output_target_store": output_target_store,
|
||||
"color_strip_store": color_strip_store,
|
||||
"audio_source_store": audio_source_store,
|
||||
"audio_template_store": audio_template_store,
|
||||
"value_source_store": value_source_store,
|
||||
"automation_store": automation_store,
|
||||
"scene_preset_store": scene_preset_store,
|
||||
"automation_engine": automation_engine,
|
||||
"auto_backup_engine": auto_backup_engine,
|
||||
"sync_clock_store": sync_clock_store,
|
||||
"sync_clock_manager": sync_clock_manager,
|
||||
"cspt_store": cspt_store,
|
||||
"gradient_store": gradient_store,
|
||||
"weather_source_store": weather_source_store,
|
||||
"weather_manager": weather_manager,
|
||||
"update_service": update_service,
|
||||
"asset_store": asset_store,
|
||||
"ha_store": ha_store,
|
||||
"ha_manager": ha_manager,
|
||||
}
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user