diff --git a/homeassistant/components/unifiprotect/binary_sensor.py b/homeassistant/components/unifiprotect/binary_sensor.py index 74710427318..4218d3108e5 100644 --- a/homeassistant/components/unifiprotect/binary_sensor.py +++ b/homeassistant/components/unifiprotect/binary_sensor.py @@ -5,7 +5,6 @@ from __future__ import annotations from collections.abc import Sequence import dataclasses import logging -from typing import Any from uiprotect.data import ( NVR, @@ -632,26 +631,23 @@ class ProtectDeviceBinarySensor(ProtectDeviceEntity, BinarySensorEntity): device: Camera | Light | Sensor entity_description: ProtectBinaryEntityDescription + _state_attrs: tuple[str, ...] = ("_attr_available", "_attr_is_on") @callback def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: super()._async_update_device_from_protect(device) self._attr_is_on = self.entity_description.get_ufp_value(self.device) - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - return (self._attr_available, self._attr_is_on) - class MountableProtectDeviceBinarySensor(ProtectDeviceBinarySensor): """A UniFi Protect Device Binary Sensor that can change device class at runtime.""" device: Sensor + _state_attrs: tuple[str, ...] = ( + "_attr_available", + "_attr_is_on", + "_attr_device_class", + ) @callback def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: @@ -662,21 +658,13 @@ class MountableProtectDeviceBinarySensor(ProtectDeviceBinarySensor): updated_device.mount_type, BinarySensorDeviceClass.DOOR ) - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - return (self._attr_available, self._attr_is_on, self._attr_device_class) - class ProtectDiskBinarySensor(ProtectNVREntity, BinarySensorEntity): """A UniFi Protect NVR Disk Binary Sensor.""" _disk: UOSDisk entity_description: ProtectBinaryEntityDescription + _state_attrs = ("_attr_available", "_attr_is_on") def __init__( self, @@ -715,21 +703,12 @@ class ProtectDiskBinarySensor(ProtectNVREntity, BinarySensorEntity): self._attr_is_on = not self._disk.is_healthy - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - - return (self._attr_available, self._attr_is_on) - class ProtectEventBinarySensor(EventEntityMixin, BinarySensorEntity): """A UniFi Protect Device Binary Sensor for events.""" entity_description: ProtectBinaryEventEntityDescription + _state_attrs = ("_attr_available", "_attr_is_on", "_attr_extra_state_attributes") @callback def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: @@ -740,20 +719,6 @@ class ProtectEventBinarySensor(EventEntityMixin, BinarySensorEntity): self._event = None self._attr_extra_state_attributes = {} - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - - return ( - self._attr_available, - self._attr_is_on, - self._attr_extra_state_attributes, - ) - MODEL_DESCRIPTIONS_WITH_CLASS = ( (_MODEL_DESCRIPTIONS, ProtectDeviceBinarySensor), diff --git a/homeassistant/components/unifiprotect/button.py b/homeassistant/components/unifiprotect/button.py index 265367a9272..7866dd5b183 100644 --- a/homeassistant/components/unifiprotect/button.py +++ b/homeassistant/components/unifiprotect/button.py @@ -186,7 +186,6 @@ class ProtectButton(ProtectDeviceEntity, ButtonEntity): @callback def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: super()._async_update_device_from_protect(device) - if self.entity_description.key == KEY_ADOPT: device = self.device self._attr_available = device.can_adopt and device.can_create( @@ -195,6 +194,5 @@ class ProtectButton(ProtectDeviceEntity, ButtonEntity): async def async_press(self) -> None: """Press the button.""" - if self.entity_description.ufp_press is not None: await getattr(self.device, self.entity_description.ufp_press)() diff --git a/homeassistant/components/unifiprotect/camera.py b/homeassistant/components/unifiprotect/camera.py index 5f077d3a62e..b4596582cd6 100644 --- a/homeassistant/components/unifiprotect/camera.py +++ b/homeassistant/components/unifiprotect/camera.py @@ -3,7 +3,6 @@ from __future__ import annotations import logging -from typing import Any from typing_extensions import Generator from uiprotect.data import ( @@ -163,6 +162,11 @@ class ProtectCamera(ProtectDeviceEntity, Camera): """A Ubiquiti UniFi Protect Camera.""" device: UFPCamera + _state_attrs = ( + "_attr_available", + "_attr_is_recording", + "_attr_motion_detection_enabled", + ) def __init__( self, @@ -210,20 +214,6 @@ class ProtectCamera(ProtectDeviceEntity, Camera): else: self._attr_supported_features = CameraEntityFeature(0) - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - - return ( - self._attr_available, - self._attr_is_recording, - self._attr_motion_detection_enabled, - ) - @callback def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: super()._async_update_device_from_protect(device) diff --git a/homeassistant/components/unifiprotect/entity.py b/homeassistant/components/unifiprotect/entity.py index a41aadfcd89..d1b82dd218f 100644 --- a/homeassistant/components/unifiprotect/entity.py +++ b/homeassistant/components/unifiprotect/entity.py @@ -3,7 +3,9 @@ from __future__ import annotations from collections.abc import Callable, Sequence +from functools import partial import logging +from operator import attrgetter from typing import TYPE_CHECKING, Any from uiprotect.data import ( @@ -161,6 +163,7 @@ class BaseProtectEntity(Entity): device: ProtectAdoptableDeviceModel | NVR _attr_should_poll = False + _state_attrs: tuple[str, ...] = ("_attr_available",) def __init__( self, @@ -194,6 +197,9 @@ class BaseProtectEntity(Entity): self._attr_attribution = DEFAULT_ATTRIBUTION self._async_set_device_info() self._async_update_device_from_protect(device) + self._state_getters = tuple( + partial(attrgetter(attr), self) for attr in self._state_attrs + ) async def async_update(self) -> None: """Update the entity. @@ -233,24 +239,18 @@ class BaseProtectEntity(Entity): and (not async_get_ufp_enabled or async_get_ufp_enabled(device)) ) - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - - return (self._attr_available,) - @callback def _async_updated_event(self, device: ProtectAdoptableDeviceModel | NVR) -> None: """When device is updated from Protect.""" - - previous_attrs = self._async_get_state_attrs() + previous_attrs = [getter() for getter in self._state_getters] self._async_update_device_from_protect(device) - current_attrs = self._async_get_state_attrs() - if previous_attrs != current_attrs: + changed = False + for idx, getter in enumerate(self._state_getters): + if previous_attrs[idx] != getter(): + changed = True + break + + if changed: if _LOGGER.isEnabledFor(logging.DEBUG): device_name = device.name or "" if hasattr(self, "entity_description") and self.entity_description.name: @@ -261,7 +261,7 @@ class BaseProtectEntity(Entity): device_name, device.mac, previous_attrs, - current_attrs, + tuple((getattr(self, attr)) for attr in self._state_attrs), ) self.async_write_ha_state() diff --git a/homeassistant/components/unifiprotect/light.py b/homeassistant/components/unifiprotect/light.py index e8a51c357a0..651b9c7d3d4 100644 --- a/homeassistant/components/unifiprotect/light.py +++ b/homeassistant/components/unifiprotect/light.py @@ -63,16 +63,7 @@ class ProtectLight(ProtectDeviceEntity, LightEntity): _attr_icon = "mdi:spotlight-beam" _attr_color_mode = ColorMode.BRIGHTNESS _attr_supported_color_modes = {ColorMode.BRIGHTNESS} - - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - - return (self._attr_available, self._attr_is_on, self._attr_brightness) + _state_attrs = ("_attr_available", "_attr_is_on", "_attr_brightness") @callback def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: diff --git a/homeassistant/components/unifiprotect/lock.py b/homeassistant/components/unifiprotect/lock.py index 4f5dfe43ce2..52de63cd833 100644 --- a/homeassistant/components/unifiprotect/lock.py +++ b/homeassistant/components/unifiprotect/lock.py @@ -49,6 +49,13 @@ class ProtectLock(ProtectDeviceEntity, LockEntity): device: Doorlock entity_description: LockEntityDescription + _state_attrs = ( + "_attr_available", + "_attr_is_locked", + "_attr_is_locking", + "_attr_is_unlocking", + "_attr_is_jammed", + ) def __init__( self, @@ -64,22 +71,6 @@ class ProtectLock(ProtectDeviceEntity, LockEntity): self._attr_name = f"{self.device.display_name} Lock" - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - - return ( - self._attr_available, - self._attr_is_locked, - self._attr_is_locking, - self._attr_is_unlocking, - self._attr_is_jammed, - ) - @callback def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: super()._async_update_device_from_protect(device) diff --git a/homeassistant/components/unifiprotect/media_player.py b/homeassistant/components/unifiprotect/media_player.py index 55a85155d89..dbf5321b3d8 100644 --- a/homeassistant/components/unifiprotect/media_player.py +++ b/homeassistant/components/unifiprotect/media_player.py @@ -69,6 +69,7 @@ class ProtectMediaPlayer(ProtectDeviceEntity, MediaPlayerEntity): | MediaPlayerEntityFeature.STOP | MediaPlayerEntityFeature.BROWSE_MEDIA ) + _state_attrs = ("_attr_available", "_attr_state", "_attr_volume_level") def __init__( self, @@ -107,16 +108,6 @@ class ProtectMediaPlayer(ProtectDeviceEntity, MediaPlayerEntity): ) self._attr_available = is_connected and updated_device.feature_flags.has_speaker - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - - return (self._attr_available, self._attr_state, self._attr_volume_level) - async def async_set_volume_level(self, volume: float) -> None: """Set volume level, range 0..1.""" diff --git a/homeassistant/components/unifiprotect/number.py b/homeassistant/components/unifiprotect/number.py index c3d0bb8b6b9..44f965e4796 100644 --- a/homeassistant/components/unifiprotect/number.py +++ b/homeassistant/components/unifiprotect/number.py @@ -6,7 +6,6 @@ from collections.abc import Sequence from dataclasses import dataclass from datetime import timedelta import logging -from typing import Any from uiprotect.data import ( Camera, @@ -257,6 +256,7 @@ class ProtectNumbers(ProtectDeviceEntity, NumberEntity): device: Camera | Light entity_description: ProtectNumberEntityDescription + _state_attrs = ("_attr_available", "_attr_native_value") def __init__( self, @@ -278,13 +278,3 @@ class ProtectNumbers(ProtectDeviceEntity, NumberEntity): async def async_set_native_value(self, value: float) -> None: """Set new value.""" await self.entity_description.ufp_set(self.device, value) - - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - - return (self._attr_available, self._attr_native_value) diff --git a/homeassistant/components/unifiprotect/select.py b/homeassistant/components/unifiprotect/select.py index b253e5a9d18..2dd52fac774 100644 --- a/homeassistant/components/unifiprotect/select.py +++ b/homeassistant/components/unifiprotect/select.py @@ -358,6 +358,7 @@ class ProtectSelects(ProtectDeviceEntity, SelectEntity): device: Camera | Light | Viewer entity_description: ProtectSelectEntityDescription + _state_attrs = ("_attr_available", "_attr_options", "_attr_current_option") def __init__( self, @@ -418,13 +419,3 @@ class ProtectSelects(ProtectDeviceEntity, SelectEntity): if self.entity_description.ufp_enum_type is not None: unifi_value = self.entity_description.ufp_enum_type(unifi_value) await self.entity_description.ufp_set(self.device, unifi_value) - - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - - return (self._attr_available, self._attr_options, self._attr_current_option) diff --git a/homeassistant/components/unifiprotect/sensor.py b/homeassistant/components/unifiprotect/sensor.py index 754bf3bc82b..56b7ef7f9a4 100644 --- a/homeassistant/components/unifiprotect/sensor.py +++ b/homeassistant/components/unifiprotect/sensor.py @@ -702,60 +702,33 @@ class ProtectDeviceSensor(ProtectDeviceEntity, SensorEntity): """A Ubiquiti UniFi Protect Sensor.""" entity_description: ProtectSensorEntityDescription + _state_attrs = ("_attr_available", "_attr_native_value") def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: super()._async_update_device_from_protect(device) self._attr_native_value = self.entity_description.get_ufp_value(self.device) - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - - return (self._attr_available, self._attr_native_value) - class ProtectNVRSensor(ProtectNVREntity, SensorEntity): """A Ubiquiti UniFi Protect Sensor.""" entity_description: ProtectSensorEntityDescription + _state_attrs = ("_attr_available", "_attr_native_value") def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: super()._async_update_device_from_protect(device) self._attr_native_value = self.entity_description.get_ufp_value(self.device) - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - - return (self._attr_available, self._attr_native_value) - class ProtectEventSensor(EventEntityMixin, SensorEntity): """A UniFi Protect Device Sensor with access tokens.""" entity_description: ProtectSensorEventEntityDescription - - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - - return ( - self._attr_available, - self._attr_native_value, - self._attr_extra_state_attributes, - ) + _state_attrs = ( + "_attr_available", + "_attr_native_value", + "_attr_extra_state_attributes", + ) class ProtectLicensePlateEventSensor(ProtectEventSensor): diff --git a/homeassistant/components/unifiprotect/switch.py b/homeassistant/components/unifiprotect/switch.py index 7690dc5d62f..36c2c497b57 100644 --- a/homeassistant/components/unifiprotect/switch.py +++ b/homeassistant/components/unifiprotect/switch.py @@ -476,6 +476,7 @@ class ProtectSwitch(ProtectDeviceEntity, SwitchEntity): """A UniFi Protect Switch.""" entity_description: ProtectSwitchEntityDescription + _state_attrs = ("_attr_available", "_attr_is_on") def __init__( self, @@ -500,20 +501,12 @@ class ProtectSwitch(ProtectDeviceEntity, SwitchEntity): """Turn the device off.""" await self.entity_description.ufp_set(self.device, False) - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - return (self._attr_available, self._attr_is_on) - class ProtectNVRSwitch(ProtectNVREntity, SwitchEntity): """A UniFi Protect NVR Switch.""" entity_description: ProtectSwitchEntityDescription + _state_attrs = ("_attr_available", "_attr_is_on") def __init__( self, @@ -537,15 +530,6 @@ class ProtectNVRSwitch(ProtectNVREntity, SwitchEntity): """Turn the device off.""" await self.entity_description.ufp_set(self.device, False) - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - return (self._attr_available, self._attr_is_on) - class ProtectPrivacyModeSwitch(RestoreEntity, ProtectSwitch): """A UniFi Protect Switch.""" diff --git a/homeassistant/components/unifiprotect/text.py b/homeassistant/components/unifiprotect/text.py index acd28a31794..009e013ee51 100644 --- a/homeassistant/components/unifiprotect/text.py +++ b/homeassistant/components/unifiprotect/text.py @@ -4,7 +4,6 @@ from __future__ import annotations from collections.abc import Sequence from dataclasses import dataclass -from typing import Any from uiprotect.data import ( Camera, @@ -87,6 +86,7 @@ class ProtectDeviceText(ProtectDeviceEntity, TextEntity): """A Ubiquiti UniFi Protect Sensor.""" entity_description: ProtectTextEntityDescription + _state_attrs = ("_attr_available", "_attr_native_value") def __init__( self, @@ -102,17 +102,6 @@ class ProtectDeviceText(ProtectDeviceEntity, TextEntity): super()._async_update_device_from_protect(device) self._attr_native_value = self.entity_description.get_ufp_value(self.device) - @callback - def _async_get_state_attrs(self) -> tuple[Any, ...]: - """Retrieve data that goes into the current state of the entity. - - Called before and after updating entity and state is only written if there - is a change. - """ - - return (self._attr_available, self._attr_native_value) - async def async_set_value(self, value: str) -> None: """Change the value.""" - await self.entity_description.ufp_set(self.device, value)