diff --git a/homeassistant/components/reolink/sensor.py b/homeassistant/components/reolink/sensor.py index af8d049dbc67..6282f29e4424 100644 --- a/homeassistant/components/reolink/sensor.py +++ b/homeassistant/components/reolink/sensor.py @@ -21,14 +21,30 @@ from . import ReolinkData from .const import DOMAIN -from .entity import ReolinkHostCoordinatorEntity +from .entity import ReolinkChannelCoordinatorEntity, ReolinkHostCoordinatorEntity + + +@dataclass +class ReolinkSensorEntityDescriptionMixin: + """Mixin values for Reolink sensor entities for a camera channel.""" + + value: Callable[[Host, int], int] + + +@dataclass +class ReolinkSensorEntityDescription( + SensorEntityDescription, ReolinkSensorEntityDescriptionMixin +): + """A class that describes sensor entities for a camera channel.""" + + supported: Callable[[Host, int], bool] = lambda api, ch: True @dataclass class ReolinkHostSensorEntityDescriptionMixin: """Mixin values for Reolink host sensor entities.""" - value: Callable[[Host], bool] + value: Callable[[Host], int] @dataclass @@ -37,9 +53,21 @@ class ReolinkHostSensorEntityDescription( ): """A class that describes host sensor entities.""" - supported: Callable[[Host], bool] = lambda host: True + supported: Callable[[Host], bool] = lambda api: True +SENSORS = ( + ReolinkSensorEntityDescription( + key="ptz_pan_position", + translation_key="ptz_pan_position", + icon="mdi:pan", + state_class=SensorStateClass.MEASUREMENT, + entity_category=EntityCategory.DIAGNOSTIC, + value=lambda api, ch: api.ptz_pan_position(ch), + supported=lambda api, ch: api.supported(ch, "ptz_position"), + ), +) + HOST_SENSORS = ( ReolinkHostSensorEntityDescription( key="wifi_signal", @@ -62,11 +90,45 @@ async def async_setup_entry( """Set up a Reolink IP Camera.""" reolink_data: ReolinkData = hass.data[DOMAIN][config_entry.entry_id] - async_add_entities( - ReolinkHostSensorEntity(reolink_data, entity_description) - for entity_description in HOST_SENSORS - if entity_description.supported(reolink_data.host.api) + entities: list[ReolinkSensorEntity | ReolinkHostSensorEntity] = [ + ReolinkSensorEntity(reolink_data, channel, entity_description) + for entity_description in SENSORS + for channel in reolink_data.host.api.channels + if entity_description.supported(reolink_data.host.api, channel) + ] + entities.extend( + [ + ReolinkHostSensorEntity(reolink_data, entity_description) + for entity_description in HOST_SENSORS + if entity_description.supported(reolink_data.host.api) + ] ) + async_add_entities(entities) + + +class ReolinkSensorEntity(ReolinkChannelCoordinatorEntity, SensorEntity): + """Base sensor class for Reolink IP camera sensors.""" + + entity_description: ReolinkSensorEntityDescription + + def __init__( + self, + reolink_data: ReolinkData, + channel: int, + entity_description: ReolinkSensorEntityDescription, + ) -> None: + """Initialize Reolink sensor.""" + super().__init__(reolink_data, channel) + self.entity_description = entity_description + + self._attr_unique_id = ( + f"{self._host.unique_id}_{channel}_{entity_description.key}" + ) + + @property + def native_value(self) -> StateType | date | datetime | Decimal: + """Return the value reported by the sensor.""" + return self.entity_description.value(self._host.api, self._channel) class ReolinkHostSensorEntity(ReolinkHostCoordinatorEntity, SensorEntity): @@ -79,7 +141,7 @@ def __init__( reolink_data: ReolinkData, entity_description: ReolinkHostSensorEntityDescription, ) -> None: - """Initialize Reolink binary sensor.""" + """Initialize Reolink host sensor.""" super().__init__(reolink_data) self.entity_description = entity_description diff --git a/homeassistant/components/reolink/strings.json b/homeassistant/components/reolink/strings.json index 08ee78fd9300..cdaeb7d06560 100644 --- a/homeassistant/components/reolink/strings.json +++ b/homeassistant/components/reolink/strings.json @@ -102,6 +102,9 @@ "sensor": { "wifi_signal": { "name": "Wi-Fi signal" + }, + "ptz_pan_position": { + "name": "PTZ pan position" } } }