homeassistant-config/custom_components/hochwasserportal/sensor.py

149 lines
4.7 KiB
Python

"""Platform for sensor integration."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from lhpapi import HochwasserPortalAPI
from homeassistant.components.sensor import (
SensorEntity,
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import UnitOfLength
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.update_coordinator import CoordinatorEntity
from .const import (
ATTR_DATA_PROVIDERS,
ATTR_HINT,
ATTR_LAST_UPDATE,
ATTR_URL,
CONF_ADD_UNAVAILABLE,
DOMAIN,
FLOW_SENSOR,
LEVEL_SENSOR,
LOGGER,
STAGE_SENSOR,
)
from .coordinator import HochwasserPortalCoordinator
@dataclass(frozen=True, kw_only=True)
class HochwasserPortalSensorEntityDescription(SensorEntityDescription):
"""Describes HochwasserPortal sensor entity."""
value_fn: Callable[[HochwasserPortalAPI], int | float | None]
available_fn: Callable[[HochwasserPortalAPI], bool]
SENSOR_TYPES: tuple[HochwasserPortalSensorEntityDescription, ...] = (
HochwasserPortalSensorEntityDescription(
key=LEVEL_SENSOR,
translation_key=LEVEL_SENSOR,
icon="mdi:waves",
native_unit_of_measurement=UnitOfLength.CENTIMETERS,
device_class=None,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda api: api.level,
available_fn=lambda api: api.level is not None,
),
HochwasserPortalSensorEntityDescription(
key=STAGE_SENSOR,
translation_key=STAGE_SENSOR,
icon="mdi:waves-arrow-up",
native_unit_of_measurement=None,
device_class=None,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda api: api.stage,
available_fn=lambda api: api.stage is not None,
),
HochwasserPortalSensorEntityDescription(
key=FLOW_SENSOR,
translation_key=FLOW_SENSOR,
icon="mdi:waves-arrow-right",
native_unit_of_measurement="m³/s",
device_class=None,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda api: api.flow,
available_fn=lambda api: api.flow is not None,
),
)
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up entities from config entry."""
coordinator: HochwasserPortalCoordinator = hass.data[DOMAIN][entry.entry_id]
async_add_entities(
[
HochwasserPortalSensor(coordinator, entry, description)
for description in SENSOR_TYPES
if description.available_fn(coordinator.api)
or entry.data.get(CONF_ADD_UNAVAILABLE, False)
]
)
class HochwasserPortalSensor(
CoordinatorEntity[HochwasserPortalCoordinator], SensorEntity
):
"""Sensor representation."""
entity_description: HochwasserPortalSensorEntityDescription
_attr_has_entity_name = True
def __init__(
self,
coordinator: HochwasserPortalCoordinator,
entry: ConfigEntry,
description: HochwasserPortalSensorEntityDescription,
) -> None:
"""Initialize the sensor."""
super().__init__(coordinator)
self.api = coordinator.api
self.entity_description = description
self._attr_unique_id = f"{entry.unique_id}_{description.key}"
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, entry.entry_id)},
name=f"{entry.title}",
configuration_url=self.api.url,
manufacturer=f"{ATTR_DATA_PROVIDERS[self.api.ident[:2]]}",
model=f"{self.api.ident}",
)
self._attr_attribution = (
f"Data provided by {ATTR_DATA_PROVIDERS[self.api.ident[:2]]}"
)
LOGGER.debug("Setting up sensor: %s", self._attr_unique_id)
@property
def native_value(self):
"""Return the state of the sensor."""
return self.entity_description.value_fn(self.api)
@property
def extra_state_attributes(self):
"""Return the state attributes of the sensor."""
data = {}
if self.api.last_update is not None:
data[ATTR_LAST_UPDATE] = self.api.last_update
if self.api.url is not None:
data[ATTR_URL] = self.api.url
if self.api.hint is not None:
data[ATTR_HINT] = self.api.hint
if bool(data):
return data
return None
@property
def available(self) -> bool:
"""Could the device be accessed during the last update call."""
return self.entity_description.available_fn(self.api)