From 29a2df3dfcf3b5d1fb6cf20b413e024eb0ebf597 Mon Sep 17 00:00:00 2001 From: Jason Hunter Date: Wed, 27 Apr 2022 01:42:53 -0400 Subject: [PATCH] Restore ONVIF sensors (#70393) Co-authored-by: Paulus Schoutsen --- .../components/onvif/binary_sensor.py | 41 +++++++++++++---- homeassistant/components/onvif/event.py | 4 +- homeassistant/components/onvif/sensor.py | 45 ++++++++++++++----- 3 files changed, 70 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/onvif/binary_sensor.py b/homeassistant/components/onvif/binary_sensor.py index 8da68bdf483..2e72d331d3d 100644 --- a/homeassistant/components/onvif/binary_sensor.py +++ b/homeassistant/components/onvif/binary_sensor.py @@ -3,11 +3,15 @@ from __future__ import annotations from homeassistant.components.binary_sensor import BinarySensorEntity from homeassistant.config_entries import ConfigEntry +from homeassistant.const import STATE_ON from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers import entity_registry as er from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.restore_state import RestoreEntity from .base import ONVIFBaseEntity from .const import DOMAIN +from .device import ONVIFDevice async def async_setup_entry( @@ -23,6 +27,13 @@ async def async_setup_entry( for event in device.events.get_platform("binary_sensor") } + ent_reg = er.async_get(hass) + for entry in er.async_entries_for_config_entry(ent_reg, config_entry.entry_id): + if entry.domain == "binary_sensor" and entry.unique_id not in entities: + entities[entry.unique_id] = ONVIFBinarySensor( + entry.unique_id, device, entry + ) + async_add_entities(entities.values()) @callback @@ -40,25 +51,39 @@ async def async_setup_entry( return True -class ONVIFBinarySensor(ONVIFBaseEntity, BinarySensorEntity): +class ONVIFBinarySensor(ONVIFBaseEntity, RestoreEntity, BinarySensorEntity): """Representation of a binary ONVIF event.""" _attr_should_poll = False - def __init__(self, uid, device): + def __init__(self, uid, device: ONVIFDevice, entry: er.RegistryEntry | None = None): """Initialize the ONVIF binary sensor.""" - event = device.events.get_uid(uid) - self._attr_device_class = event.device_class - self._attr_entity_category = event.entity_category - self._attr_entity_registry_enabled_default = event.entity_enabled - self._attr_name = event.name - self._attr_is_on = event.value self._attr_unique_id = uid + if entry is not None: + self._attr_device_class = entry.original_device_class + self._attr_entity_category = entry.entity_category + self._attr_name = entry.name + else: + event = device.events.get_uid(uid) + self._attr_device_class = event.device_class + self._attr_entity_category = event.entity_category + self._attr_entity_registry_enabled_default = event.entity_enabled + self._attr_name = f"{device.name} {event.name}" + self._attr_is_on = event.value super().__init__(device) + @property + def is_on(self) -> bool | None: + """Return true if the binary sensor is on.""" + if (event := self.device.events.get_uid(self._attr_unique_id)) is not None: + return event.value + return self._attr_is_on + async def async_added_to_hass(self): """Connect to dispatcher listening for entity data notifications.""" self.async_on_remove( self.device.events.async_add_listener(self.async_write_ha_state) ) + if (last_state := await self.async_get_last_state()) is not None: + self._attr_is_on = last_state.state == STATE_ON diff --git a/homeassistant/components/onvif/event.py b/homeassistant/components/onvif/event.py index ba8658f5fec..3b4ae981677 100644 --- a/homeassistant/components/onvif/event.py +++ b/homeassistant/components/onvif/event.py @@ -226,9 +226,9 @@ class EventManager: self._events[event.uid] = event - def get_uid(self, uid) -> Event: + def get_uid(self, uid) -> Event | None: """Retrieve event for given id.""" - return self._events[uid] + return self._events.get(uid) def get_platform(self, platform) -> list[Event]: """Retrieve events for given platform.""" diff --git a/homeassistant/components/onvif/sensor.py b/homeassistant/components/onvif/sensor.py index b4f1833a74d..67c0ee3da3f 100644 --- a/homeassistant/components/onvif/sensor.py +++ b/homeassistant/components/onvif/sensor.py @@ -1,13 +1,18 @@ """Support for ONVIF binary sensors.""" from __future__ import annotations -from homeassistant.components.sensor import SensorEntity +from datetime import date, datetime + +from homeassistant.components.sensor import RestoreSensor from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant, callback +from homeassistant.helpers import entity_registry as er from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.typing import StateType from .base import ONVIFBaseEntity from .const import DOMAIN +from .device import ONVIFDevice async def async_setup_entry( @@ -23,6 +28,11 @@ async def async_setup_entry( for event in device.events.get_platform("sensor") } + ent_reg = er.async_get(hass) + for entry in er.async_entries_for_config_entry(ent_reg, config_entry.entry_id): + if entry.domain == "sensor" and entry.unique_id not in entities: + entities[entry.unique_id] = ONVIFSensor(entry.unique_id, device, entry) + async_add_entities(entities.values()) @callback @@ -40,26 +50,41 @@ async def async_setup_entry( return True -class ONVIFSensor(ONVIFBaseEntity, SensorEntity): +class ONVIFSensor(ONVIFBaseEntity, RestoreSensor): """Representation of a ONVIF sensor event.""" _attr_should_poll = False - def __init__(self, uid, device): + def __init__(self, uid, device: ONVIFDevice, entry: er.RegistryEntry | None = None): """Initialize the ONVIF binary sensor.""" - event = device.events.get_uid(uid) - self._attr_device_class = event.device_class - self._attr_entity_category = event.entity_category - self._attr_entity_registry_enabled_default = event.entity_enabled - self._attr_name = event.name - self._attr_native_unit_of_measurement = event.unit_of_measurement - self._attr_native_value = event.value self._attr_unique_id = uid + if entry is not None: + self._attr_device_class = entry.original_device_class + self._attr_entity_category = entry.entity_category + self._attr_name = entry.name + self._attr_native_unit_of_measurement = entry.unit_of_measurement + else: + event = device.events.get_uid(uid) + self._attr_device_class = event.device_class + self._attr_entity_category = event.entity_category + self._attr_entity_registry_enabled_default = event.entity_enabled + self._attr_name = f"{device.name} {event.name}" + self._attr_native_unit_of_measurement = event.unit_of_measurement + self._attr_native_value = event.value super().__init__(device) + @property + def native_value(self) -> StateType | date | datetime: + """Return the value reported by the sensor.""" + if (event := self.device.events.get_uid(self._attr_unique_id)) is not None: + return event.value + return self._attr_native_value + async def async_added_to_hass(self): """Connect to dispatcher listening for entity data notifications.""" self.async_on_remove( self.device.events.async_add_listener(self.async_write_ha_state) ) + if (last_sensor_data := await self.async_get_last_sensor_data()) is not None: + self._attr_native_value = last_sensor_data.native_value