Complete typing on Verisure integration (#47482)

This commit is contained in:
Franck Nijhof 2021-03-06 00:37:56 +01:00 committed by GitHub
parent 4c181bbfe5
commit 10dae253e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 159 additions and 90 deletions

View File

@ -1,5 +1,8 @@
"""Support for Verisure devices.""" """Support for Verisure devices."""
from __future__ import annotations
from datetime import timedelta from datetime import timedelta
from typing import Any, Literal
from jsonpath import jsonpath from jsonpath import jsonpath
import verisure import verisure
@ -12,8 +15,10 @@ from homeassistant.const import (
EVENT_HOMEASSISTANT_STOP, EVENT_HOMEASSISTANT_STOP,
HTTP_SERVICE_UNAVAILABLE, HTTP_SERVICE_UNAVAILABLE,
) )
from homeassistant.core import HomeAssistant
from homeassistant.helpers import discovery from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.typing import ConfigType
from homeassistant.util import Throttle from homeassistant.util import Throttle
from .const import ( from .const import (
@ -78,7 +83,7 @@ CONFIG_SCHEMA = vol.Schema(
DEVICE_SERIAL_SCHEMA = vol.Schema({vol.Required(ATTR_DEVICE_SERIAL): cv.string}) DEVICE_SERIAL_SCHEMA = vol.Schema({vol.Required(ATTR_DEVICE_SERIAL): cv.string})
def setup(hass, config): def setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the Verisure integration.""" """Set up the Verisure integration."""
global HUB # pylint: disable=global-statement global HUB # pylint: disable=global-statement
HUB = VerisureHub(config[DOMAIN]) HUB = VerisureHub(config[DOMAIN])
@ -137,7 +142,7 @@ def setup(hass, config):
class VerisureHub: class VerisureHub:
"""A Verisure hub wrapper class.""" """A Verisure hub wrapper class."""
def __init__(self, domain_config): def __init__(self, domain_config: ConfigType):
"""Initialize the Verisure hub.""" """Initialize the Verisure hub."""
self.overview = {} self.overview = {}
self.imageseries = {} self.imageseries = {}
@ -150,7 +155,7 @@ class VerisureHub:
self.giid = domain_config.get(CONF_GIID) self.giid = domain_config.get(CONF_GIID)
def login(self): def login(self) -> bool:
"""Login to Verisure.""" """Login to Verisure."""
try: try:
self.session.login() self.session.login()
@ -161,7 +166,7 @@ class VerisureHub:
return self.set_giid() return self.set_giid()
return True return True
def logout(self): def logout(self) -> bool:
"""Logout from Verisure.""" """Logout from Verisure."""
try: try:
self.session.logout() self.session.logout()
@ -170,7 +175,7 @@ class VerisureHub:
return False return False
return True return True
def set_giid(self): def set_giid(self) -> bool:
"""Set installation GIID.""" """Set installation GIID."""
try: try:
self.session.set_giid(self.giid) self.session.set_giid(self.giid)
@ -179,7 +184,7 @@ class VerisureHub:
return False return False
return True return True
def update_overview(self): def update_overview(self) -> None:
"""Update the overview.""" """Update the overview."""
try: try:
self.overview = self.session.get_overview() self.overview = self.session.get_overview()
@ -192,34 +197,34 @@ class VerisureHub:
raise raise
@Throttle(timedelta(seconds=60)) @Throttle(timedelta(seconds=60))
def update_smartcam_imageseries(self): def update_smartcam_imageseries(self) -> None:
"""Update the image series.""" """Update the image series."""
self.imageseries = self.session.get_camera_imageseries() self.imageseries = self.session.get_camera_imageseries()
@Throttle(timedelta(seconds=30)) @Throttle(timedelta(seconds=30))
def smartcam_capture(self, device_id): def smartcam_capture(self, device_id: str) -> None:
"""Capture a new image from a smartcam.""" """Capture a new image from a smartcam."""
self.session.capture_image(device_id) self.session.capture_image(device_id)
def disable_autolock(self, device_id): def disable_autolock(self, device_id: str) -> None:
"""Disable autolock.""" """Disable autolock."""
self.session.set_lock_config(device_id, auto_lock_enabled=False) self.session.set_lock_config(device_id, auto_lock_enabled=False)
def enable_autolock(self, device_id): def enable_autolock(self, device_id: str) -> None:
"""Enable autolock.""" """Enable autolock."""
self.session.set_lock_config(device_id, auto_lock_enabled=True) self.session.set_lock_config(device_id, auto_lock_enabled=True)
def get(self, jpath, *args): def get(self, jpath: str, *args) -> list[Any] | Literal[False]:
"""Get values from the overview that matches the jsonpath.""" """Get values from the overview that matches the jsonpath."""
res = jsonpath(self.overview, jpath % args) res = jsonpath(self.overview, jpath % args)
return res or [] return res or []
def get_first(self, jpath, *args): def get_first(self, jpath: str, *args) -> Any | None:
"""Get first value from the overview that matches the jsonpath.""" """Get first value from the overview that matches the jsonpath."""
res = self.get(jpath, *args) res = self.get(jpath, *args)
return res[0] if res else None return res[0] if res else None
def get_image_info(self, jpath, *args): def get_image_info(self, jpath: str, *args) -> list[Any] | Literal[False]:
"""Get values from the imageseries that matches the jsonpath.""" """Get values from the imageseries that matches the jsonpath."""
res = jsonpath(self.imageseries, jpath % args) res = jsonpath(self.imageseries, jpath % args)
return res or [] return res or []

View File

@ -1,7 +1,13 @@
"""Support for Verisure alarm control panels.""" """Support for Verisure alarm control panels."""
from time import sleep from __future__ import annotations
import homeassistant.components.alarm_control_panel as alarm from time import sleep
from typing import Any, Callable
from homeassistant.components.alarm_control_panel import (
FORMAT_NUMBER,
AlarmControlPanelEntity,
)
from homeassistant.components.alarm_control_panel.const import ( from homeassistant.components.alarm_control_panel.const import (
SUPPORT_ALARM_ARM_AWAY, SUPPORT_ALARM_ARM_AWAY,
SUPPORT_ALARM_ARM_HOME, SUPPORT_ALARM_ARM_HOME,
@ -11,12 +17,19 @@ from homeassistant.const import (
STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_HOME,
STATE_ALARM_DISARMED, STATE_ALARM_DISARMED,
) )
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity
from . import HUB as hub from . import HUB as hub
from .const import CONF_ALARM, CONF_CODE_DIGITS, CONF_GIID, LOGGER from .const import CONF_ALARM, CONF_CODE_DIGITS, CONF_GIID, LOGGER
def setup_platform(hass, config, add_entities, discovery_info=None): def setup_platform(
hass: HomeAssistant,
config: dict[str, Any],
add_entities: Callable[[list[Entity], bool], None],
discovery_info: dict[str, Any] | None = None,
) -> None:
"""Set up the Verisure platform.""" """Set up the Verisure platform."""
alarms = [] alarms = []
if int(hub.config.get(CONF_ALARM, 1)): if int(hub.config.get(CONF_ALARM, 1)):
@ -25,7 +38,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
add_entities(alarms) add_entities(alarms)
def set_arm_state(state, code=None): def set_arm_state(state: str, code: str | None = None) -> None:
"""Send set arm state command.""" """Send set arm state command."""
transaction_id = hub.session.set_arm_state(code, state)[ transaction_id = hub.session.set_arm_state(code, state)[
"armStateChangeTransactionId" "armStateChangeTransactionId"
@ -38,7 +51,7 @@ def set_arm_state(state, code=None):
hub.update_overview() hub.update_overview()
class VerisureAlarm(alarm.AlarmControlPanelEntity): class VerisureAlarm(AlarmControlPanelEntity):
"""Representation of a Verisure alarm status.""" """Representation of a Verisure alarm status."""
def __init__(self): def __init__(self):
@ -48,7 +61,7 @@ class VerisureAlarm(alarm.AlarmControlPanelEntity):
self._changed_by = None self._changed_by = None
@property @property
def name(self): def name(self) -> str:
"""Return the name of the device.""" """Return the name of the device."""
giid = hub.config.get(CONF_GIID) giid = hub.config.get(CONF_GIID)
if giid is not None: if giid is not None:
@ -61,7 +74,7 @@ class VerisureAlarm(alarm.AlarmControlPanelEntity):
return "{} alarm".format(hub.session.installations[0]["alias"]) return "{} alarm".format(hub.session.installations[0]["alias"])
@property @property
def state(self): def state(self) -> str | None:
"""Return the state of the device.""" """Return the state of the device."""
return self._state return self._state
@ -71,16 +84,16 @@ class VerisureAlarm(alarm.AlarmControlPanelEntity):
return SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY return SUPPORT_ALARM_ARM_HOME | SUPPORT_ALARM_ARM_AWAY
@property @property
def code_format(self): def code_format(self) -> str:
"""Return one or more digits/characters.""" """Return one or more digits/characters."""
return alarm.FORMAT_NUMBER return FORMAT_NUMBER
@property @property
def changed_by(self): def changed_by(self) -> str | None:
"""Return the last change triggered by.""" """Return the last change triggered by."""
return self._changed_by return self._changed_by
def update(self): def update(self) -> None:
"""Update alarm status.""" """Update alarm status."""
hub.update_overview() hub.update_overview()
status = hub.get_first("$.armState.statusType") status = hub.get_first("$.armState.statusType")
@ -94,14 +107,14 @@ class VerisureAlarm(alarm.AlarmControlPanelEntity):
LOGGER.error("Unknown alarm state %s", status) LOGGER.error("Unknown alarm state %s", status)
self._changed_by = hub.get_first("$.armState.name") self._changed_by = hub.get_first("$.armState.name")
def alarm_disarm(self, code=None): def alarm_disarm(self, code: str | None = None) -> None:
"""Send disarm command.""" """Send disarm command."""
set_arm_state("DISARMED", code) set_arm_state("DISARMED", code)
def alarm_arm_home(self, code=None): def alarm_arm_home(self, code: str | None = None) -> None:
"""Send arm home command.""" """Send arm home command."""
set_arm_state("ARMED_HOME", code) set_arm_state("ARMED_HOME", code)
def alarm_arm_away(self, code=None): def alarm_arm_away(self, code: str | None = None) -> None:
"""Send arm away command.""" """Send arm away command."""
set_arm_state("ARMED_AWAY", code) set_arm_state("ARMED_AWAY", code)

View File

@ -1,13 +1,24 @@
"""Support for Verisure binary sensors.""" """Support for Verisure binary sensors."""
from __future__ import annotations
from typing import Any, Callable
from homeassistant.components.binary_sensor import ( from homeassistant.components.binary_sensor import (
DEVICE_CLASS_CONNECTIVITY, DEVICE_CLASS_CONNECTIVITY,
BinarySensorEntity, BinarySensorEntity,
) )
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity
from . import CONF_DOOR_WINDOW, HUB as hub from . import CONF_DOOR_WINDOW, HUB as hub
def setup_platform(hass, config, add_entities, discovery_info=None): def setup_platform(
hass: HomeAssistant,
config: dict[str, Any],
add_entities: Callable[[list[Entity], bool], None],
discovery_info: dict[str, Any] | None = None,
) -> None:
"""Set up the Verisure binary sensors.""" """Set up the Verisure binary sensors."""
sensors = [] sensors = []
hub.update_overview() hub.update_overview()
@ -29,12 +40,12 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
class VerisureDoorWindowSensor(BinarySensorEntity): class VerisureDoorWindowSensor(BinarySensorEntity):
"""Representation of a Verisure door window sensor.""" """Representation of a Verisure door window sensor."""
def __init__(self, device_label): def __init__(self, device_label: str):
"""Initialize the Verisure door window sensor.""" """Initialize the Verisure door window sensor."""
self._device_label = device_label self._device_label = device_label
@property @property
def name(self): def name(self) -> str:
"""Return the name of the binary sensor.""" """Return the name of the binary sensor."""
return hub.get_first( return hub.get_first(
"$.doorWindow.doorWindowDevice[?(@.deviceLabel=='%s')].area", "$.doorWindow.doorWindowDevice[?(@.deviceLabel=='%s')].area",
@ -42,7 +53,7 @@ class VerisureDoorWindowSensor(BinarySensorEntity):
) )
@property @property
def is_on(self): def is_on(self) -> bool:
"""Return the state of the sensor.""" """Return the state of the sensor."""
return ( return (
hub.get_first( hub.get_first(
@ -53,7 +64,7 @@ class VerisureDoorWindowSensor(BinarySensorEntity):
) )
@property @property
def available(self): def available(self) -> bool:
"""Return True if entity is available.""" """Return True if entity is available."""
return ( return (
hub.get_first( hub.get_first(
@ -64,7 +75,7 @@ class VerisureDoorWindowSensor(BinarySensorEntity):
) )
# pylint: disable=no-self-use # pylint: disable=no-self-use
def update(self): def update(self) -> None:
"""Update the state of the sensor.""" """Update the state of the sensor."""
hub.update_overview() hub.update_overview()
@ -73,26 +84,26 @@ class VerisureEthernetStatus(BinarySensorEntity):
"""Representation of a Verisure VBOX internet status.""" """Representation of a Verisure VBOX internet status."""
@property @property
def name(self): def name(self) -> str:
"""Return the name of the binary sensor.""" """Return the name of the binary sensor."""
return "Verisure Ethernet status" return "Verisure Ethernet status"
@property @property
def is_on(self): def is_on(self) -> bool:
"""Return the state of the sensor.""" """Return the state of the sensor."""
return hub.get_first("$.ethernetConnectedNow") return hub.get_first("$.ethernetConnectedNow")
@property @property
def available(self): def available(self) -> bool:
"""Return True if entity is available.""" """Return True if entity is available."""
return hub.get_first("$.ethernetConnectedNow") is not None return hub.get_first("$.ethernetConnectedNow") is not None
# pylint: disable=no-self-use # pylint: disable=no-self-use
def update(self): def update(self) -> None:
"""Update the state of the sensor.""" """Update the state of the sensor."""
hub.update_overview() hub.update_overview()
@property @property
def device_class(self): def device_class(self) -> str:
"""Return the class of this device, from component DEVICE_CLASSES.""" """Return the class of this device, from component DEVICE_CLASSES."""
return DEVICE_CLASS_CONNECTIVITY return DEVICE_CLASS_CONNECTIVITY

View File

@ -1,22 +1,34 @@
"""Support for Verisure cameras.""" """Support for Verisure cameras."""
from __future__ import annotations
import errno import errno
import os import os
from typing import Any, Callable, Literal
from homeassistant.components.camera import Camera from homeassistant.components.camera import Camera
from homeassistant.const import EVENT_HOMEASSISTANT_STOP from homeassistant.const import EVENT_HOMEASSISTANT_STOP
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity
from . import HUB as hub from . import HUB as hub
from .const import CONF_SMARTCAM, LOGGER from .const import CONF_SMARTCAM, LOGGER
def setup_platform(hass, config, add_entities, discovery_info=None): def setup_platform(
hass: HomeAssistant,
config: dict[str, Any],
add_entities: Callable[[list[Entity], bool], None],
discovery_info: dict[str, Any] | None = None,
) -> None | Literal[False]:
"""Set up the Verisure Camera.""" """Set up the Verisure Camera."""
if not int(hub.config.get(CONF_SMARTCAM, 1)): if not int(hub.config.get(CONF_SMARTCAM, 1)):
return False return False
directory_path = hass.config.config_dir directory_path = hass.config.config_dir
if not os.access(directory_path, os.R_OK): if not os.access(directory_path, os.R_OK):
LOGGER.error("file path %s is not readable", directory_path) LOGGER.error("file path %s is not readable", directory_path)
return False return False
hub.update_overview() hub.update_overview()
smartcams = [ smartcams = [
VerisureSmartcam(hass, device_label, directory_path) VerisureSmartcam(hass, device_label, directory_path)
@ -29,7 +41,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
class VerisureSmartcam(Camera): class VerisureSmartcam(Camera):
"""Representation of a Verisure camera.""" """Representation of a Verisure camera."""
def __init__(self, hass, device_label, directory_path): def __init__(self, hass: HomeAssistant, device_label: str, directory_path: str):
"""Initialize Verisure File Camera component.""" """Initialize Verisure File Camera component."""
super().__init__() super().__init__()
@ -39,7 +51,7 @@ class VerisureSmartcam(Camera):
self._image_id = None self._image_id = None
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, self.delete_image) hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, self.delete_image)
def camera_image(self): def camera_image(self) -> bytes | None:
"""Return image response.""" """Return image response."""
self.check_imagelist() self.check_imagelist()
if not self._image: if not self._image:
@ -49,7 +61,7 @@ class VerisureSmartcam(Camera):
with open(self._image, "rb") as file: with open(self._image, "rb") as file:
return file.read() return file.read()
def check_imagelist(self): def check_imagelist(self) -> None:
"""Check the contents of the image list.""" """Check the contents of the image list."""
hub.update_smartcam_imageseries() hub.update_smartcam_imageseries()
image_ids = hub.get_image_info( image_ids = hub.get_image_info(
@ -67,12 +79,12 @@ class VerisureSmartcam(Camera):
) )
hub.session.download_image(self._device_label, new_image_id, new_image_path) hub.session.download_image(self._device_label, new_image_id, new_image_path)
LOGGER.debug("Old image_id=%s", self._image_id) LOGGER.debug("Old image_id=%s", self._image_id)
self.delete_image(self) self.delete_image()
self._image_id = new_image_id self._image_id = new_image_id
self._image = new_image_path self._image = new_image_path
def delete_image(self, event): def delete_image(self) -> None:
"""Delete an old image.""" """Delete an old image."""
remove_image = os.path.join( remove_image = os.path.join(
self._directory_path, "{}{}".format(self._image_id, ".jpg") self._directory_path, "{}{}".format(self._image_id, ".jpg")
@ -85,7 +97,7 @@ class VerisureSmartcam(Camera):
raise raise
@property @property
def name(self): def name(self) -> str:
"""Return the name of this camera.""" """Return the name of this camera."""
return hub.get_first( return hub.get_first(
"$.customerImageCameras[?(@.deviceLabel=='%s')].area", self._device_label "$.customerImageCameras[?(@.deviceLabel=='%s')].area", self._device_label

View File

@ -1,14 +1,24 @@
"""Support for Verisure locks.""" """Support for Verisure locks."""
from __future__ import annotations
from time import monotonic, sleep from time import monotonic, sleep
from typing import Any, Callable
from homeassistant.components.lock import LockEntity from homeassistant.components.lock import LockEntity
from homeassistant.const import ATTR_CODE, STATE_LOCKED, STATE_UNLOCKED from homeassistant.const import ATTR_CODE, STATE_LOCKED, STATE_UNLOCKED
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity
from . import HUB as hub from . import HUB as hub
from .const import CONF_CODE_DIGITS, CONF_DEFAULT_LOCK_CODE, CONF_LOCKS, LOGGER from .const import CONF_CODE_DIGITS, CONF_DEFAULT_LOCK_CODE, CONF_LOCKS, LOGGER
def setup_platform(hass, config, add_entities, discovery_info=None): def setup_platform(
hass: HomeAssistant,
config: dict[str, Any],
add_entities: Callable[[list[Entity], bool], None],
discovery_info: dict[str, Any] | None = None,
) -> None:
"""Set up the Verisure lock platform.""" """Set up the Verisure lock platform."""
locks = [] locks = []
if int(hub.config.get(CONF_LOCKS, 1)): if int(hub.config.get(CONF_LOCKS, 1)):
@ -26,7 +36,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
class VerisureDoorlock(LockEntity): class VerisureDoorlock(LockEntity):
"""Representation of a Verisure doorlock.""" """Representation of a Verisure doorlock."""
def __init__(self, device_label): def __init__(self, device_label: str):
"""Initialize the Verisure lock.""" """Initialize the Verisure lock."""
self._device_label = device_label self._device_label = device_label
self._state = None self._state = None
@ -36,19 +46,19 @@ class VerisureDoorlock(LockEntity):
self._default_lock_code = hub.config.get(CONF_DEFAULT_LOCK_CODE) self._default_lock_code = hub.config.get(CONF_DEFAULT_LOCK_CODE)
@property @property
def name(self): def name(self) -> str:
"""Return the name of the lock.""" """Return the name of the lock."""
return hub.get_first( return hub.get_first(
"$.doorLockStatusList[?(@.deviceLabel=='%s')].area", self._device_label "$.doorLockStatusList[?(@.deviceLabel=='%s')].area", self._device_label
) )
@property @property
def state(self): def state(self) -> str | None:
"""Return the state of the lock.""" """Return the state of the lock."""
return self._state return self._state
@property @property
def available(self): def available(self) -> bool:
"""Return True if entity is available.""" """Return True if entity is available."""
return ( return (
hub.get_first( hub.get_first(
@ -58,16 +68,16 @@ class VerisureDoorlock(LockEntity):
) )
@property @property
def changed_by(self): def changed_by(self) -> str | None:
"""Last change triggered by.""" """Last change triggered by."""
return self._changed_by return self._changed_by
@property @property
def code_format(self): def code_format(self) -> str:
"""Return the required six digit code.""" """Return the required six digit code."""
return "^\\d{%s}$" % self._digits return "^\\d{%s}$" % self._digits
def update(self): def update(self) -> None:
"""Update lock status.""" """Update lock status."""
if monotonic() - self._change_timestamp < 10: if monotonic() - self._change_timestamp < 10:
return return
@ -88,11 +98,11 @@ class VerisureDoorlock(LockEntity):
) )
@property @property
def is_locked(self): def is_locked(self) -> bool:
"""Return true if lock is locked.""" """Return true if lock is locked."""
return self._state == STATE_LOCKED return self._state == STATE_LOCKED
def unlock(self, **kwargs): def unlock(self, **kwargs) -> None:
"""Send unlock command.""" """Send unlock command."""
if self._state is None: if self._state is None:
return return
@ -104,7 +114,7 @@ class VerisureDoorlock(LockEntity):
self.set_lock_state(code, STATE_UNLOCKED) self.set_lock_state(code, STATE_UNLOCKED)
def lock(self, **kwargs): def lock(self, **kwargs) -> None:
"""Send lock command.""" """Send lock command."""
if self._state == STATE_LOCKED: if self._state == STATE_LOCKED:
return return
@ -116,7 +126,7 @@ class VerisureDoorlock(LockEntity):
self.set_lock_state(code, STATE_LOCKED) self.set_lock_state(code, STATE_LOCKED)
def set_lock_state(self, code, state): def set_lock_state(self, code: str, state: str) -> None:
"""Send set lock state command.""" """Send set lock state command."""
lock_state = "lock" if state == STATE_LOCKED else "unlock" lock_state = "lock" if state == STATE_LOCKED else "unlock"
transaction_id = hub.session.set_lock_state( transaction_id = hub.session.set_lock_state(

View File

@ -1,12 +1,22 @@
"""Support for Verisure sensors.""" """Support for Verisure sensors."""
from __future__ import annotations
from typing import Any, Callable
from homeassistant.const import PERCENTAGE, TEMP_CELSIUS from homeassistant.const import PERCENTAGE, TEMP_CELSIUS
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from . import HUB as hub from . import HUB as hub
from .const import CONF_HYDROMETERS, CONF_MOUSE, CONF_THERMOMETERS from .const import CONF_HYDROMETERS, CONF_MOUSE, CONF_THERMOMETERS
def setup_platform(hass, config, add_entities, discovery_info=None): def setup_platform(
hass: HomeAssistant,
config: dict[str, Any],
add_entities: Callable[[list[Entity], bool], None],
discovery_info: dict[str, Any] | None = None,
) -> None:
"""Set up the Verisure platform.""" """Set up the Verisure platform."""
sensors = [] sensors = []
hub.update_overview() hub.update_overview()
@ -47,12 +57,12 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
class VerisureThermometer(Entity): class VerisureThermometer(Entity):
"""Representation of a Verisure thermometer.""" """Representation of a Verisure thermometer."""
def __init__(self, device_label): def __init__(self, device_label: str):
"""Initialize the sensor.""" """Initialize the sensor."""
self._device_label = device_label self._device_label = device_label
@property @property
def name(self): def name(self) -> str:
"""Return the name of the device.""" """Return the name of the device."""
return ( return (
hub.get_first( hub.get_first(
@ -62,14 +72,14 @@ class VerisureThermometer(Entity):
) )
@property @property
def state(self): def state(self) -> str | None:
"""Return the state of the device.""" """Return the state of the device."""
return hub.get_first( return hub.get_first(
"$.climateValues[?(@.deviceLabel=='%s')].temperature", self._device_label "$.climateValues[?(@.deviceLabel=='%s')].temperature", self._device_label
) )
@property @property
def available(self): def available(self) -> bool:
"""Return True if entity is available.""" """Return True if entity is available."""
return ( return (
hub.get_first( hub.get_first(
@ -80,12 +90,12 @@ class VerisureThermometer(Entity):
) )
@property @property
def unit_of_measurement(self): def unit_of_measurement(self) -> str:
"""Return the unit of measurement of this entity.""" """Return the unit of measurement of this entity."""
return TEMP_CELSIUS return TEMP_CELSIUS
# pylint: disable=no-self-use # pylint: disable=no-self-use
def update(self): def update(self) -> None:
"""Update the sensor.""" """Update the sensor."""
hub.update_overview() hub.update_overview()
@ -93,12 +103,12 @@ class VerisureThermometer(Entity):
class VerisureHygrometer(Entity): class VerisureHygrometer(Entity):
"""Representation of a Verisure hygrometer.""" """Representation of a Verisure hygrometer."""
def __init__(self, device_label): def __init__(self, device_label: str):
"""Initialize the sensor.""" """Initialize the sensor."""
self._device_label = device_label self._device_label = device_label
@property @property
def name(self): def name(self) -> str:
"""Return the name of the device.""" """Return the name of the device."""
return ( return (
hub.get_first( hub.get_first(
@ -108,14 +118,14 @@ class VerisureHygrometer(Entity):
) )
@property @property
def state(self): def state(self) -> str | None:
"""Return the state of the device.""" """Return the state of the device."""
return hub.get_first( return hub.get_first(
"$.climateValues[?(@.deviceLabel=='%s')].humidity", self._device_label "$.climateValues[?(@.deviceLabel=='%s')].humidity", self._device_label
) )
@property @property
def available(self): def available(self) -> bool:
"""Return True if entity is available.""" """Return True if entity is available."""
return ( return (
hub.get_first( hub.get_first(
@ -125,12 +135,12 @@ class VerisureHygrometer(Entity):
) )
@property @property
def unit_of_measurement(self): def unit_of_measurement(self) -> str:
"""Return the unit of measurement of this entity.""" """Return the unit of measurement of this entity."""
return PERCENTAGE return PERCENTAGE
# pylint: disable=no-self-use # pylint: disable=no-self-use
def update(self): def update(self) -> None:
"""Update the sensor.""" """Update the sensor."""
hub.update_overview() hub.update_overview()
@ -143,7 +153,7 @@ class VerisureMouseDetection(Entity):
self._device_label = device_label self._device_label = device_label
@property @property
def name(self): def name(self) -> str:
"""Return the name of the device.""" """Return the name of the device."""
return ( return (
hub.get_first( hub.get_first(
@ -153,14 +163,14 @@ class VerisureMouseDetection(Entity):
) )
@property @property
def state(self): def state(self) -> str | None:
"""Return the state of the device.""" """Return the state of the device."""
return hub.get_first( return hub.get_first(
"$.eventCounts[?(@.deviceLabel=='%s')].detections", self._device_label "$.eventCounts[?(@.deviceLabel=='%s')].detections", self._device_label
) )
@property @property
def available(self): def available(self) -> bool:
"""Return True if entity is available.""" """Return True if entity is available."""
return ( return (
hub.get_first("$.eventCounts[?(@.deviceLabel=='%s')]", self._device_label) hub.get_first("$.eventCounts[?(@.deviceLabel=='%s')]", self._device_label)
@ -168,11 +178,11 @@ class VerisureMouseDetection(Entity):
) )
@property @property
def unit_of_measurement(self): def unit_of_measurement(self) -> str:
"""Return the unit of measurement of this entity.""" """Return the unit of measurement of this entity."""
return "Mice" return "Mice"
# pylint: disable=no-self-use # pylint: disable=no-self-use
def update(self): def update(self) -> None:
"""Update the sensor.""" """Update the sensor."""
hub.update_overview() hub.update_overview()

View File

@ -1,45 +1,53 @@
"""Support for Verisure Smartplugs.""" """Support for Verisure Smartplugs."""
from __future__ import annotations
from time import monotonic from time import monotonic
from typing import Any, Callable, Literal
from homeassistant.components.switch import SwitchEntity from homeassistant.components.switch import SwitchEntity
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity
from . import CONF_SMARTPLUGS, HUB as hub from . import CONF_SMARTPLUGS, HUB as hub
def setup_platform(hass, config, add_entities, discovery_info=None): def setup_platform(
hass: HomeAssistant,
config: dict[str, Any],
add_entities: Callable[[list[Entity], bool], None],
discovery_info: dict[str, Any] | None = None,
) -> None | Literal[False]:
"""Set up the Verisure switch platform.""" """Set up the Verisure switch platform."""
if not int(hub.config.get(CONF_SMARTPLUGS, 1)): if not int(hub.config.get(CONF_SMARTPLUGS, 1)):
return False return False
hub.update_overview() hub.update_overview()
switches = [] switches = [
switches.extend(
[
VerisureSmartplug(device_label) VerisureSmartplug(device_label)
for device_label in hub.get("$.smartPlugs[*].deviceLabel") for device_label in hub.get("$.smartPlugs[*].deviceLabel")
] ]
)
add_entities(switches) add_entities(switches)
class VerisureSmartplug(SwitchEntity): class VerisureSmartplug(SwitchEntity):
"""Representation of a Verisure smartplug.""" """Representation of a Verisure smartplug."""
def __init__(self, device_id): def __init__(self, device_id: str):
"""Initialize the Verisure device.""" """Initialize the Verisure device."""
self._device_label = device_id self._device_label = device_id
self._change_timestamp = 0 self._change_timestamp = 0
self._state = False self._state = False
@property @property
def name(self): def name(self) -> str:
"""Return the name or location of the smartplug.""" """Return the name or location of the smartplug."""
return hub.get_first( return hub.get_first(
"$.smartPlugs[?(@.deviceLabel == '%s')].area", self._device_label "$.smartPlugs[?(@.deviceLabel == '%s')].area", self._device_label
) )
@property @property
def is_on(self): def is_on(self) -> bool:
"""Return true if on.""" """Return true if on."""
if monotonic() - self._change_timestamp < 10: if monotonic() - self._change_timestamp < 10:
return self._state return self._state
@ -53,26 +61,26 @@ class VerisureSmartplug(SwitchEntity):
return self._state return self._state
@property @property
def available(self): def available(self) -> bool:
"""Return True if entity is available.""" """Return True if entity is available."""
return ( return (
hub.get_first("$.smartPlugs[?(@.deviceLabel == '%s')]", self._device_label) hub.get_first("$.smartPlugs[?(@.deviceLabel == '%s')]", self._device_label)
is not None is not None
) )
def turn_on(self, **kwargs): def turn_on(self, **kwargs) -> None:
"""Set smartplug status on.""" """Set smartplug status on."""
hub.session.set_smartplug_state(self._device_label, True) hub.session.set_smartplug_state(self._device_label, True)
self._state = True self._state = True
self._change_timestamp = monotonic() self._change_timestamp = monotonic()
def turn_off(self, **kwargs): def turn_off(self, **kwargs) -> None:
"""Set smartplug status off.""" """Set smartplug status off."""
hub.session.set_smartplug_state(self._device_label, False) hub.session.set_smartplug_state(self._device_label, False)
self._state = False self._state = False
self._change_timestamp = monotonic() self._change_timestamp = monotonic()
# pylint: disable=no-self-use # pylint: disable=no-self-use
def update(self): def update(self) -> None:
"""Get the latest date of the smartplug.""" """Get the latest date of the smartplug."""
hub.update_overview() hub.update_overview()