"""Support for LaMetric numbers.""" from __future__ import annotations from collections.abc import Awaitable, Callable from dataclasses import dataclass from typing import Any from demetriek import Device, LaMetricDevice, Range from homeassistant.components.number import NumberEntity, NumberEntityDescription from homeassistant.const import PERCENTAGE, EntityCategory from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback from .coordinator import LaMetricConfigEntry, LaMetricDataUpdateCoordinator from .entity import LaMetricEntity from .helpers import lametric_exception_handler @dataclass(frozen=True, kw_only=True) class LaMetricNumberEntityDescription(NumberEntityDescription): """Class describing LaMetric number entities.""" value_fn: Callable[[Device], int | None] range_fn: Callable[[Device], Range | None] has_fn: Callable[[Device], bool] = lambda device: True set_value_fn: Callable[[LaMetricDevice, float], Awaitable[Any]] NUMBERS = [ LaMetricNumberEntityDescription( key="brightness", translation_key="brightness", entity_category=EntityCategory.CONFIG, native_step=1, range_fn=lambda device: device.display.brightness_limit, native_unit_of_measurement=PERCENTAGE, value_fn=lambda device: device.display.brightness, set_value_fn=lambda device, bri: device.display(brightness=int(bri)), ), LaMetricNumberEntityDescription( key="volume", translation_key="volume", entity_category=EntityCategory.CONFIG, native_step=1, range_fn=lambda device: device.audio.volume_range if device.audio else None, native_unit_of_measurement=PERCENTAGE, has_fn=lambda device: bool(device.audio and device.audio.available), value_fn=lambda device: device.audio.volume if device.audio else 0, set_value_fn=lambda api, volume: api.audio(volume=int(volume)), ), ] async def async_setup_entry( hass: HomeAssistant, entry: LaMetricConfigEntry, async_add_entities: AddConfigEntryEntitiesCallback, ) -> None: """Set up LaMetric number based on a config entry.""" coordinator = entry.runtime_data async_add_entities( LaMetricNumberEntity( coordinator=coordinator, description=description, ) for description in NUMBERS ) class LaMetricNumberEntity(LaMetricEntity, NumberEntity): """Representation of a LaMetric number.""" entity_description: LaMetricNumberEntityDescription def __init__( self, coordinator: LaMetricDataUpdateCoordinator, description: LaMetricNumberEntityDescription, ) -> None: """Initiate LaMetric Number.""" super().__init__(coordinator) self.entity_description = description self._attr_unique_id = f"{coordinator.data.serial_number}-{description.key}" @property def native_value(self) -> int | None: """Return the number value.""" return self.entity_description.value_fn(self.coordinator.data) @property def native_min_value(self) -> int: """Return the min range.""" if limits := self.entity_description.range_fn(self.coordinator.data): return limits.range_min return 0 @property def native_max_value(self) -> int: """Return the max range.""" if limits := self.entity_description.range_fn(self.coordinator.data): return limits.range_max return 100 @lametric_exception_handler async def async_set_native_value(self, value: float) -> None: """Change to new number value.""" await self.entity_description.set_value_fn(self.coordinator.lametric, value) await self.coordinator.async_request_refresh()