From 512902fc59e1c3b0d7faec4e72745e7b5918e39f Mon Sep 17 00:00:00 2001 From: mkmer Date: Fri, 24 Nov 2023 11:02:19 -0500 Subject: [PATCH] Add Switch platform for motion detection in Blink (#102789) Co-authored-by: Joost Lekkerkerker --- .coveragerc | 1 + .../components/blink/binary_sensor.py | 2 + homeassistant/components/blink/const.py | 1 + homeassistant/components/blink/strings.json | 5 + homeassistant/components/blink/switch.py | 99 +++++++++++++++++++ 5 files changed, 108 insertions(+) create mode 100644 homeassistant/components/blink/switch.py diff --git a/.coveragerc b/.coveragerc index f28ef24e4b2..00116c658ca 100644 --- a/.coveragerc +++ b/.coveragerc @@ -120,6 +120,7 @@ omit = homeassistant/components/blink/binary_sensor.py homeassistant/components/blink/camera.py homeassistant/components/blink/sensor.py + homeassistant/components/blink/switch.py homeassistant/components/blinksticklight/light.py homeassistant/components/blockchain/sensor.py homeassistant/components/bloomsky/* diff --git a/homeassistant/components/blink/binary_sensor.py b/homeassistant/components/blink/binary_sensor.py index 9400e79838b..8598868e2dc 100644 --- a/homeassistant/components/blink/binary_sensor.py +++ b/homeassistant/components/blink/binary_sensor.py @@ -32,9 +32,11 @@ BINARY_SENSORS_TYPES: tuple[BinarySensorEntityDescription, ...] = ( device_class=BinarySensorDeviceClass.BATTERY, entity_category=EntityCategory.DIAGNOSTIC, ), + # Camera Armed sensor is depreciated covered by switch and will be removed in 2023.6. BinarySensorEntityDescription( key=TYPE_CAMERA_ARMED, translation_key="camera_armed", + entity_registry_enabled_default=False, ), BinarySensorEntityDescription( key=TYPE_MOTION_DETECTED, diff --git a/homeassistant/components/blink/const.py b/homeassistant/components/blink/const.py index 7de42a80efc..d394b5c0008 100644 --- a/homeassistant/components/blink/const.py +++ b/homeassistant/components/blink/const.py @@ -30,4 +30,5 @@ PLATFORMS = [ Platform.BINARY_SENSOR, Platform.CAMERA, Platform.SENSOR, + Platform.SWITCH, ] diff --git a/homeassistant/components/blink/strings.json b/homeassistant/components/blink/strings.json index 85556bbcd5a..c29c4c765b7 100644 --- a/homeassistant/components/blink/strings.json +++ b/homeassistant/components/blink/strings.json @@ -47,6 +47,11 @@ "camera_armed": { "name": "Camera armed" } + }, + "switch": { + "camera_motion": { + "name": "Camera motion detection" + } } }, "services": { diff --git a/homeassistant/components/blink/switch.py b/homeassistant/components/blink/switch.py new file mode 100644 index 00000000000..197c8e08685 --- /dev/null +++ b/homeassistant/components/blink/switch.py @@ -0,0 +1,99 @@ +"""Support for Blink Motion detection switches.""" +from __future__ import annotations + +import asyncio +from typing import Any + +from homeassistant.components.switch import ( + SwitchDeviceClass, + SwitchEntity, + SwitchEntityDescription, +) +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers.device_registry import DeviceInfo +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .const import DEFAULT_BRAND, DOMAIN, TYPE_CAMERA_ARMED +from .coordinator import BlinkUpdateCoordinator + +SWITCH_TYPES: tuple[SwitchEntityDescription, ...] = ( + SwitchEntityDescription( + key=TYPE_CAMERA_ARMED, + icon="mdi:motion-sensor", + translation_key="camera_motion", + device_class=SwitchDeviceClass.SWITCH, + ), +) + + +async def async_setup_entry( + hass: HomeAssistant, + config: ConfigEntry, + async_add_entities: AddEntitiesCallback, +) -> None: + """Set up the Blink switches.""" + coordinator: BlinkUpdateCoordinator = hass.data[DOMAIN][config.entry_id] + + async_add_entities( + BlinkSwitch(coordinator, camera, description) + for camera in coordinator.api.cameras + for description in SWITCH_TYPES + ) + + +class BlinkSwitch(CoordinatorEntity[BlinkUpdateCoordinator], SwitchEntity): + """Representation of a Blink motion detection switch.""" + + _attr_has_entity_name = True + + def __init__( + self, + coordinator: BlinkUpdateCoordinator, + camera, + description: SwitchEntityDescription, + ) -> None: + """Initialize the switch.""" + super().__init__(coordinator) + self._camera = coordinator.api.cameras[camera] + self.entity_description = description + serial = self._camera.serial + self._attr_unique_id = f"{serial}-{description.key}" + self._attr_device_info = DeviceInfo( + identifiers={(DOMAIN, serial)}, + serial_number=serial, + name=camera, + manufacturer=DEFAULT_BRAND, + model=self._camera.camera_type, + ) + + async def async_turn_on(self, **kwargs: Any) -> None: + """Turn the switch on.""" + try: + await self._camera.async_arm(True) + + except asyncio.TimeoutError as er: + raise HomeAssistantError( + "Blink failed to arm camera motion detection" + ) from er + + await self.coordinator.async_refresh() + + async def async_turn_off(self, **kwargs: Any) -> None: + """Turn the switch off.""" + try: + await self._camera.async_arm(False) + + except asyncio.TimeoutError as er: + raise HomeAssistantError( + "Blink failed to dis-arm camera motion detection" + ) from er + + await self.coordinator.async_refresh() + + @property + def is_on(self) -> bool: + """Return if Camera Motion is enabled.""" + return self._camera.motion_enabled