diff --git a/homeassistant/components/ezviz/entity.py b/homeassistant/components/ezviz/entity.py index 1c966c7f82e..ccf273a970b 100644 --- a/homeassistant/components/ezviz/entity.py +++ b/homeassistant/components/ezviz/entity.py @@ -38,3 +38,32 @@ class EzvizEntity(CoordinatorEntity[EzvizDataUpdateCoordinator], Entity): def data(self) -> dict[str, Any]: """Return coordinator data for this entity.""" return self.coordinator.data[self._serial] + + +class EzvizBaseEntity(Entity): + """Generic entity for EZVIZ individual poll entities.""" + + def __init__( + self, + coordinator: EzvizDataUpdateCoordinator, + serial: str, + ) -> None: + """Initialize the entity.""" + self._serial = serial + self.coordinator = coordinator + self._camera_name = self.data["name"] + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, serial)}, + connections={ + (CONNECTION_NETWORK_MAC, self.data["mac_address"]), + }, + manufacturer=MANUFACTURER, + model=self.data["device_sub_category"], + name=self.data["name"], + sw_version=self.data["version"], + ) + + @property + def data(self) -> dict[str, Any]: + """Return coordinator data for this entity.""" + return self.coordinator.data[self._serial] diff --git a/homeassistant/components/ezviz/manifest.json b/homeassistant/components/ezviz/manifest.json index 6697fbce71d..e9f11f4cd39 100644 --- a/homeassistant/components/ezviz/manifest.json +++ b/homeassistant/components/ezviz/manifest.json @@ -7,5 +7,5 @@ "documentation": "https://www.home-assistant.io/integrations/ezviz", "iot_class": "cloud_polling", "loggers": ["paho_mqtt", "pyezviz"], - "requirements": ["pyezviz==0.2.0.15"] + "requirements": ["pyezviz==0.2.0.17"] } diff --git a/homeassistant/components/ezviz/number.py b/homeassistant/components/ezviz/number.py index 849bf2c400b..074685c69f9 100644 --- a/homeassistant/components/ezviz/number.py +++ b/homeassistant/components/ezviz/number.py @@ -1,8 +1,18 @@ """Support for EZVIZ number controls.""" from __future__ import annotations -from pyezviz.constants import DeviceCatagories -from pyezviz.exceptions import HTTPError, PyEzvizError +from dataclasses import dataclass +from datetime import timedelta +import logging + +from pyezviz.constants import SupportExt +from pyezviz.exceptions import ( + EzvizAuthTokenExpired, + EzvizAuthVerificationCode, + HTTPError, + InvalidURL, + PyEzvizError, +) from homeassistant.components.number import NumberEntity, NumberEntityDescription from homeassistant.config_entries import ConfigEntry @@ -13,17 +23,37 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from .const import DATA_COORDINATOR, DOMAIN from .coordinator import EzvizDataUpdateCoordinator -from .entity import EzvizEntity +from .entity import EzvizBaseEntity -PARALLEL_UPDATES = 1 +SCAN_INTERVAL = timedelta(seconds=3600) +PARALLEL_UPDATES = 0 +_LOGGER = logging.getLogger(__name__) -NUMBER_TYPES = NumberEntityDescription( + +@dataclass +class EzvizNumberEntityDescriptionMixin: + """Mixin values for EZVIZ Number entities.""" + + supported_ext: str + supported_ext_value: list + + +@dataclass +class EzvizNumberEntityDescription( + NumberEntityDescription, EzvizNumberEntityDescriptionMixin +): + """Describe a EZVIZ Number.""" + + +NUMBER_TYPE = EzvizNumberEntityDescription( key="detection_sensibility", name="Detection sensitivity", icon="mdi:eye", entity_category=EntityCategory.CONFIG, native_min_value=0, native_step=1, + supported_ext=str(SupportExt.SupportSensibilityAdjust.value), + supported_ext_value=["1", "3"], ) @@ -36,15 +66,18 @@ async def async_setup_entry( ] async_add_entities( - EzvizSensor(coordinator, camera, sensor, NUMBER_TYPES) - for camera in coordinator.data - for sensor, value in coordinator.data[camera].items() - if sensor in NUMBER_TYPES.key - if value + [ + EzvizSensor(coordinator, camera, value, entry.entry_id) + for camera in coordinator.data + for capibility, value in coordinator.data[camera]["supportExt"].items() + if capibility == NUMBER_TYPE.supported_ext + if value in NUMBER_TYPE.supported_ext_value + ], + update_before_add=True, ) -class EzvizSensor(EzvizEntity, NumberEntity): +class EzvizSensor(EzvizBaseEntity, NumberEntity): """Representation of a EZVIZ number entity.""" _attr_has_entity_name = True @@ -53,46 +86,57 @@ class EzvizSensor(EzvizEntity, NumberEntity): self, coordinator: EzvizDataUpdateCoordinator, serial: str, - sensor: str, - description: NumberEntityDescription, + value: str, + config_entry_id: str, ) -> None: """Initialize the sensor.""" super().__init__(coordinator, serial) - self._sensor_name = sensor - self.battery_cam_type = bool( - self.data["device_category"] - == DeviceCatagories.BATTERY_CAMERA_DEVICE_CATEGORY.value - ) - self._attr_unique_id = f"{serial}_{sensor}" - self._attr_native_max_value = 100 if self.battery_cam_type else 6 - self.entity_description = description + self.sensitivity_type = 3 if value == "3" else 0 + self._attr_native_max_value = 100 if value == "3" else 6 + self._attr_unique_id = f"{serial}_{NUMBER_TYPE.key}" + self.entity_description = NUMBER_TYPE + self.config_entry_id = config_entry_id + self.sensor_value: int | None = None @property def native_value(self) -> float | None: """Return the state of the entity.""" - try: - return float(self.data[self._sensor_name]) - except ValueError: - return None + if self.sensor_value is not None: + return float(self.sensor_value) + return None def set_native_value(self, value: float) -> None: """Set camera detection sensitivity.""" level = int(value) try: - if self.battery_cam_type: - self.coordinator.ezviz_client.detection_sensibility( - self._serial, - level, - 3, - ) - else: - self.coordinator.ezviz_client.detection_sensibility( - self._serial, - level, - 0, - ) + self.coordinator.ezviz_client.detection_sensibility( + self._serial, + level, + self.sensitivity_type, + ) except (HTTPError, PyEzvizError) as err: raise HomeAssistantError( f"Cannot set detection sensitivity level on {self.name}" ) from err + + self.sensor_value = level + + def update(self) -> None: + """Fetch data from EZVIZ.""" + _LOGGER.debug("Updating %s", self.name) + try: + self.sensor_value = self.coordinator.ezviz_client.get_detection_sensibility( + self._serial, + str(self.sensitivity_type), + ) + + except (EzvizAuthTokenExpired, EzvizAuthVerificationCode): + _LOGGER.debug("Failed to login to EZVIZ API") + self.hass.async_create_task( + self.hass.config_entries.async_reload(self.config_entry_id) + ) + return + + except (InvalidURL, HTTPError, PyEzvizError) as error: + raise HomeAssistantError(f"Invalid response from API: {error}") from error diff --git a/requirements_all.txt b/requirements_all.txt index 07a4823291f..fc3f3d3ac01 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1664,7 +1664,7 @@ pyeverlights==0.1.0 pyevilgenius==2.0.0 # homeassistant.components.ezviz -pyezviz==0.2.0.15 +pyezviz==0.2.0.17 # homeassistant.components.fibaro pyfibaro==0.7.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 53b3213dfde..b67921742e9 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1222,7 +1222,7 @@ pyeverlights==0.1.0 pyevilgenius==2.0.0 # homeassistant.components.ezviz -pyezviz==0.2.0.15 +pyezviz==0.2.0.17 # homeassistant.components.fibaro pyfibaro==0.7.1