Add Ezviz button entities (#93647)

* Initial commit

* Add button for ptz

* coveragerc

* Add ptz buttons to PTZ cameras only

* Describe support capbility

* Improve typing

* bump api version.

* Match entity naming used throughout

* Add translation

* Create ir before execution and breaks in version

* Fix for translation missing name key.

* Change depreciation to 2024.2.0

* Update camera.py

* Tiny spelling tweaks

---------

Co-authored-by: Franck Nijhof <frenck@frenck.nl>
This commit is contained in:
Renier Moorcroft 2023-07-25 00:31:44 +02:00 committed by GitHub
parent 6717e40114
commit 5ec633a839
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 169 additions and 0 deletions

View File

@ -316,6 +316,7 @@ omit =
homeassistant/components/ezviz/__init__.py
homeassistant/components/ezviz/alarm_control_panel.py
homeassistant/components/ezviz/binary_sensor.py
homeassistant/components/ezviz/button.py
homeassistant/components/ezviz/camera.py
homeassistant/components/ezviz/image.py
homeassistant/components/ezviz/light.py

View File

@ -35,6 +35,7 @@ PLATFORMS_BY_TYPE: dict[str, list] = {
ATTR_TYPE_CLOUD: [
Platform.ALARM_CONTROL_PANEL,
Platform.BINARY_SENSOR,
Platform.BUTTON,
Platform.CAMERA,
Platform.IMAGE,
Platform.LIGHT,

View File

@ -0,0 +1,131 @@
"""Support for EZVIZ button controls."""
from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from typing import Any
from pyezviz import EzvizClient
from pyezviz.constants import SupportExt
from pyezviz.exceptions import HTTPError, PyEzvizError
from homeassistant.components.button import ButtonEntity, ButtonEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import HomeAssistantError
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from .const import DATA_COORDINATOR, DOMAIN
from .coordinator import EzvizDataUpdateCoordinator
from .entity import EzvizEntity
PARALLEL_UPDATES = 1
@dataclass
class EzvizButtonEntityDescriptionMixin:
"""Mixin values for EZVIZ button entities."""
method: Callable[[EzvizClient, str, str], Any]
supported_ext: str
@dataclass
class EzvizButtonEntityDescription(
ButtonEntityDescription, EzvizButtonEntityDescriptionMixin
):
"""Describe a EZVIZ Button."""
BUTTON_ENTITIES = (
EzvizButtonEntityDescription(
key="ptz_up",
translation_key="ptz_up",
icon="mdi:pan",
method=lambda pyezviz_client, serial, run: pyezviz_client.ptz_control(
"UP", serial, run
),
supported_ext=str(SupportExt.SupportPtz.value),
),
EzvizButtonEntityDescription(
key="ptz_down",
translation_key="ptz_down",
icon="mdi:pan",
method=lambda pyezviz_client, serial, run: pyezviz_client.ptz_control(
"DOWN", serial, run
),
supported_ext=str(SupportExt.SupportPtz.value),
),
EzvizButtonEntityDescription(
key="ptz_left",
translation_key="ptz_left",
icon="mdi:pan",
method=lambda pyezviz_client, serial, run: pyezviz_client.ptz_control(
"LEFT", serial, run
),
supported_ext=str(SupportExt.SupportPtz.value),
),
EzvizButtonEntityDescription(
key="ptz_right",
translation_key="ptz_right",
icon="mdi:pan",
method=lambda pyezviz_client, serial, run: pyezviz_client.ptz_control(
"RIGHT", serial, run
),
supported_ext=str(SupportExt.SupportPtz.value),
),
)
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
) -> None:
"""Set up EZVIZ button based on a config entry."""
coordinator: EzvizDataUpdateCoordinator = hass.data[DOMAIN][entry.entry_id][
DATA_COORDINATOR
]
# Add button entities if supportExt value indicates PTZ capbility.
# Could be missing or "0" for unsupported.
# If present with value of "1" then add button entity.
async_add_entities(
EzvizButtonEntity(coordinator, camera, entity_description)
for camera in coordinator.data
for capibility, value in coordinator.data[camera]["supportExt"].items()
for entity_description in BUTTON_ENTITIES
if capibility == entity_description.supported_ext
if value == "1"
)
class EzvizButtonEntity(EzvizEntity, ButtonEntity):
"""Representation of a EZVIZ button entity."""
entity_description: EzvizButtonEntityDescription
_attr_has_entity_name = True
def __init__(
self,
coordinator: EzvizDataUpdateCoordinator,
serial: str,
description: EzvizButtonEntityDescription,
) -> None:
"""Initialize the button."""
super().__init__(coordinator, serial)
self._attr_unique_id = f"{serial}_{description.key}"
self.entity_description = description
def press(self) -> None:
"""Execute the button action."""
try:
self.entity_description.method(
self.coordinator.ezviz_client, self._serial, "START"
)
self.entity_description.method(
self.coordinator.ezviz_client, self._serial, "STOP"
)
except (HTTPError, PyEzvizError) as err:
raise HomeAssistantError(
f"Cannot perform PTZ action on {self.name}"
) from err

View File

@ -263,6 +263,17 @@ class EzvizCamera(EzvizEntity, Camera):
def perform_ptz(self, direction: str, speed: int) -> None:
"""Perform a PTZ action on the camera."""
ir.async_create_issue(
self.hass,
DOMAIN,
"service_depreciation_ptz",
breaks_in_ha_version="2024.2.0",
is_fixable=True,
is_persistent=True,
severity=ir.IssueSeverity.WARNING,
translation_key="service_depreciation_ptz",
)
try:
self.coordinator.ezviz_client.ptz_control(
str(direction).upper(), self._serial, "START", speed

View File

@ -81,6 +81,17 @@
}
}
}
},
"service_depreciation_ptz": {
"title": "EZVIZ PTZ service is being removed",
"fix_flow": {
"step": {
"confirm": {
"title": "[%key:component::ezviz::issues::service_depreciation_ptz::title%]",
"description": "EZVIZ PTZ service is deprecated and will be removed.\nTo move the camera, you can instead use the `button.press` service targetting the PTZ* entities.\n\nPlease remove the use of this service from your automations and scripts and select **submit** to close this issue."
}
}
}
}
},
"entity": {
@ -99,6 +110,20 @@
"name": "Last motion image"
}
},
"button": {
"ptz_up": {
"name": "PTZ up"
},
"ptz_down": {
"name": "PTZ down"
},
"ptz_left": {
"name": "PTZ left"
},
"ptz_right": {
"name": "PTZ right"
}
},
"binary_sensor": {
"alarm_schedules_enabled": {
"name": "Alarm schedules enabled"