"""Number settings of a ninlight lamp: fades, transition and sACN addressing.""" from __future__ import annotations 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 .coordinator import NinlightConfigEntry, NinlightCoordinator from .entity import NinlightEntity, NinlightSacnEntity PARALLEL_UPDATES = 0 @dataclass(frozen=True, kw_only=True) class NinlightNumberDescription(NumberEntityDescription): """A millisecond setting stored under `key` in the lamp 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 NUMBERS = ( NinlightNumberDescription(key="fade_in", translation_key="fade_in", native_max_value=10_000), NinlightNumberDescription(key="fade_out", translation_key="fade_out", native_max_value=10_000), NinlightNumberDescription( key="transition_default", translation_key="transition_default", native_max_value=60_000 ), ) async def async_setup_entry( hass: HomeAssistant, entry: NinlightConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: entities: list[NumberEntity] = [ NinlightNumber(entry.runtime_data, description) for description in NUMBERS ] entities.append(NinlightSacnUniverse(entry.runtime_data)) entities.append(NinlightSacnStartSlot(entry.runtime_data)) async_add_entities(entities) class NinlightNumber(NinlightEntity, NumberEntity): """One millisecond setting.""" entity_description: NinlightNumberDescription def __init__( self, coordinator: NinlightCoordinator, description: NinlightNumberDescription ) -> None: super().__init__(coordinator, description.key) self.entity_description = description @property def native_value(self) -> int | None: value = self.coordinator.data.state.get(self.entity_description.key) return int(value) if value is not None 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 NinlightSacnUniverse(NinlightSacnEntity, NumberEntity): """The DMX universe the lamp listens on.""" _attr_entity_category = EntityCategory.CONFIG _attr_translation_key = "sacn_universe" _attr_native_min_value = 1 _attr_native_max_value = 63_999 _attr_native_step = 1 _attr_mode = NumberMode.BOX def __init__(self, coordinator: NinlightCoordinator) -> None: super().__init__(coordinator, "sacn_universe") @property def native_value(self) -> float | None: value = self.sacn.get("universe") return float(value) if isinstance(value, (int, float)) else None async def async_set_native_value(self, value: float) -> None: await self.coordinator.async_set_sacn(universe=int(value)) class NinlightSacnStartSlot(NinlightSacnEntity, NumberEntity): """The first slot of the lamp inside its universe.""" _attr_entity_category = EntityCategory.CONFIG _attr_translation_key = "sacn_start_slot" _attr_native_min_value = 1 _attr_native_step = 1 _attr_mode = NumberMode.BOX def __init__(self, coordinator: NinlightCoordinator) -> None: super().__init__(coordinator, "sacn_start_slot") @property def native_max_value(self) -> float: """The highest start slot that still leaves room for all of the lamp's slots. The lamp reports how many it needs, and that number depends on both the board and the slot layout - a fixed 512 here would offer settings the lamp then rejects. """ slots = self.sacn.get("slots") if not isinstance(slots, int) or not 1 <= slots <= 512: return 512 return 512 - slots + 1 @property def native_value(self) -> float | None: value = self.sacn.get("start_slot") return float(value) if isinstance(value, (int, float)) else None async def async_set_native_value(self, value: float) -> None: await self.coordinator.async_set_sacn(start_slot=int(value))