diff --git a/homeassistant/components/unifiprotect/binary_sensor.py b/homeassistant/components/unifiprotect/binary_sensor.py index c4e1aa87df25a..fe2017d2f053b 100644 --- a/homeassistant/components/unifiprotect/binary_sensor.py +++ b/homeassistant/components/unifiprotect/binary_sensor.py @@ -8,11 +8,9 @@ from uiprotect.data import ( NVR, Camera, - Light, ModelType, MountType, ProtectAdoptableDeviceModel, - ProtectModelWithId, Sensor, SmartDetectObjectType, ) @@ -27,11 +25,12 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from .data import ProtectData, UFPConfigEntry +from .data import ProtectData, ProtectDeviceType, UFPConfigEntry from .entity import ( BaseProtectEntity, EventEntityMixin, ProtectDeviceEntity, + ProtectIsOnEntity, ProtectNVREntity, async_all_device_entities, ) @@ -623,31 +622,22 @@ class ProtectBinaryEventEntityDescription( } -class ProtectDeviceBinarySensor(ProtectDeviceEntity, BinarySensorEntity): +class ProtectDeviceBinarySensor( + ProtectIsOnEntity, ProtectDeviceEntity, BinarySensorEntity +): """A UniFi Protect Device Binary Sensor.""" - 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) 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", - ) + _state_attrs = ("_attr_available", "_attr_is_on", "_attr_device_class") @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: super()._async_update_device_from_protect(device) # UP Sense can be any of the 3 contact sensor device classes self._attr_device_class = MOUNT_DEVICE_CLASS_MAP.get( @@ -673,7 +663,6 @@ def __init__( self._disk = disk # backwards compat with old unique IDs index = self._disk.slot - 1 - description = dataclasses.replace( description, key=f"{description.key}_{index}", @@ -682,7 +671,7 @@ def __init__( super().__init__(data, device, description) @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: super()._async_update_device_from_protect(device) slot = self._disk.slot self._attr_available = False @@ -712,7 +701,7 @@ def _set_event_done(self) -> None: self._attr_extra_state_attributes = {} @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: description = self.entity_description prev_event = self._event diff --git a/homeassistant/components/unifiprotect/button.py b/homeassistant/components/unifiprotect/button.py index 6c0ef37e1df10..79985b9c7b250 100644 --- a/homeassistant/components/unifiprotect/button.py +++ b/homeassistant/components/unifiprotect/button.py @@ -4,10 +4,11 @@ from collections.abc import Sequence from dataclasses import dataclass +from functools import partial import logging -from typing import Final +from typing import TYPE_CHECKING, Final -from uiprotect.data import ModelType, ProtectAdoptableDeviceModel, ProtectModelWithId +from uiprotect.data import ModelType, ProtectAdoptableDeviceModel from homeassistant.components.button import ( ButtonDeviceClass, @@ -21,7 +22,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import DEVICES_THAT_ADOPT, DOMAIN -from .data import UFPConfigEntry +from .data import ProtectDeviceType, UFPConfigEntry from .entity import ProtectDeviceEntity, async_all_device_entities from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T @@ -38,7 +39,6 @@ class ProtectButtonEntityDescription( DEVICE_CLASS_CHIME_BUTTON: Final = "unifiprotect__chime_button" -KEY_ADOPT = "adopt" ALL_DEVICE_BUTTONS: tuple[ProtectButtonEntityDescription, ...] = ( @@ -61,7 +61,7 @@ class ProtectButtonEntityDescription( ) ADOPT_BUTTON = ProtectButtonEntityDescription[ProtectAdoptableDeviceModel]( - key=KEY_ADOPT, + key="adopt", name="Adopt device", icon="mdi:plus-circle", ufp_press="adopt", @@ -119,17 +119,25 @@ async def async_setup_entry( """Discover devices on a UniFi Protect NVR.""" data = entry.runtime_data + adopt_entities = partial( + async_all_device_entities, + data, + ProtectAdoptButton, + unadopted_descs=[ADOPT_BUTTON], + ) + base_entities = partial( + async_all_device_entities, + data, + ProtectButton, + all_descs=ALL_DEVICE_BUTTONS, + model_descriptions=_MODEL_DESCRIPTIONS, + ) + @callback def _add_new_device(device: ProtectAdoptableDeviceModel) -> None: - entities = async_all_device_entities( - data, - ProtectButton, - all_descs=ALL_DEVICE_BUTTONS, - unadopted_descs=[ADOPT_BUTTON], - model_descriptions=_MODEL_DESCRIPTIONS, - ufp_device=device, + async_add_entities( + [*base_entities(ufp_device=device), *adopt_entities(ufp_device=device)] ) - async_add_entities(entities) _async_remove_adopt_button(hass, device) @callback @@ -137,29 +145,13 @@ def _async_add_unadopted_device(device: ProtectAdoptableDeviceModel) -> None: if not device.can_adopt or not device.can_create(data.api.bootstrap.auth_user): _LOGGER.debug("Device is not adoptable: %s", device.id) return - async_add_entities( - async_all_device_entities( - data, - ProtectButton, - unadopted_descs=[ADOPT_BUTTON], - ufp_device=device, - ) - ) + async_add_entities(adopt_entities(ufp_device=device)) data.async_subscribe_adopt(_add_new_device) entry.async_on_unload( async_dispatcher_connect(hass, data.add_signal, _async_add_unadopted_device) ) - - async_add_entities( - async_all_device_entities( - data, - ProtectButton, - all_descs=ALL_DEVICE_BUTTONS, - unadopted_descs=[ADOPT_BUTTON], - model_descriptions=_MODEL_DESCRIPTIONS, - ) - ) + async_add_entities([*base_entities(), *adopt_entities()]) for device in data.get_by_types(DEVICES_THAT_ADOPT): _async_remove_adopt_button(hass, device) @@ -170,16 +162,20 @@ class ProtectButton(ProtectDeviceEntity, ButtonEntity): entity_description: ProtectButtonEntityDescription - @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( - self.data.api.bootstrap.auth_user - ) - 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)() + + +class ProtectAdoptButton(ProtectButton): + """A Ubiquiti UniFi Protect Adopt button.""" + + @callback + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: + super()._async_update_device_from_protect(device) + if TYPE_CHECKING: + assert isinstance(device, ProtectAdoptableDeviceModel) + self._attr_available = device.can_adopt and device.can_create( + self.data.api.bootstrap.auth_user + ) diff --git a/homeassistant/components/unifiprotect/camera.py b/homeassistant/components/unifiprotect/camera.py index 73cdb4a2c312e..62c35d00171be 100644 --- a/homeassistant/components/unifiprotect/camera.py +++ b/homeassistant/components/unifiprotect/camera.py @@ -9,7 +9,6 @@ Camera as UFPCamera, CameraChannel, ProtectAdoptableDeviceModel, - ProtectModelWithId, StateType, ) @@ -28,7 +27,7 @@ ATTR_WIDTH, DOMAIN, ) -from .data import ProtectData, UFPConfigEntry +from .data import ProtectData, ProtectDeviceType, UFPConfigEntry from .entity import ProtectDeviceEntity from .utils import get_camera_base_name @@ -216,7 +215,7 @@ def _async_set_stream_source(self) -> None: self._attr_supported_features = _EMPTY_CAMERA_FEATURES @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: super()._async_update_device_from_protect(device) updated_device = self.device channel = updated_device.channels[self.channel.id] diff --git a/homeassistant/components/unifiprotect/entity.py b/homeassistant/components/unifiprotect/entity.py index 7eceb86195533..f29d18ce35b96 100644 --- a/homeassistant/components/unifiprotect/entity.py +++ b/homeassistant/components/unifiprotect/entity.py @@ -9,14 +9,7 @@ from operator import attrgetter from typing import TYPE_CHECKING -from uiprotect.data import ( - NVR, - Event, - ModelType, - ProtectAdoptableDeviceModel, - ProtectModelWithId, - StateType, -) +from uiprotect.data import NVR, Event, ModelType, ProtectAdoptableDeviceModel, StateType from homeassistant.core import callback import homeassistant.helpers.device_registry as dr @@ -30,7 +23,7 @@ DEFAULT_BRAND, DOMAIN, ) -from .data import ProtectData +from .data import ProtectData, ProtectDeviceType from .models import PermRequired, ProtectEntityDescription, ProtectEventMixin _LOGGER = logging.getLogger(__name__) @@ -160,7 +153,7 @@ def async_all_device_entities( class BaseProtectEntity(Entity): """Base class for UniFi protect entities.""" - device: ProtectAdoptableDeviceModel | NVR + device: ProtectDeviceType _attr_should_poll = False _attr_attribution = DEFAULT_ATTRIBUTION @@ -171,7 +164,7 @@ class BaseProtectEntity(Entity): def __init__( self, data: ProtectData, - device: ProtectAdoptableDeviceModel | NVR, + device: ProtectDeviceType, description: EntityDescription | None = None, ) -> None: """Initialize the entity.""" @@ -203,37 +196,32 @@ async def async_update(self) -> None: @callback def _async_set_device_info(self) -> None: - self._attr_device_info = DeviceInfo( - name=self.device.display_name, - manufacturer=DEFAULT_BRAND, - model=self.device.type, - via_device=(DOMAIN, self.data.api.bootstrap.nvr.mac), - sw_version=self.device.firmware_version, - connections={(dr.CONNECTION_NETWORK_MAC, self.device.mac)}, - configuration_url=self.device.protect_url, - ) + """Set device info.""" @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: """Update Entity object from Protect device.""" - if TYPE_CHECKING: - assert isinstance(device, ProtectAdoptableDeviceModel) - - if last_update_success := self.data.last_update_success: + was_available = self._attr_available + if last_updated_success := self.data.last_update_success: self.device = device - async_get_ufp_enabled = self._async_get_ufp_enabled - self._attr_available = ( - last_update_success - and ( - device.state is StateType.CONNECTED - or (not device.is_adopted_by_us and device.can_adopt) + if device.model is ModelType.NVR: + available = last_updated_success + else: + if TYPE_CHECKING: + assert isinstance(device, ProtectAdoptableDeviceModel) + connected = device.state is StateType.CONNECTED or ( + not device.is_adopted_by_us and device.can_adopt ) - and (not async_get_ufp_enabled or async_get_ufp_enabled(device)) - ) + async_get_ufp_enabled = self._async_get_ufp_enabled + enabled = not async_get_ufp_enabled or async_get_ufp_enabled(device) + available = last_updated_success and connected and enabled + + if available != was_available: + self._attr_available = available @callback - def _async_updated_event(self, device: ProtectAdoptableDeviceModel | NVR) -> None: + def _async_updated_event(self, device: ProtectDeviceType) -> None: """When device is updated from Protect.""" previous_attrs = [getter() for getter in self._state_getters] self._async_update_device_from_protect(device) @@ -266,10 +254,36 @@ async def async_added_to_hass(self) -> None: ) +class ProtectIsOnEntity(BaseProtectEntity): + """Base class for entities with is_on property.""" + + _state_attrs: tuple[str, ...] = ("_attr_available", "_attr_is_on") + _attr_is_on: bool | None + entity_description: ProtectEntityDescription + + def _async_update_device_from_protect( + self, device: ProtectAdoptableDeviceModel | NVR + ) -> None: + super()._async_update_device_from_protect(device) + was_on = self._attr_is_on + if was_on != (is_on := self.entity_description.get_ufp_value(device) is True): + self._attr_is_on = is_on + + class ProtectDeviceEntity(BaseProtectEntity): """Base class for UniFi protect entities.""" - device: ProtectAdoptableDeviceModel + @callback + def _async_set_device_info(self) -> None: + self._attr_device_info = DeviceInfo( + name=self.device.display_name, + manufacturer=DEFAULT_BRAND, + model=self.device.type, + via_device=(DOMAIN, self.data.api.bootstrap.nvr.mac), + sw_version=self.device.firmware_version, + connections={(dr.CONNECTION_NETWORK_MAC, self.device.mac)}, + configuration_url=self.device.protect_url, + ) class ProtectNVREntity(BaseProtectEntity): @@ -289,14 +303,6 @@ def _async_set_device_info(self) -> None: configuration_url=self.device.api.base_url, ) - @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: - data = self.data - if last_update_success := data.last_update_success: - self.device = data.api.bootstrap.nvr - - self._attr_available = last_update_success - class EventEntityMixin(ProtectDeviceEntity): """Adds motion event attributes to sensor.""" @@ -338,9 +344,8 @@ def _event_already_ended( event object so we need to check the datetime object that was saved from the last time the entity was updated. """ - event = self._event return bool( - event + (event := self._event) and event.end and prev_event and prev_event_end diff --git a/homeassistant/components/unifiprotect/event.py b/homeassistant/components/unifiprotect/event.py index 4e2fd7fce447a..c8269e363267a 100644 --- a/homeassistant/components/unifiprotect/event.py +++ b/homeassistant/components/unifiprotect/event.py @@ -4,12 +4,7 @@ import dataclasses -from uiprotect.data import ( - Camera, - EventType, - ProtectAdoptableDeviceModel, - ProtectModelWithId, -) +from uiprotect.data import Camera, EventType, ProtectAdoptableDeviceModel from homeassistant.components.event import ( EventDeviceClass, @@ -20,7 +15,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import ATTR_EVENT_ID -from .data import ProtectData, UFPConfigEntry +from .data import ProtectData, ProtectDeviceType, UFPConfigEntry from .entity import EventEntityMixin, ProtectDeviceEntity from .models import ProtectEventMixin @@ -50,7 +45,7 @@ class ProtectDeviceEventEntity(EventEntityMixin, ProtectDeviceEntity, EventEntit entity_description: ProtectEventEntityDescription @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: description = self.entity_description prev_event = self._event diff --git a/homeassistant/components/unifiprotect/light.py b/homeassistant/components/unifiprotect/light.py index 651b9c7d3d495..486a8956e0c78 100644 --- a/homeassistant/components/unifiprotect/light.py +++ b/homeassistant/components/unifiprotect/light.py @@ -5,18 +5,13 @@ import logging from typing import Any -from uiprotect.data import ( - Light, - ModelType, - ProtectAdoptableDeviceModel, - ProtectModelWithId, -) +from uiprotect.data import Light, ModelType, ProtectAdoptableDeviceModel from homeassistant.components.light import ATTR_BRIGHTNESS, ColorMode, LightEntity from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from .data import UFPConfigEntry +from .data import ProtectDeviceType, UFPConfigEntry from .entity import ProtectDeviceEntity _LOGGER = logging.getLogger(__name__) @@ -66,7 +61,7 @@ class ProtectLight(ProtectDeviceEntity, LightEntity): _state_attrs = ("_attr_available", "_attr_is_on", "_attr_brightness") @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: super()._async_update_device_from_protect(device) updated_device = self.device self._attr_is_on = updated_device.is_light_on diff --git a/homeassistant/components/unifiprotect/lock.py b/homeassistant/components/unifiprotect/lock.py index b649813135b35..3e9372db0e545 100644 --- a/homeassistant/components/unifiprotect/lock.py +++ b/homeassistant/components/unifiprotect/lock.py @@ -10,14 +10,13 @@ LockStatusType, ModelType, ProtectAdoptableDeviceModel, - ProtectModelWithId, ) from homeassistant.components.lock import LockEntity, LockEntityDescription from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from .data import UFPConfigEntry +from .data import ProtectDeviceType, UFPConfigEntry from .entity import ProtectDeviceEntity _LOGGER = logging.getLogger(__name__) @@ -60,7 +59,7 @@ class ProtectLock(ProtectDeviceEntity, LockEntity): ) @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: super()._async_update_device_from_protect(device) lock_status = self.device.lock_status diff --git a/homeassistant/components/unifiprotect/media_player.py b/homeassistant/components/unifiprotect/media_player.py index d9b2dad722059..5f9991b257ba9 100644 --- a/homeassistant/components/unifiprotect/media_player.py +++ b/homeassistant/components/unifiprotect/media_player.py @@ -5,12 +5,7 @@ import logging from typing import Any -from uiprotect.data import ( - Camera, - ProtectAdoptableDeviceModel, - ProtectModelWithId, - StateType, -) +from uiprotect.data import Camera, ProtectAdoptableDeviceModel, StateType from uiprotect.exceptions import StreamError from homeassistant.components import media_source @@ -28,7 +23,7 @@ from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.entity_platform import AddEntitiesCallback -from .data import UFPConfigEntry +from .data import ProtectDeviceType, UFPConfigEntry from .entity import ProtectDeviceEntity _LOGGER = logging.getLogger(__name__) @@ -77,7 +72,7 @@ class ProtectMediaPlayer(ProtectDeviceEntity, MediaPlayerEntity): _state_attrs = ("_attr_available", "_attr_state", "_attr_volume_level") @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: super()._async_update_device_from_protect(device) updated_device = self.device self._attr_volume_level = float(updated_device.speaker_settings.volume / 100) diff --git a/homeassistant/components/unifiprotect/number.py b/homeassistant/components/unifiprotect/number.py index a0d360af80bdd..4282746fc563f 100644 --- a/homeassistant/components/unifiprotect/number.py +++ b/homeassistant/components/unifiprotect/number.py @@ -12,7 +12,6 @@ Light, ModelType, ProtectAdoptableDeviceModel, - ProtectModelWithId, ) from homeassistant.components.number import NumberEntity, NumberEntityDescription @@ -20,7 +19,7 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from .data import ProtectData, UFPConfigEntry +from .data import ProtectData, ProtectDeviceType, UFPConfigEntry from .entity import ProtectDeviceEntity, async_all_device_entities from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T @@ -268,7 +267,7 @@ def __init__( self._attr_native_step = self.entity_description.ufp_step @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: super()._async_update_device_from_protect(device) self._attr_native_value = self.entity_description.get_ufp_value(self.device) diff --git a/homeassistant/components/unifiprotect/select.py b/homeassistant/components/unifiprotect/select.py index 9e742caa9cebc..e06ae7bfbeca3 100644 --- a/homeassistant/components/unifiprotect/select.py +++ b/homeassistant/components/unifiprotect/select.py @@ -21,7 +21,6 @@ ModelType, MountType, ProtectAdoptableDeviceModel, - ProtectModelWithId, RecordingMode, Sensor, Viewer, @@ -33,7 +32,7 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import TYPE_EMPTY_VALUE -from .data import ProtectData, UFPConfigEntry +from .data import ProtectData, ProtectDeviceType, UFPConfigEntry from .entity import ProtectDeviceEntity, async_all_device_entities from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T from .utils import async_get_light_motion_current @@ -371,7 +370,7 @@ def __init__( super().__init__(data, device, description) @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: super()._async_update_device_from_protect(device) entity_description = self.entity_description # entities with categories are not exposed for voice diff --git a/homeassistant/components/unifiprotect/sensor.py b/homeassistant/components/unifiprotect/sensor.py index 84cac342d00d7..786c5bd66c825 100644 --- a/homeassistant/components/unifiprotect/sensor.py +++ b/homeassistant/components/unifiprotect/sensor.py @@ -16,7 +16,6 @@ ModelType, ProtectAdoptableDeviceModel, ProtectDeviceModel, - ProtectModelWithId, Sensor, SmartDetectObjectType, ) @@ -41,7 +40,7 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from .data import ProtectData, UFPConfigEntry +from .data import ProtectData, ProtectDeviceType, UFPConfigEntry from .entity import ( BaseProtectEntity, EventEntityMixin, @@ -721,7 +720,7 @@ class BaseProtectSensor(BaseProtectEntity, SensorEntity): entity_description: ProtectSensorEntityDescription _state_attrs = ("_attr_available", "_attr_native_value") - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: super()._async_update_device_from_protect(device) self._attr_native_value = self.entity_description.get_ufp_value(self.device) @@ -756,7 +755,7 @@ def _set_event_done(self) -> None: self._attr_extra_state_attributes = {} @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: description = self.entity_description prev_event = self._event diff --git a/homeassistant/components/unifiprotect/switch.py b/homeassistant/components/unifiprotect/switch.py index ca56a602209f5..6eac572cc3e23 100644 --- a/homeassistant/components/unifiprotect/switch.py +++ b/homeassistant/components/unifiprotect/switch.py @@ -5,14 +5,12 @@ from collections.abc import Sequence from dataclasses import dataclass from functools import partial -import logging from typing import Any from uiprotect.data import ( Camera, ModelType, ProtectAdoptableDeviceModel, - ProtectModelWithId, RecordingMode, VideoMode, ) @@ -23,16 +21,16 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.restore_state import RestoreEntity -from .data import ProtectData, UFPConfigEntry +from .data import ProtectData, ProtectDeviceType, UFPConfigEntry from .entity import ( BaseProtectEntity, ProtectDeviceEntity, + ProtectIsOnEntity, ProtectNVREntity, async_all_device_entities, ) from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T -_LOGGER = logging.getLogger(__name__) ATTR_PREV_MIC = "prev_mic_level" ATTR_PREV_RECORD = "prev_record_mode" @@ -45,10 +43,7 @@ class ProtectSwitchEntityDescription( async def _set_highfps(obj: Camera, value: bool) -> None: - if value: - await obj.set_video_mode(VideoMode.HIGH_FPS) - else: - await obj.set_video_mode(VideoMode.DEFAULT) + await obj.set_video_mode(VideoMode.HIGH_FPS if value else VideoMode.DEFAULT) CAMERA_SWITCHES: tuple[ProtectSwitchEntityDescription, ...] = ( @@ -472,15 +467,10 @@ async def _set_highfps(obj: Camera, value: bool) -> None: } -class ProtectBaseSwitch(BaseProtectEntity, SwitchEntity): +class ProtectBaseSwitch(ProtectIsOnEntity): """Base class for UniFi Protect Switch.""" entity_description: ProtectSwitchEntityDescription - _state_attrs = ("_attr_available", "_attr_is_on") - - 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) is True async def async_turn_on(self, **kwargs: Any) -> None: """Turn the device on.""" @@ -491,18 +481,23 @@ async def async_turn_off(self, **kwargs: Any) -> None: await self.entity_description.ufp_set(self.device, False) -class ProtectSwitch(ProtectBaseSwitch, ProtectDeviceEntity): +class ProtectSwitch(ProtectDeviceEntity, ProtectBaseSwitch, SwitchEntity): """A UniFi Protect Switch.""" + entity_description: ProtectSwitchEntityDescription + -class ProtectNVRSwitch(ProtectBaseSwitch, ProtectNVREntity): +class ProtectNVRSwitch(ProtectNVREntity, ProtectBaseSwitch, SwitchEntity): """A UniFi Protect NVR Switch.""" + entity_description: ProtectSwitchEntityDescription + class ProtectPrivacyModeSwitch(RestoreEntity, ProtectSwitch): """A UniFi Protect Switch.""" device: Camera + entity_description: ProtectSwitchEntityDescription def __init__( self, @@ -533,7 +528,7 @@ def _update_previous_attr(self) -> None: self._attr_extra_state_attributes = {} @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: super()._async_update_device_from_protect(device) # do not add extra state attribute on initialize if self.entity_id: diff --git a/homeassistant/components/unifiprotect/text.py b/homeassistant/components/unifiprotect/text.py index e01a6b31f11e4..9af946a7e116d 100644 --- a/homeassistant/components/unifiprotect/text.py +++ b/homeassistant/components/unifiprotect/text.py @@ -10,7 +10,6 @@ DoorbellMessageType, ModelType, ProtectAdoptableDeviceModel, - ProtectModelWithId, ) from homeassistant.components.text import TextEntity, TextEntityDescription @@ -18,7 +17,7 @@ from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddEntitiesCallback -from .data import UFPConfigEntry +from .data import ProtectDeviceType, UFPConfigEntry from .entity import ProtectDeviceEntity, async_all_device_entities from .models import PermRequired, ProtectEntityDescription, ProtectSetableKeysMixin, T @@ -89,7 +88,7 @@ class ProtectDeviceText(ProtectDeviceEntity, TextEntity): _state_attrs = ("_attr_available", "_attr_native_value") @callback - def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None: + def _async_update_device_from_protect(self, device: ProtectDeviceType) -> None: super()._async_update_device_from_protect(device) self._attr_native_value = self.entity_description.get_ufp_value(self.device)