feat: nachgezogen, was ha-ninlight laengst hat
Michaels Befund: die Integration ist nicht dasselbe wie die von ninlight. Verglichen und die Luecken geschlossen - alle Felder gibt es in der Firmware schon, sie waren nur nicht bedienbar: * number: fade_in, fade_out, transition_default in Millisekunden, mit den Grenzen der Firmware (10 s, 10 s, 60 s). * select: Einschaltverhalten (last, on, off). * switch: bei Aenderung einschalten. * light: Uebergangszeit beim Ein- und Ausschalten. HA rechnet in Sekunden, das Geraet in Millisekunden; laengeres als 60 s wird gekappt, sonst wiese das Geraet die ganze Anfrage mit 400 ab. Ohne Angabe wird kein Feld geschickt, sonst ueberschriebe jeder Schaltbefehl die Vorgabe. * sensor: letzter Update-Fehler und Startzeit (Zeitstempel statt einer Laufzeit, die jede Abfrage weiterlaeuft), beide ab Werk aus. * diagnostics.py: Diagnosedaten zum Herunterladen, ohne Token, Adressen, MAC und SSID. * config_flow: Neu-Konfigurieren von Adresse und Token, mit Gegenprobe der MAC - ein Tippfehler in der Adresse soll nicht still den falschen Eintrag umbiegen. * Hinweis in den Reparaturen, wenn ein Geraet noch auf dem oeffentlichen Werks-Token steht. Nicht uebernommen: die Auswahl sacn_layout. ninstrip ist immer rgb, ein Strip hat keinen Masterkanal - eine Auswahl mit einer Option waere nur Zierde. 241 Tests, 97 %. Die Kappung der Uebergangszeit per Mutation gegengeprueft.
This commit is contained in:
@@ -1,14 +1,22 @@
|
||||
"""sACN-Zahlenfelder eines ninstrip-Geraets: Universe und Startslot."""
|
||||
"""Zahlenfelder eines ninstrip-Geraets: Uebergangszeiten und sACN."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from homeassistant.components.number import NumberEntity, NumberMode
|
||||
from homeassistant.const import EntityCategory
|
||||
from dataclasses import dataclass
|
||||
|
||||
from homeassistant.components.number import (
|
||||
NumberDeviceClass,
|
||||
NumberEntity,
|
||||
NumberEntityDescription,
|
||||
NumberMode,
|
||||
)
|
||||
from homeassistant.const import EntityCategory, UnitOfTime
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
|
||||
|
||||
from .const import MAX_FADE_MS, MAX_TRANSITION_MS
|
||||
from .coordinator import NinstripConfigEntry, NinstripCoordinator
|
||||
from .entity import NinstripSacnEntity
|
||||
from .entity import NinstripEntity, NinstripSacnEntity
|
||||
|
||||
PARALLEL_UPDATES = 0
|
||||
|
||||
@@ -17,13 +25,62 @@ PARALLEL_UPDATES = 0
|
||||
_KANAELE_VORGABE = 3
|
||||
|
||||
|
||||
@dataclass(frozen=True, kw_only=True)
|
||||
class NinstripZeitDescription(NumberEntityDescription):
|
||||
"""Ein Millisekundenfeld aus device/state."""
|
||||
|
||||
entity_category: EntityCategory = EntityCategory.CONFIG
|
||||
device_class: NumberDeviceClass = NumberDeviceClass.DURATION
|
||||
native_unit_of_measurement: str = UnitOfTime.MILLISECONDS
|
||||
native_min_value: float = 0
|
||||
native_step: float = 50
|
||||
mode: NumberMode = NumberMode.BOX
|
||||
|
||||
|
||||
# Grenzen wie in der Firmware (nl_api_device.c). Feldnamen wie in ninlight.
|
||||
ZEITEN = (
|
||||
NinstripZeitDescription(key="fade_in", translation_key="fade_in", native_max_value=MAX_FADE_MS),
|
||||
NinstripZeitDescription(
|
||||
key="fade_out", translation_key="fade_out", native_max_value=MAX_FADE_MS
|
||||
),
|
||||
NinstripZeitDescription(
|
||||
key="transition_default",
|
||||
translation_key="transition_default",
|
||||
native_max_value=MAX_TRANSITION_MS,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
async def async_setup_entry(
|
||||
hass: HomeAssistant,
|
||||
entry: NinstripConfigEntry,
|
||||
async_add_entities: AddConfigEntryEntitiesCallback,
|
||||
) -> None:
|
||||
coordinator = entry.runtime_data
|
||||
async_add_entities([NinstripSacnUniverse(coordinator), NinstripSacnStartSlot(coordinator)])
|
||||
entitaeten: list[NumberEntity] = [NinstripZeit(coordinator, d) for d in ZEITEN]
|
||||
entitaeten.append(NinstripSacnUniverse(coordinator))
|
||||
entitaeten.append(NinstripSacnStartSlot(coordinator))
|
||||
async_add_entities(entitaeten)
|
||||
|
||||
|
||||
class NinstripZeit(NinstripEntity, NumberEntity):
|
||||
"""Ein Millisekundenfeld: Einblenden, Ausblenden, Vorgabe fuer Uebergaenge."""
|
||||
|
||||
entity_description: NinstripZeitDescription
|
||||
|
||||
def __init__(
|
||||
self, coordinator: NinstripCoordinator, description: NinstripZeitDescription
|
||||
) -> None:
|
||||
super().__init__(coordinator, description.key)
|
||||
self.entity_description = description
|
||||
|
||||
@property
|
||||
def native_value(self) -> float | None:
|
||||
wert = self.coordinator.data.state.get(self.entity_description.key)
|
||||
return float(wert) if isinstance(wert, (int, float)) else None
|
||||
|
||||
async def async_set_native_value(self, value: float) -> None:
|
||||
await self.coordinator.async_set_state(**{self.entity_description.key: int(value)})
|
||||
|
||||
|
||||
class NinstripSacnUniverse(NinstripSacnEntity, NumberEntity):
|
||||
|
||||
Reference in New Issue
Block a user