core/homeassistant/components/lametric/number.py

111 lines
3.8 KiB
Python

"""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()