Avoid writing unifiprotect state when nothing has changed (#100439)
This commit is contained in:
parent
7b71d27637
commit
8a98a0e830
7 changed files with 163 additions and 25 deletions
|
@ -621,3 +621,23 @@ class ProtectEventBinarySensor(EventEntityMixin, BinarySensorEntity):
|
|||
if not is_on:
|
||||
self._event = None
|
||||
self._attr_extra_state_attributes = {}
|
||||
|
||||
@callback
|
||||
def _async_updated_event(self, device: ProtectModelWithId) -> None:
|
||||
"""Call back for incoming data that only writes when state has changed.
|
||||
|
||||
Only the is_on, _attr_extra_state_attributes, and available are ever
|
||||
updated for these entities, and since the websocket update for the
|
||||
device will trigger an update for all entities connected to the device,
|
||||
we want to avoid writing state unless something has actually changed.
|
||||
"""
|
||||
previous_is_on = self._attr_is_on
|
||||
previous_available = self._attr_available
|
||||
previous_extra_state_attributes = self._attr_extra_state_attributes
|
||||
self._async_update_device_from_protect(device)
|
||||
if (
|
||||
self._attr_is_on != previous_is_on
|
||||
or self._attr_extra_state_attributes != previous_extra_state_attributes
|
||||
or self._attr_available != previous_available
|
||||
):
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -193,3 +193,17 @@ class ProtectButton(ProtectDeviceEntity, ButtonEntity):
|
|||
|
||||
if self.entity_description.ufp_press is not None:
|
||||
await getattr(self.device, self.entity_description.ufp_press)()
|
||||
|
||||
@callback
|
||||
def _async_updated_event(self, device: ProtectModelWithId) -> None:
|
||||
"""Call back for incoming data that only writes when state has changed.
|
||||
|
||||
Only available is updated for these entities, and since the websocket
|
||||
update for the device will trigger an update for all entities connected
|
||||
to the device, we want to avoid writing state unless something has
|
||||
actually changed.
|
||||
"""
|
||||
previous_available = self._attr_available
|
||||
self._async_update_device_from_protect(device)
|
||||
if self._attr_available != previous_available:
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -115,6 +115,26 @@ class ProtectMediaPlayer(ProtectDeviceEntity, MediaPlayerEntity):
|
|||
)
|
||||
self._attr_available = is_connected and updated_device.feature_flags.has_speaker
|
||||
|
||||
@callback
|
||||
def _async_updated_event(self, device: ProtectModelWithId) -> None:
|
||||
"""Call back for incoming data that only writes when state has changed.
|
||||
|
||||
Only the state, volume, and available are ever updated for these
|
||||
entities, and since the websocket update for the device will trigger
|
||||
an update for all entities connected to the device, we want to avoid
|
||||
writing state unless something has actually changed.
|
||||
"""
|
||||
previous_state = self._attr_state
|
||||
previous_available = self._attr_available
|
||||
previous_volume_level = self._attr_volume_level
|
||||
self._async_update_device_from_protect(device)
|
||||
if (
|
||||
self._attr_state != previous_state
|
||||
or self._attr_volume_level != previous_volume_level
|
||||
or self._attr_available != previous_available
|
||||
):
|
||||
self.async_write_ha_state()
|
||||
|
||||
async def async_set_volume_level(self, volume: float) -> None:
|
||||
"""Set volume level, range 0..1."""
|
||||
|
||||
|
|
|
@ -268,3 +268,21 @@ 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_updated_event(self, device: ProtectModelWithId) -> None:
|
||||
"""Call back for incoming data that only writes when state has changed.
|
||||
|
||||
Only the native value and available are ever updated for these
|
||||
entities, and since the websocket update for the device will trigger
|
||||
an update for all entities connected to the device, we want to avoid
|
||||
writing state unless something has actually changed.
|
||||
"""
|
||||
previous_value = self._attr_native_value
|
||||
previous_available = self._attr_available
|
||||
self._async_update_device_from_protect(device)
|
||||
if (
|
||||
self._attr_native_value != previous_value
|
||||
or self._attr_available != previous_available
|
||||
):
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -349,9 +349,9 @@ class ProtectSelects(ProtectDeviceEntity, SelectEntity):
|
|||
description: ProtectSelectEntityDescription,
|
||||
) -> None:
|
||||
"""Initialize the unifi protect select entity."""
|
||||
self._async_set_options(data, description)
|
||||
super().__init__(data, device, description)
|
||||
self._attr_name = f"{self.device.display_name} {self.entity_description.name}"
|
||||
self._async_set_options()
|
||||
|
||||
@callback
|
||||
def _async_update_device_from_protect(self, device: ProtectModelWithId) -> None:
|
||||
|
@ -366,31 +366,28 @@ class ProtectSelects(ProtectDeviceEntity, SelectEntity):
|
|||
_LOGGER.debug(
|
||||
"Updating dynamic select options for %s", entity_description.name
|
||||
)
|
||||
self._async_set_options()
|
||||
self._async_set_options(self.data, entity_description)
|
||||
if (unifi_value := entity_description.get_ufp_value(device)) is None:
|
||||
unifi_value = TYPE_EMPTY_VALUE
|
||||
self._attr_current_option = self._unifi_to_hass_options.get(
|
||||
unifi_value, unifi_value
|
||||
)
|
||||
|
||||
@callback
|
||||
def _async_set_options(self) -> None:
|
||||
def _async_set_options(
|
||||
self, data: ProtectData, description: ProtectSelectEntityDescription
|
||||
) -> None:
|
||||
"""Set options attributes from UniFi Protect device."""
|
||||
|
||||
if self.entity_description.ufp_options is not None:
|
||||
options = self.entity_description.ufp_options
|
||||
if (ufp_options := description.ufp_options) is not None:
|
||||
options = ufp_options
|
||||
else:
|
||||
assert self.entity_description.ufp_options_fn is not None
|
||||
options = self.entity_description.ufp_options_fn(self.data.api)
|
||||
assert description.ufp_options_fn is not None
|
||||
options = description.ufp_options_fn(data.api)
|
||||
|
||||
self._attr_options = [item["name"] for item in options]
|
||||
self._hass_to_unifi_options = {item["name"]: item["id"] for item in options}
|
||||
self._unifi_to_hass_options = {item["id"]: item["name"] for item in options}
|
||||
|
||||
@property
|
||||
def current_option(self) -> str:
|
||||
"""Return the current selected option."""
|
||||
|
||||
unifi_value = self.entity_description.get_ufp_value(self.device)
|
||||
if unifi_value is None:
|
||||
unifi_value = TYPE_EMPTY_VALUE
|
||||
return self._unifi_to_hass_options.get(unifi_value, unifi_value)
|
||||
|
||||
async def async_select_option(self, option: str) -> None:
|
||||
"""Change the Select Entity Option."""
|
||||
|
||||
|
@ -404,3 +401,23 @@ 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_updated_event(self, device: ProtectModelWithId) -> None:
|
||||
"""Call back for incoming data that only writes when state has changed.
|
||||
|
||||
Only the options, option, and available are ever updated for these
|
||||
entities, and since the websocket update for the device will trigger
|
||||
an update for all entities connected to the device, we want to avoid
|
||||
writing state unless something has actually changed.
|
||||
"""
|
||||
previous_option = self._attr_current_option
|
||||
previous_options = self._attr_options
|
||||
previous_available = self._attr_available
|
||||
self._async_update_device_from_protect(device)
|
||||
if (
|
||||
self._attr_current_option != previous_option
|
||||
or self._attr_options != previous_options
|
||||
or self._attr_available != previous_available
|
||||
):
|
||||
self.async_write_ha_state()
|
||||
|
|
|
@ -710,22 +710,56 @@ class ProtectDeviceSensor(ProtectDeviceEntity, SensorEntity):
|
|||
|
||||
entity_description: ProtectSensorEntityDescription
|
||||
|
||||
@callback
|
||||
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_updated_event(self, device: ProtectModelWithId) -> None:
|
||||
"""Call back for incoming data that only writes when state has changed.
|
||||
|
||||
Only the native value and available are ever updated for these
|
||||
entities, and since the websocket update for the device will trigger
|
||||
an update for all entities connected to the device, we want to avoid
|
||||
writing state unless something has actually changed.
|
||||
"""
|
||||
previous_value = self._attr_native_value
|
||||
previous_available = self._attr_available
|
||||
self._async_update_device_from_protect(device)
|
||||
if (
|
||||
self._attr_native_value != previous_value
|
||||
or self._attr_available != previous_available
|
||||
):
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
class ProtectNVRSensor(ProtectNVREntity, SensorEntity):
|
||||
"""A Ubiquiti UniFi Protect Sensor."""
|
||||
|
||||
entity_description: ProtectSensorEntityDescription
|
||||
|
||||
@callback
|
||||
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_updated_event(self, device: ProtectModelWithId) -> None:
|
||||
"""Call back for incoming data that only writes when state has changed.
|
||||
|
||||
Only the native value and available are ever updated for these
|
||||
entities, and since the websocket update for the device will trigger
|
||||
an update for all entities connected to the device, we want to avoid
|
||||
writing state unless something has actually changed.
|
||||
"""
|
||||
previous_value = self._attr_native_value
|
||||
previous_available = self._attr_available
|
||||
self._async_update_device_from_protect(device)
|
||||
if (
|
||||
self._attr_native_value != previous_value
|
||||
or self._attr_available != previous_available
|
||||
):
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
class ProtectEventSensor(EventEntityMixin, SensorEntity):
|
||||
"""A UniFi Protect Device Sensor with access tokens."""
|
||||
|
|
|
@ -420,21 +420,36 @@ class ProtectSwitch(ProtectDeviceEntity, SwitchEntity):
|
|||
self._attr_name = f"{self.device.display_name} {self.entity_description.name}"
|
||||
self._switch_type = self.entity_description.key
|
||||
|
||||
@property
|
||||
def is_on(self) -> bool:
|
||||
"""Return true if device is on."""
|
||||
return self.entity_description.get_ufp_value(self.device) is True
|
||||
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."""
|
||||
|
||||
await self.entity_description.ufp_set(self.device, True)
|
||||
|
||||
async def async_turn_off(self, **kwargs: Any) -> None:
|
||||
"""Turn the device off."""
|
||||
|
||||
await self.entity_description.ufp_set(self.device, False)
|
||||
|
||||
@callback
|
||||
def _async_updated_event(self, device: ProtectModelWithId) -> None:
|
||||
"""Call back for incoming data that only writes when state has changed.
|
||||
|
||||
Only the is_on and available are ever updated for these
|
||||
entities, and since the websocket update for the device will trigger
|
||||
an update for all entities connected to the device, we want to avoid
|
||||
writing state unless something has actually changed.
|
||||
"""
|
||||
previous_is_on = self._attr_is_on
|
||||
previous_available = self._attr_available
|
||||
self._async_update_device_from_protect(device)
|
||||
if (
|
||||
self._attr_is_on != previous_is_on
|
||||
or self._attr_available != previous_available
|
||||
):
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
class ProtectNVRSwitch(ProtectNVREntity, SwitchEntity):
|
||||
"""A UniFi Protect NVR Switch."""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue