Add entity description to EZVIZ SwitchEntity (#95672)

* Initial commit

* Update switch entity

* Add entity description

* Redundant get. Key will always be there.

* fixed dumb condition mistake.

* Removed names from entity description

* Implement suggestions

* async_add_entities has iterator so cleanup

* Update strings.json
This commit is contained in:
Renier Moorcroft 2023-07-29 17:37:40 +02:00 committed by GitHub
parent 750260b266
commit f52876c7f6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 173 additions and 34 deletions

View file

@ -163,6 +163,44 @@
"last_alarm_type_name": {
"name": "Last alarm type name"
}
},
"switch": {
"status_light": {
"name": "Status light"
},
"privacy": {
"name": "Privacy"
},
"infrared_light": {
"name": "Infrared light"
},
"sleep": {
"name": "Sleep"
},
"audio": {
"name": "Audio"
},
"motion_tracking": {
"name": "Motion tracking"
},
"all_day_video_recording": {
"name": "All day video recording"
},
"auto_sleep": {
"name": "Auto sleep"
},
"flicker_light_on_movement": {
"name": "Flicker light on movement"
},
"pir_motion_activated_light": {
"name": "PIR motion activated light"
},
"tamper_alarm": {
"name": "Tamper alarm"
},
"follow_movement": {
"name": "Follow movement"
}
}
},
"services": {

View file

@ -1,14 +1,20 @@
"""Support for EZVIZ Switch sensors."""
from __future__ import annotations
from dataclasses import dataclass
from typing import Any
from pyezviz.constants import DeviceSwitchType
from pyezviz.constants import DeviceSwitchType, SupportExt
from pyezviz.exceptions import HTTPError, PyEzvizError
from homeassistant.components.switch import SwitchDeviceClass, SwitchEntity
from homeassistant.components.switch import (
SwitchDeviceClass,
SwitchEntity,
SwitchEntityDescription,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.core import HomeAssistant, callback
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DATA_COORDINATOR, DOMAIN
@ -16,6 +22,96 @@ from .coordinator import EzvizDataUpdateCoordinator
from .entity import EzvizEntity
@dataclass
class EzvizSwitchEntityDescriptionMixin:
"""Mixin values for EZVIZ Switch entities."""
supported_ext: str | None
@dataclass
class EzvizSwitchEntityDescription(
SwitchEntityDescription, EzvizSwitchEntityDescriptionMixin
):
"""Describe a EZVIZ switch."""
SWITCH_TYPES: dict[int, EzvizSwitchEntityDescription] = {
3: EzvizSwitchEntityDescription(
key="3",
translation_key="status_light",
device_class=SwitchDeviceClass.SWITCH,
supported_ext=None,
),
7: EzvizSwitchEntityDescription(
key="7",
translation_key="privacy",
device_class=SwitchDeviceClass.SWITCH,
supported_ext=str(SupportExt.SupportPtzPrivacy.value),
),
10: EzvizSwitchEntityDescription(
key="10",
translation_key="infrared_light",
device_class=SwitchDeviceClass.SWITCH,
supported_ext=str(SupportExt.SupportCloseInfraredLight.value),
),
21: EzvizSwitchEntityDescription(
key="21",
translation_key="sleep",
device_class=SwitchDeviceClass.SWITCH,
supported_ext=str(SupportExt.SupportSleep.value),
),
22: EzvizSwitchEntityDescription(
key="22",
translation_key="audio",
device_class=SwitchDeviceClass.SWITCH,
supported_ext=str(SupportExt.SupportAudioOnoff.value),
),
25: EzvizSwitchEntityDescription(
key="25",
translation_key="motion_tracking",
device_class=SwitchDeviceClass.SWITCH,
supported_ext=str(SupportExt.SupportIntelligentTrack.value),
),
29: EzvizSwitchEntityDescription(
key="29",
translation_key="all_day_video_recording",
device_class=SwitchDeviceClass.SWITCH,
supported_ext=str(SupportExt.SupportFulldayRecord.value),
),
32: EzvizSwitchEntityDescription(
key="32",
translation_key="auto_sleep",
device_class=SwitchDeviceClass.SWITCH,
supported_ext=str(SupportExt.SupportAutoSleep.value),
),
301: EzvizSwitchEntityDescription(
key="301",
translation_key="flicker_light_on_movement",
device_class=SwitchDeviceClass.SWITCH,
supported_ext=str(SupportExt.SupportActiveDefense.value),
),
305: EzvizSwitchEntityDescription(
key="305",
translation_key="pir_motion_activated_light",
device_class=SwitchDeviceClass.SWITCH,
supported_ext=str(SupportExt.SupportLightRelate.value),
),
306: EzvizSwitchEntityDescription(
key="306",
translation_key="tamper_alarm",
device_class=SwitchDeviceClass.SWITCH,
supported_ext=str(SupportExt.SupportTamperAlarm.value),
),
650: EzvizSwitchEntityDescription(
key="650",
translation_key="follow_movement",
device_class=SwitchDeviceClass.SWITCH,
supported_ext=str(SupportExt.SupportTracking.value),
),
}
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
@ -24,61 +120,66 @@ async def async_setup_entry(
DATA_COORDINATOR
]
supported_switches = {switches.value for switches in DeviceSwitchType}
async_add_entities(
[
EzvizSwitch(coordinator, camera, switch)
EzvizSwitch(coordinator, camera, switch_number)
for camera in coordinator.data
for switch in coordinator.data[camera].get("switches")
if switch in supported_switches
]
for switch_number in coordinator.data[camera]["switches"]
if switch_number in SWITCH_TYPES
if SWITCH_TYPES[switch_number].supported_ext
in coordinator.data[camera]["supportExt"]
or SWITCH_TYPES[switch_number].supported_ext is None
)
class EzvizSwitch(EzvizEntity, SwitchEntity):
"""Representation of a EZVIZ sensor."""
_attr_device_class = SwitchDeviceClass.SWITCH
_attr_has_entity_name = True
def __init__(
self, coordinator: EzvizDataUpdateCoordinator, serial: str, switch: str
self, coordinator: EzvizDataUpdateCoordinator, serial: str, switch_number: int
) -> None:
"""Initialize the switch."""
super().__init__(coordinator, serial)
self._name = switch
self._attr_name = f"{self._camera_name} {DeviceSwitchType(switch).name.title()}"
self._switch_number = switch_number
self._attr_unique_id = (
f"{serial}_{self._camera_name}.{DeviceSwitchType(switch).name}"
f"{serial}_{self._camera_name}.{DeviceSwitchType(switch_number).name}"
)
@property
def is_on(self) -> bool:
"""Return the state of the switch."""
return self.data["switches"][self._name]
self.entity_description = SWITCH_TYPES[switch_number]
self._attr_is_on = self.data["switches"][switch_number]
async def async_turn_on(self, **kwargs: Any) -> None:
"""Change a device switch on the camera."""
try:
update_ok = await self.hass.async_add_executor_job(
self.coordinator.ezviz_client.switch_status, self._serial, self._name, 1
)
if await self.hass.async_add_executor_job(
self.coordinator.ezviz_client.switch_status,
self._serial,
self._switch_number,
1,
):
self._attr_is_on = True
self.async_write_ha_state()
except (HTTPError, PyEzvizError) as err:
raise PyEzvizError(f"Failed to turn on switch {self._name}") from err
if update_ok:
await self.coordinator.async_request_refresh()
raise HomeAssistantError(f"Failed to turn on switch {self.name}") from err
async def async_turn_off(self, **kwargs: Any) -> None:
"""Change a device switch on the camera."""
try:
update_ok = await self.hass.async_add_executor_job(
self.coordinator.ezviz_client.switch_status, self._serial, self._name, 0
)
if await self.hass.async_add_executor_job(
self.coordinator.ezviz_client.switch_status,
self._serial,
self._switch_number,
0,
):
self._attr_is_on = False
self.async_write_ha_state()
except (HTTPError, PyEzvizError) as err:
raise PyEzvizError(f"Failed to turn off switch {self._name}") from err
raise HomeAssistantError(f"Failed to turn off switch {self.name}") from err
if update_ok:
await self.coordinator.async_request_refresh()
@callback
def _handle_coordinator_update(self) -> None:
"""Handle updated data from the coordinator."""
self._attr_is_on = self.data["switches"].get(self._switch_number)
super()._handle_coordinator_update()