From 5f627df6f8d07331e8385f3e24efa0a0e92abdbf Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Mon, 15 Mar 2021 23:59:41 +0100 Subject: [PATCH] Add devices to Verisure integration (#47913) Co-authored-by: Paulus Schoutsen --- .../verisure/alarm_control_panel.py | 12 ++++- .../components/verisure/binary_sensor.py | 32 +++++++++++- homeassistant/components/verisure/camera.py | 37 +++++++++----- homeassistant/components/verisure/const.py | 14 ++++++ homeassistant/components/verisure/lock.py | 21 +++++++- homeassistant/components/verisure/sensor.py | 49 ++++++++++++++++++- homeassistant/components/verisure/switch.py | 19 +++++-- 7 files changed, 163 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/verisure/alarm_control_panel.py b/homeassistant/components/verisure/alarm_control_panel.py index 8a2a05e2005..54e36ac65de 100644 --- a/homeassistant/components/verisure/alarm_control_panel.py +++ b/homeassistant/components/verisure/alarm_control_panel.py @@ -2,7 +2,7 @@ from __future__ import annotations import asyncio -from typing import Callable, Iterable +from typing import Any, Callable, Iterable from homeassistant.components.alarm_control_panel import ( FORMAT_NUMBER, @@ -56,6 +56,16 @@ class VerisureAlarm(CoordinatorEntity, AlarmControlPanelEntity): """Return the unique ID for this alarm control panel.""" return self.coordinator.entry.data[CONF_GIID] + @property + def device_info(self) -> dict[str, Any]: + """Return device information about this entity.""" + return { + "name": "Verisure Alarm", + "manufacturer": "Verisure", + "model": "VBox", + "identifiers": {(DOMAIN, self.coordinator.entry.data[CONF_GIID])}, + } + @property def state(self) -> str | None: """Return the state of the device.""" diff --git a/homeassistant/components/verisure/binary_sensor.py b/homeassistant/components/verisure/binary_sensor.py index 4289a6f8ffc..864785c7cd0 100644 --- a/homeassistant/components/verisure/binary_sensor.py +++ b/homeassistant/components/verisure/binary_sensor.py @@ -1,7 +1,7 @@ """Support for Verisure binary sensors.""" from __future__ import annotations -from typing import Callable, Iterable +from typing import Any, Callable, Iterable from homeassistant.components.binary_sensor import ( DEVICE_CLASS_CONNECTIVITY, @@ -13,7 +13,7 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import Entity from homeassistant.helpers.update_coordinator import CoordinatorEntity -from . import DOMAIN +from .const import CONF_GIID, DOMAIN from .coordinator import VerisureDataUpdateCoordinator @@ -57,6 +57,19 @@ class VerisureDoorWindowSensor(CoordinatorEntity, BinarySensorEntity): """Return the unique ID for this alarm control panel.""" return f"{self.serial_number}_door_window" + @property + def device_info(self) -> dict[str, Any]: + """Return device information about this entity.""" + area = self.coordinator.data["door_window"][self.serial_number]["area"] + return { + "name": area, + "suggested_area": area, + "manufacturer": "Verisure", + "model": "Shock Sensor Detector", + "identifiers": {(DOMAIN, self.serial_number)}, + "via_device": (DOMAIN, self.coordinator.entry.data[CONF_GIID]), + } + @property def device_class(self) -> str: """Return the class of this device, from component DEVICE_CLASSES.""" @@ -88,6 +101,21 @@ class VerisureEthernetStatus(CoordinatorEntity, BinarySensorEntity): """Return the name of the binary sensor.""" return "Verisure Ethernet status" + @property + def unique_id(self) -> str: + """Return the unique ID for this binary sensor.""" + return f"{self.coordinator.entry.data[CONF_GIID]}_ethernet" + + @property + def device_info(self) -> dict[str, Any]: + """Return device information about this entity.""" + return { + "name": "Verisure Alarm", + "manufacturer": "Verisure", + "model": "VBox", + "identifiers": {(DOMAIN, self.coordinator.entry.data[CONF_GIID])}, + } + @property def is_on(self) -> bool: """Return the state of the sensor.""" diff --git a/homeassistant/components/verisure/camera.py b/homeassistant/components/verisure/camera.py index 776211b5cf3..006f9c28ef5 100644 --- a/homeassistant/components/verisure/camera.py +++ b/homeassistant/components/verisure/camera.py @@ -3,7 +3,7 @@ from __future__ import annotations import errno import os -from typing import Callable, Iterable +from typing import Any, Callable, Iterable from verisure import Error as VerisureError @@ -15,7 +15,7 @@ from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_platform import current_platform from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import DOMAIN, LOGGER, SERVICE_CAPTURE_SMARTCAM +from .const import CONF_GIID, DOMAIN, LOGGER, SERVICE_CAPTURE_SMARTCAM from .coordinator import VerisureDataUpdateCoordinator @@ -62,6 +62,29 @@ class VerisureSmartcam(CoordinatorEntity, Camera): self._image_id = None hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, self.delete_image) + @property + def name(self) -> str: + """Return the name of this camera.""" + return self.coordinator.data["cameras"][self.serial_number]["area"] + + @property + def unique_id(self) -> str: + """Return the unique ID for this camera.""" + return self.serial_number + + @property + def device_info(self) -> dict[str, Any]: + """Return device information about this entity.""" + area = self.coordinator.data["cameras"][self.serial_number]["area"] + return { + "name": area, + "suggested_area": area, + "manufacturer": "Verisure", + "model": "SmartCam", + "identifiers": {(DOMAIN, self.serial_number)}, + "via_device": (DOMAIN, self.coordinator.entry.data[CONF_GIID]), + } + def camera_image(self) -> bytes | None: """Return image response.""" self.check_imagelist() @@ -115,16 +138,6 @@ class VerisureSmartcam(CoordinatorEntity, Camera): if error.errno != errno.ENOENT: raise - @property - def name(self) -> str: - """Return the name of this camera.""" - return self.coordinator.data["cameras"][self.serial_number]["area"] - - @property - def unique_id(self) -> str: - """Return the unique ID for this camera.""" - return self.serial_number - def capture_smartcam(self) -> None: """Capture a new picture from a smartcam.""" try: diff --git a/homeassistant/components/verisure/const.py b/homeassistant/components/verisure/const.py index 107d146e708..8e39e0594dd 100644 --- a/homeassistant/components/verisure/const.py +++ b/homeassistant/components/verisure/const.py @@ -17,6 +17,20 @@ SERVICE_CAPTURE_SMARTCAM = "capture_smartcam" SERVICE_DISABLE_AUTOLOCK = "disable_autolock" SERVICE_ENABLE_AUTOLOCK = "enable_autolock" +# Mapping of device types to a human readable name +DEVICE_TYPE_NAME = { + "CAMERAPIR2": "Camera detector", + "HOMEPAD1": "VoiceBox", + "HUMIDITY1": "Climate sensor", + "PIR2": "Camera detector", + "SIREN1": "Siren", + "SMARTCAMERA1": "SmartCam", + "SMOKE2": "Smoke detector", + "SMOKE3": "Smoke detector", + "VOICEBOX1": "VoiceBox", + "WATER1": "Water detector", +} + # Legacy; to remove after YAML removal CONF_CODE_DIGITS = "code_digits" CONF_DEFAULT_LOCK_CODE = "default_lock_code" diff --git a/homeassistant/components/verisure/lock.py b/homeassistant/components/verisure/lock.py index 0431d0aee41..d4708c68e88 100644 --- a/homeassistant/components/verisure/lock.py +++ b/homeassistant/components/verisure/lock.py @@ -2,7 +2,7 @@ from __future__ import annotations import asyncio -from typing import Callable, Iterable +from typing import Any, Callable, Iterable from verisure import Error as VerisureError @@ -15,6 +15,7 @@ from homeassistant.helpers.entity_platform import current_platform from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import ( + CONF_GIID, CONF_LOCK_CODE_DIGITS, CONF_LOCK_DEFAULT_CODE, DEFAULT_LOCK_CODE_DIGITS, @@ -73,6 +74,24 @@ class VerisureDoorlock(CoordinatorEntity, LockEntity): """Return the name of the lock.""" return self.coordinator.data["locks"][self.serial_number]["area"] + @property + def unique_id(self) -> str: + """Return the unique ID for this entity.""" + return self.serial_number + + @property + def device_info(self) -> dict[str, Any]: + """Return device information about this entity.""" + area = self.coordinator.data["locks"][self.serial_number]["area"] + return { + "name": area, + "suggested_area": area, + "manufacturer": "Verisure", + "model": "Lockguard Smartlock", + "identifiers": {(DOMAIN, self.serial_number)}, + "via_device": (DOMAIN, self.coordinator.entry.data[CONF_GIID]), + } + @property def available(self) -> bool: """Return True if entity is available.""" diff --git a/homeassistant/components/verisure/sensor.py b/homeassistant/components/verisure/sensor.py index 37b02161879..614bd0a386d 100644 --- a/homeassistant/components/verisure/sensor.py +++ b/homeassistant/components/verisure/sensor.py @@ -1,7 +1,7 @@ """Support for Verisure sensors.""" from __future__ import annotations -from typing import Callable, Iterable +from typing import Any, Callable, Iterable from homeassistant.config_entries import ConfigEntry from homeassistant.const import PERCENTAGE, TEMP_CELSIUS @@ -9,7 +9,7 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import Entity from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import DOMAIN +from .const import CONF_GIID, DEVICE_TYPE_NAME, DOMAIN from .coordinator import VerisureDataUpdateCoordinator @@ -64,6 +64,22 @@ class VerisureThermometer(CoordinatorEntity, Entity): """Return the unique ID for this entity.""" return f"{self.serial_number}_temperature" + @property + def device_info(self) -> dict[str, Any]: + """Return device information about this entity.""" + device_type = self.coordinator.data["climate"][self.serial_number].get( + "deviceType" + ) + area = self.coordinator.data["climate"][self.serial_number]["deviceArea"] + return { + "name": area, + "suggested_area": area, + "manufacturer": "Verisure", + "model": DEVICE_TYPE_NAME.get(device_type, device_type), + "identifiers": {(DOMAIN, self.serial_number)}, + "via_device": (DOMAIN, self.coordinator.entry.data[CONF_GIID]), + } + @property def state(self) -> str | None: """Return the state of the entity.""" @@ -107,6 +123,22 @@ class VerisureHygrometer(CoordinatorEntity, Entity): """Return the unique ID for this entity.""" return f"{self.serial_number}_humidity" + @property + def device_info(self) -> dict[str, Any]: + """Return device information about this entity.""" + device_type = self.coordinator.data["climate"][self.serial_number].get( + "deviceType" + ) + area = self.coordinator.data["climate"][self.serial_number]["deviceArea"] + return { + "name": area, + "suggested_area": area, + "manufacturer": "Verisure", + "model": DEVICE_TYPE_NAME.get(device_type, device_type), + "identifiers": {(DOMAIN, self.serial_number)}, + "via_device": (DOMAIN, self.coordinator.entry.data[CONF_GIID]), + } + @property def state(self) -> str | None: """Return the state of the entity.""" @@ -150,6 +182,19 @@ class VerisureMouseDetection(CoordinatorEntity, Entity): """Return the unique ID for this entity.""" return f"{self.serial_number}_mice" + @property + def device_info(self) -> dict[str, Any]: + """Return device information about this entity.""" + area = self.coordinator.data["mice"][self.serial_number]["area"] + return { + "name": area, + "suggested_area": area, + "manufacturer": "Verisure", + "model": "Mouse detector", + "identifiers": {(DOMAIN, self.serial_number)}, + "via_device": (DOMAIN, self.coordinator.entry.data[CONF_GIID]), + } + @property def state(self) -> str | None: """Return the state of the device.""" diff --git a/homeassistant/components/verisure/switch.py b/homeassistant/components/verisure/switch.py index 887d052bd81..534db9c7a50 100644 --- a/homeassistant/components/verisure/switch.py +++ b/homeassistant/components/verisure/switch.py @@ -2,7 +2,7 @@ from __future__ import annotations from time import monotonic -from typing import Callable, Iterable +from typing import Any, Callable, Iterable from homeassistant.components.switch import SwitchEntity from homeassistant.config_entries import ConfigEntry @@ -10,7 +10,7 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.entity import Entity from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .const import DOMAIN +from .const import CONF_GIID, DOMAIN from .coordinator import VerisureDataUpdateCoordinator @@ -48,9 +48,22 @@ class VerisureSmartplug(CoordinatorEntity, SwitchEntity): @property def unique_id(self) -> str: - """Return the unique ID for this alarm control panel.""" + """Return the unique ID for this entity.""" return self.serial_number + @property + def device_info(self) -> dict[str, Any]: + """Return device information about this entity.""" + area = self.coordinator.data["smart_plugs"][self.serial_number]["area"] + return { + "name": area, + "suggested_area": area, + "manufacturer": "Verisure", + "model": "SmartPlug", + "identifiers": {(DOMAIN, self.serial_number)}, + "via_device": (DOMAIN, self.coordinator.entry.data[CONF_GIID]), + } + @property def is_on(self) -> bool: """Return true if on."""