diff --git a/homeassistant/components/ezviz/__init__.py b/homeassistant/components/ezviz/__init__.py index 670e07a07dc..19dd5121d69 100644 --- a/homeassistant/components/ezviz/__init__.py +++ b/homeassistant/components/ezviz/__init__.py @@ -2,7 +2,8 @@ from datetime import timedelta import logging -from pyezviz.client import EzvizClient, HTTPError, InvalidURL, PyEzvizError +from pyezviz.client import EzvizClient +from pyezviz.exceptions import HTTPError, InvalidURL, PyEzvizError from homeassistant.const import ( CONF_PASSWORD, diff --git a/homeassistant/components/ezviz/camera.py b/homeassistant/components/ezviz/camera.py index 919ff5039b2..d2dbd1b6aab 100644 --- a/homeassistant/components/ezviz/camera.py +++ b/homeassistant/components/ezviz/camera.py @@ -1,29 +1,43 @@ """Support ezviz camera devices.""" import asyncio -from datetime import timedelta import logging from haffmpeg.tools import IMAGE_JPEG, ImageFrame +from pyezviz.exceptions import HTTPError, InvalidHost, PyEzvizError import voluptuous as vol from homeassistant.components.camera import PLATFORM_SCHEMA, SUPPORT_STREAM, Camera from homeassistant.components.ffmpeg import DATA_FFMPEG from homeassistant.config_entries import SOURCE_DISCOVERY, SOURCE_IGNORE, SOURCE_IMPORT from homeassistant.const import CONF_IP_ADDRESS, CONF_PASSWORD, CONF_USERNAME -from homeassistant.helpers import config_validation as cv +from homeassistant.helpers import config_validation as cv, entity_platform from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import ( + ATTR_DIRECTION, + ATTR_ENABLE, + ATTR_LEVEL, ATTR_SERIAL, + ATTR_SPEED, + ATTR_TYPE, CONF_CAMERAS, CONF_FFMPEG_ARGUMENTS, DATA_COORDINATOR, DEFAULT_CAMERA_USERNAME, DEFAULT_FFMPEG_ARGUMENTS, DEFAULT_RTSP_PORT, + DIR_DOWN, + DIR_LEFT, + DIR_RIGHT, + DIR_UP, DOMAIN, MANUFACTURER, + SERVICE_ALARM_SOUND, + SERVICE_ALARM_TRIGER, + SERVICE_DETECTION_SENSITIVITY, + SERVICE_PTZ, + SERVICE_WAKE_DEVICE, ) CAMERA_SCHEMA = vol.Schema( @@ -40,8 +54,6 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( _LOGGER = logging.getLogger(__name__) -MIN_TIME_BETWEEN_SESSION_RENEW = timedelta(seconds=90) - async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up a Ezviz IP Camera from platform config.""" @@ -157,6 +169,46 @@ async def async_setup_entry(hass, entry, async_add_entities): async_add_entities(camera_entities) + platform = entity_platform.current_platform.get() + + platform.async_register_entity_service( + SERVICE_PTZ, + { + vol.Required(ATTR_DIRECTION): vol.In( + [DIR_UP, DIR_DOWN, DIR_LEFT, DIR_RIGHT] + ), + vol.Required(ATTR_SPEED): cv.positive_int, + }, + "perform_ptz", + ) + + platform.async_register_entity_service( + SERVICE_ALARM_TRIGER, + { + vol.Required(ATTR_ENABLE): cv.positive_int, + }, + "perform_sound_alarm", + ) + + platform.async_register_entity_service( + SERVICE_WAKE_DEVICE, {}, "perform_wake_device" + ) + + platform.async_register_entity_service( + SERVICE_ALARM_SOUND, + {vol.Required(ATTR_LEVEL): cv.positive_int}, + "perform_alarm_sound", + ) + + platform.async_register_entity_service( + SERVICE_DETECTION_SENSITIVITY, + { + vol.Required(ATTR_LEVEL): cv.positive_int, + vol.Required(ATTR_TYPE): cv.positive_int, + }, + "perform_set_alarm_detection_sensibility", + ) + class EzvizCamera(CoordinatorEntity, Camera, RestoreEntity): """An implementation of a Ezviz security camera.""" @@ -232,6 +284,24 @@ class EzvizCamera(CoordinatorEntity, Camera, RestoreEntity): """Camera Motion Detection Status.""" return self.coordinator.data[self._idx]["alarm_notify"] + def enable_motion_detection(self): + """Enable motion detection in camera.""" + try: + self.coordinator.ezviz_client.set_camera_defence(self._serial, 1) + + except InvalidHost as err: + _LOGGER.error("Error enabling motion detection") + raise InvalidHost from err + + def disable_motion_detection(self): + """Disable motion detection.""" + try: + self.coordinator.ezviz_client.set_camera_defence(self._serial, 0) + + except InvalidHost as err: + _LOGGER.error("Error disabling motion detection") + raise InvalidHost from err + @property def unique_id(self): """Return the name of this camera.""" @@ -271,3 +341,52 @@ class EzvizCamera(CoordinatorEntity, Camera, RestoreEntity): self._rtsp_stream = rtsp_stream_source return rtsp_stream_source return None + + def perform_ptz(self, direction, speed): + """Perform a PTZ action on the camera.""" + _LOGGER.debug("PTZ action '%s' on %s", direction, self._name) + try: + self.coordinator.ezviz_client.ptz_control( + str(direction).upper(), self._serial, "START", speed + ) + self.coordinator.ezviz_client.ptz_control( + str(direction).upper(), self._serial, "STOP", speed + ) + + except HTTPError as err: + _LOGGER.error("Cannot perform PTZ") + raise HTTPError from err + + def perform_sound_alarm(self, enable): + """Sound the alarm on a camera.""" + try: + self.coordinator.ezviz_client.sound_alarm(self._serial, enable) + except HTTPError as err: + _LOGGER.debug("Cannot sound alarm") + raise HTTPError from err + + def perform_wake_device(self): + """Basically wakes the camera by querying the device.""" + try: + self.coordinator.ezviz_client.get_detection_sensibility(self._serial) + except (HTTPError, PyEzvizError) as err: + _LOGGER.error("Cannot wake device") + raise PyEzvizError from err + + def perform_alarm_sound(self, level): + """Enable/Disable movement sound alarm.""" + try: + self.coordinator.ezviz_client.alarm_sound(self._serial, level, 1) + except HTTPError as err: + _LOGGER.error("Cannot set alarm sound level for on movement detected") + raise HTTPError from err + + def perform_set_alarm_detection_sensibility(self, level, type_value): + """Set camera detection sensibility level service.""" + try: + self.coordinator.ezviz_client.detection_sensibility( + self._serial, level, type_value + ) + except (HTTPError, PyEzvizError) as err: + _LOGGER.error("Cannot set detection sensitivity level") + raise PyEzvizError from err diff --git a/homeassistant/components/ezviz/config_flow.py b/homeassistant/components/ezviz/config_flow.py index 6915d8fa8db..8f10e3f0698 100644 --- a/homeassistant/components/ezviz/config_flow.py +++ b/homeassistant/components/ezviz/config_flow.py @@ -1,8 +1,15 @@ """Config flow for ezviz.""" import logging -from pyezviz.client import EzvizClient, HTTPError, InvalidURL, PyEzvizError -from pyezviz.test_cam_rtsp import AuthTestResultFailed, InvalidHost, TestRTSPAuth +from pyezviz.client import EzvizClient +from pyezviz.exceptions import ( + AuthTestResultFailed, + HTTPError, + InvalidHost, + InvalidURL, + PyEzvizError, +) +from pyezviz.test_cam_rtsp import TestRTSPAuth import voluptuous as vol from homeassistant.config_entries import ConfigFlow, OptionsFlow diff --git a/homeassistant/components/ezviz/const.py b/homeassistant/components/ezviz/const.py index c307f0693f6..e3e2cae712c 100644 --- a/homeassistant/components/ezviz/const.py +++ b/homeassistant/components/ezviz/const.py @@ -6,29 +6,30 @@ MANUFACTURER = "Ezviz" # Configuration ATTR_SERIAL = "serial" CONF_CAMERAS = "cameras" -ATTR_SWITCH = "switch" -ATTR_ENABLE = "enable" -ATTR_DIRECTION = "direction" -ATTR_SPEED = "speed" -ATTR_LEVEL = "level" -ATTR_TYPE = "type_value" -DIR_UP = "up" -DIR_DOWN = "down" -DIR_LEFT = "left" -DIR_RIGHT = "right" -ATTR_LIGHT = "LIGHT" -ATTR_SOUND = "SOUND" -ATTR_INFRARED_LIGHT = "INFRARED_LIGHT" -ATTR_PRIVACY = "PRIVACY" -ATTR_SLEEP = "SLEEP" -ATTR_MOBILE_TRACKING = "MOBILE_TRACKING" -ATTR_TRACKING = "TRACKING" CONF_FFMPEG_ARGUMENTS = "ffmpeg_arguments" ATTR_HOME = "HOME_MODE" ATTR_AWAY = "AWAY_MODE" ATTR_TYPE_CLOUD = "EZVIZ_CLOUD_ACCOUNT" ATTR_TYPE_CAMERA = "CAMERA_ACCOUNT" +# Services data +DIR_UP = "up" +DIR_DOWN = "down" +DIR_LEFT = "left" +DIR_RIGHT = "right" +ATTR_ENABLE = "enable" +ATTR_DIRECTION = "direction" +ATTR_SPEED = "speed" +ATTR_LEVEL = "level" +ATTR_TYPE = "type_value" + +# Service names +SERVICE_PTZ = "ptz" +SERVICE_ALARM_TRIGER = "sound_alarm" +SERVICE_WAKE_DEVICE = "wake_device" +SERVICE_ALARM_SOUND = "alarm_sound" +SERVICE_DETECTION_SENSITIVITY = "set_alarm_detection_sensibility" + # Defaults EU_URL = "apiieu.ezvizlife.com" RUSSIA_URL = "apirus.ezvizru.com" diff --git a/homeassistant/components/ezviz/coordinator.py b/homeassistant/components/ezviz/coordinator.py index 2fc9f6c9f82..ad755edce12 100644 --- a/homeassistant/components/ezviz/coordinator.py +++ b/homeassistant/components/ezviz/coordinator.py @@ -3,7 +3,7 @@ from datetime import timedelta import logging from async_timeout import timeout -from pyezviz.client import HTTPError, InvalidURL, PyEzvizError +from pyezviz.exceptions import HTTPError, InvalidURL, PyEzvizError from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed diff --git a/homeassistant/components/ezviz/manifest.json b/homeassistant/components/ezviz/manifest.json index 46abf8bc99a..d5a38b17755 100644 --- a/homeassistant/components/ezviz/manifest.json +++ b/homeassistant/components/ezviz/manifest.json @@ -4,7 +4,7 @@ "documentation": "https://www.home-assistant.io/integrations/ezviz", "dependencies": ["ffmpeg"], "codeowners": ["@RenierM26", "@baqs"], - "requirements": ["pyezviz==0.1.8.7"], + "requirements": ["pyezviz==0.1.8.9"], "config_flow": true, "iot_class": "cloud_polling" } diff --git a/homeassistant/components/ezviz/services.yaml b/homeassistant/components/ezviz/services.yaml new file mode 100644 index 00000000000..2635662e636 --- /dev/null +++ b/homeassistant/components/ezviz/services.yaml @@ -0,0 +1,111 @@ +alarm_sound: + name: Set warning sound level. + description: Set movement warning sound level. + target: + entity: + integration: ezviz + domain: camera + fields: + level: + name: Sound level + description: Sound level (2 is disabled, 1 intensive, 0 soft). + required: true + example: 0 + default: 0 + selector: + number: + min: 0 + max: 2 + step: 1 + mode: box +ptz: + name: PTZ + description: Moves the camera to the direction, with defined speed + target: + entity: + integration: ezviz + domain: camera + fields: + direction: + name: Direction + description: Direction to move camera (up, down, left, right). + required: true + example: "up" + default: "up" + selector: + select: + options: + - "up" + - "down" + - "left" + - "right" + speed: + name: Speed + description: Speed of movement (from 1 to 9). + required: true + example: 5 + default: 5 + selector: + number: + min: 1 + max: 9 + step: 1 + mode: box +set_alarm_detection_sensibility: + name: Detection sensitivity + description: Sets the detection sensibility level. + target: + entity: + integration: ezviz + domain: camera + fields: + level: + name: Sensitivity Level + description: 'Sensibility level (1-6) for type 0 (Normal camera) + or (1-100) for type 3 (PIR sensor camera).' + required: true + example: 3 + default: 3 + selector: + number: + min: 1 + max: 100 + step: 1 + mode: box + type_value: + name: Detection type + description: 'Type of detection. Options : 0 - Camera or 3 - PIR Sensor Camera' + required: true + example: '0' + default: '0' + selector: + select: + options: + - '0' + - '3' +sound_alarm: + name: Sound Alarm + description: Sounds the alarm on your camera. + target: + entity: + integration: ezviz + domain: camera + fields: + enable: + description: Enter 1 or 2 (1=disable, 2=enable). + required: true + example: 1 + default: 1 + selector: + number: + min: 1 + max: 2 + step: 1 + mode: box +wake_device: + name: Wake Camera + description: This can be used to wake the camera/device from hibernation. + target: + entity: + integration: ezviz + domain: camera diff --git a/requirements_all.txt b/requirements_all.txt index 03a5fff0f60..01b1a6109d8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1411,7 +1411,7 @@ pyephember==0.3.1 pyeverlights==0.1.0 # homeassistant.components.ezviz -pyezviz==0.1.8.7 +pyezviz==0.1.8.9 # homeassistant.components.fido pyfido==2.1.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index f0ba017a98f..b5b3a65e67e 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -776,7 +776,7 @@ pyeconet==0.1.14 pyeverlights==0.1.0 # homeassistant.components.ezviz -pyezviz==0.1.8.7 +pyezviz==0.1.8.9 # homeassistant.components.fido pyfido==2.1.1 diff --git a/tests/components/ezviz/test_config_flow.py b/tests/components/ezviz/test_config_flow.py index b762f10447f..2775781cf00 100644 --- a/tests/components/ezviz/test_config_flow.py +++ b/tests/components/ezviz/test_config_flow.py @@ -2,8 +2,13 @@ from unittest.mock import patch -from pyezviz.client import HTTPError, InvalidURL, PyEzvizError -from pyezviz.test_cam_rtsp import AuthTestResultFailed, InvalidHost +from pyezviz.exceptions import ( + AuthTestResultFailed, + HTTPError, + InvalidHost, + InvalidURL, + PyEzvizError, +) from homeassistant.components.ezviz.const import ( ATTR_SERIAL,