Files
wled-screen-controller-mixed/custom_components/wled_screen_controller/__init__.py
alexei.dolgolyov 67da014684 Rewrite HAOS integration: target-centric architecture with KC color sensors
- Rewrite integration to target-centric model: each picture target becomes
  a HA device under a server hub with switch, FPS, and status sensors
- Replace KC light entities with color sensors (hex state + RGB attributes)
  for better automation support via WebSocket real-time updates
- Add WebSocket manager for Key Colors color streaming
- Add KC per-stage timing metrics (calc_colors, broadcast) with rolling avg
- Fix KC timing fields missing from API by adding them to Pydantic schema
- Make start/stop processing idempotent to prevent intermittent 404 errors
- Add HAOS localization support (en, ru) using translation_key system
- Rename integration from "WLED Screen Controller" to "LED Screen Controller"
- Remove obsolete select.py (display select) and README.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 13:01:40 +03:00

128 lines
4.1 KiB
Python

"""The LED Screen Controller integration."""
from __future__ import annotations
import logging
from datetime import timedelta
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import device_registry as dr
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from .const import (
DOMAIN,
CONF_SERVER_URL,
CONF_API_KEY,
DEFAULT_SCAN_INTERVAL,
TARGET_TYPE_KEY_COLORS,
DATA_COORDINATOR,
DATA_WS_MANAGER,
)
from .coordinator import WLEDScreenControllerCoordinator
from .ws_manager import KeyColorsWebSocketManager
_LOGGER = logging.getLogger(__name__)
PLATFORMS: list[Platform] = [
Platform.SWITCH,
Platform.SENSOR,
]
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up LED Screen Controller from a config entry."""
server_url = entry.data[CONF_SERVER_URL]
api_key = entry.data[CONF_API_KEY]
session = async_get_clientsession(hass)
coordinator = WLEDScreenControllerCoordinator(
hass,
session,
server_url,
api_key,
update_interval=timedelta(seconds=DEFAULT_SCAN_INTERVAL),
)
await coordinator.async_config_entry_first_refresh()
ws_manager = KeyColorsWebSocketManager(hass, server_url, api_key)
# Create device entries for each target
device_registry = dr.async_get(hass)
if coordinator.data and "targets" in coordinator.data:
for target_id, target_data in coordinator.data["targets"].items():
info = target_data["info"]
target_type = info.get("target_type", "led")
model = (
"Key Colors Target"
if target_type == TARGET_TYPE_KEY_COLORS
else "LED Target"
)
device_registry.async_get_or_create(
config_entry_id=entry.entry_id,
identifiers={(DOMAIN, target_id)},
name=info.get("name", target_id),
manufacturer="LED Screen Controller",
model=model,
configuration_url=server_url,
)
# Store data
hass.data.setdefault(DOMAIN, {})
hass.data[DOMAIN][entry.entry_id] = {
DATA_COORDINATOR: coordinator,
DATA_WS_MANAGER: ws_manager,
}
# Track target IDs to detect changes
initial_target_ids = set(
coordinator.data.get("targets", {}).keys() if coordinator.data else []
)
def _on_coordinator_update() -> None:
"""Manage WS connections and detect target list changes."""
if not coordinator.data:
return
targets = coordinator.data.get("targets", {})
# Start/stop WS connections for KC targets based on processing state
for target_id, target_data in targets.items():
info = target_data.get("info", {})
state = target_data.get("state") or {}
if info.get("target_type") == TARGET_TYPE_KEY_COLORS:
if state.get("processing"):
hass.async_create_task(ws_manager.start_listening(target_id))
else:
hass.async_create_task(ws_manager.stop_listening(target_id))
# Reload if target list changed
current_ids = set(targets.keys())
if current_ids != initial_target_ids:
_LOGGER.info("Target list changed, reloading integration")
hass.async_create_task(
hass.config_entries.async_reload(entry.entry_id)
)
coordinator.async_add_listener(_on_coordinator_update)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
ws_manager: KeyColorsWebSocketManager = hass.data[DOMAIN][entry.entry_id][
DATA_WS_MANAGER
]
await ws_manager.shutdown()
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok:
hass.data[DOMAIN].pop(entry.entry_id)
return unload_ok