"""Hauptschalter, Helligkeit und Farbe eines ninstrip. Bewusst eine Entitaet je Geraet, nicht je Segment: device/state ist der Hauptschalter. Farbe und Farbtemperatur stehen dagegen NICHT dort, sondern je Segment - die Entitaet schreibt sie deshalb in alle Segmente zugleich und laesst deren Grenzen und Namen stehen. Einzelne Segmententitaeten koennen spaeter dazukommen. """ from __future__ import annotations from typing import Any from homeassistant.components.light import ( ATTR_BRIGHTNESS, ATTR_COLOR_TEMP_KELVIN, ATTR_RGB_COLOR, ColorMode, LightEntity, ) from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from .coordinator import NinstripConfigEntry, NinstripCoordinator from .entity import NinstripEntity # Die Firmware rechnet Farbtemperaturen ausserhalb dieser Spanne nicht auf die # Weisskanaele um (nl_ct.h). Strips ohne Weisskanaele bekommen dieselbe Spanne # als RGB-Naeherung, damit "warmweiss" auf jedem Chip leuchtet. MIN_KELVIN = 2700 MAX_KELVIN = 6500 async def async_setup_entry( hass: HomeAssistant, entry: NinstripConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: async_add_entities([NinstripLight(entry.runtime_data)]) class NinstripLight(NinstripEntity, LightEntity): """Der Strip als Ganzes.""" _attr_name = None _attr_supported_color_modes = {ColorMode.RGB, ColorMode.COLOR_TEMP} _attr_min_color_temp_kelvin = MIN_KELVIN _attr_max_color_temp_kelvin = MAX_KELVIN def __init__(self, coordinator: NinstripCoordinator) -> None: super().__init__(coordinator, "light") # --- Zustand ------------------------------------------------------- def _segments(self) -> list[dict[str, Any]]: return self.coordinator.data.segments.get("segments") or [] def _einig(self, feld: str) -> Any: """Der Wert, wenn alle Segmente sich einig sind - sonst None. Ein Strip kann segmentweise verschiedene Farben zeigen. Home Assistant kennt nur eine je Entitaet; in dem Fall waere jede Angabe gelogen, also gibt es keine. """ segmente = self._segments() if not segmente: return None werte = [seg.get(feld) for seg in segmente] return werte[0] if all(w == werte[0] and w is not None for w in werte) else None @property def is_on(self) -> bool: return bool(self.coordinator.data.state.get("on")) @property def brightness(self) -> int | None: """Das Geraet rechnet in Prozent, Home Assistant in 0..255.""" value = self.coordinator.data.state.get("brightness") if value is None: return None return round(max(0, min(100, int(value))) * 255 / 100) @property def color_mode(self) -> ColorMode: """Weiss nur, wenn sich alle Segmente auf 'white' einigen. Sonst RGB: ein Strip mit Effekten oder gemischten Segmenten hat keine eine Farbtemperatur, und HA wuerde den Farbkreis sonst ausblenden. """ return ColorMode.COLOR_TEMP if self._einig("mode") == "white" else ColorMode.RGB @property def rgb_color(self) -> tuple[int, int, int] | None: farbe = self._einig("color") if not isinstance(farbe, dict): return None try: return (int(farbe["r"]), int(farbe["g"]), int(farbe["b"])) except KeyError, TypeError, ValueError: return None @property def color_temp_kelvin(self) -> int | None: wert = self._einig("color_temp") return int(wert) if isinstance(wert, (int, float)) else None @property def extra_state_attributes(self) -> dict[str, Any]: state = self.coordinator.data.state return { "segment_count": state.get("segment_count"), "pixel_count": state.get("pixel_count"), "preset": state.get("preset"), "preset_modified": state.get("preset_modified"), } # --- Schalten ------------------------------------------------------ async def async_turn_on(self, **kwargs: Any) -> None: # Erst die Farbe in die Segmente, dann der Hauptschalter: so leuchtet # nichts kurz in der alten Farbe auf. if ATTR_RGB_COLOR in kwargs: r, g, b = kwargs[ATTR_RGB_COLOR] await self.coordinator.async_set_all_segments( mode="solid", color={"r": int(r), "g": int(g), "b": int(b)} ) elif ATTR_COLOR_TEMP_KELVIN in kwargs: kelvin = max(MIN_KELVIN, min(MAX_KELVIN, int(kwargs[ATTR_COLOR_TEMP_KELVIN]))) await self.coordinator.async_set_all_segments(mode="white", color_temp=kelvin) fields: dict[str, Any] = {"on": True} if ATTR_BRIGHTNESS in kwargs: fields["brightness"] = round(int(kwargs[ATTR_BRIGHTNESS]) * 100 / 255) await self.coordinator.async_set_state(**fields) async def async_turn_off(self, **kwargs: Any) -> None: await self.coordinator.async_set_state(on=False)