Initial Verisure cleanups (#44639)

This commit is contained in:
Franck Nijhof 2020-12-30 09:55:18 +01:00 committed by GitHub
parent 9cc768b34c
commit ee194b9411
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 92 additions and 77 deletions

View File

@ -493,6 +493,7 @@ homeassistant/components/utility_meter/* @dgomes
homeassistant/components/velbus/* @Cereal2nd @brefra homeassistant/components/velbus/* @Cereal2nd @brefra
homeassistant/components/velux/* @Julius2342 homeassistant/components/velux/* @Julius2342
homeassistant/components/vera/* @vangorra homeassistant/components/vera/* @vangorra
homeassistant/components/verisure/* @frenck
homeassistant/components/versasense/* @flamm3blemuff1n homeassistant/components/versasense/* @flamm3blemuff1n
homeassistant/components/version/* @fabaff @ludeeus homeassistant/components/version/* @fabaff @ludeeus
homeassistant/components/vesync/* @markperdue @webdjoe @thegardenmonkey homeassistant/components/vesync/* @markperdue @webdjoe @thegardenmonkey

View File

@ -1,7 +1,5 @@
"""Support for Verisure devices.""" """Support for Verisure devices."""
from datetime import timedelta from datetime import timedelta
import logging
import threading
from jsonpath import jsonpath from jsonpath import jsonpath
import verisure import verisure
@ -18,30 +16,27 @@ from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.util import Throttle from homeassistant.util import Throttle
_LOGGER = logging.getLogger(__name__) from .const import (
ATTR_DEVICE_SERIAL,
ATTR_DEVICE_SERIAL = "device_serial" CONF_ALARM,
CONF_CODE_DIGITS,
CONF_ALARM = "alarm" CONF_DEFAULT_LOCK_CODE,
CONF_CODE_DIGITS = "code_digits" CONF_DOOR_WINDOW,
CONF_DOOR_WINDOW = "door_window" CONF_GIID,
CONF_GIID = "giid" CONF_HYDROMETERS,
CONF_HYDROMETERS = "hygrometers" CONF_LOCKS,
CONF_LOCKS = "locks" CONF_MOUSE,
CONF_DEFAULT_LOCK_CODE = "default_lock_code" CONF_SMARTCAM,
CONF_MOUSE = "mouse" CONF_SMARTPLUGS,
CONF_SMARTPLUGS = "smartplugs" CONF_THERMOMETERS,
CONF_THERMOMETERS = "thermometers" DEFAULT_SCAN_INTERVAL,
CONF_SMARTCAM = "smartcam" DOMAIN,
LOGGER,
DOMAIN = "verisure" MIN_SCAN_INTERVAL,
SERVICE_CAPTURE_SMARTCAM,
MIN_SCAN_INTERVAL = timedelta(minutes=1) SERVICE_DISABLE_AUTOLOCK,
DEFAULT_SCAN_INTERVAL = timedelta(minutes=1) SERVICE_ENABLE_AUTOLOCK,
)
SERVICE_CAPTURE_SMARTCAM = "capture_smartcam"
SERVICE_DISABLE_AUTOLOCK = "disable_autolock"
SERVICE_ENABLE_AUTOLOCK = "enable_autolock"
HUB = None HUB = None
@ -101,9 +96,9 @@ def setup(hass, config):
device_id = service.data[ATTR_DEVICE_SERIAL] device_id = service.data[ATTR_DEVICE_SERIAL]
try: try:
await hass.async_add_executor_job(HUB.smartcam_capture, device_id) await hass.async_add_executor_job(HUB.smartcam_capture, device_id)
_LOGGER.debug("Capturing new image from %s", ATTR_DEVICE_SERIAL) LOGGER.debug("Capturing new image from %s", ATTR_DEVICE_SERIAL)
except verisure.Error as ex: except verisure.Error as ex:
_LOGGER.error("Could not capture image, %s", ex) LOGGER.error("Could not capture image, %s", ex)
hass.services.register( hass.services.register(
DOMAIN, SERVICE_CAPTURE_SMARTCAM, capture_smartcam, schema=DEVICE_SERIAL_SCHEMA DOMAIN, SERVICE_CAPTURE_SMARTCAM, capture_smartcam, schema=DEVICE_SERIAL_SCHEMA
@ -114,9 +109,9 @@ def setup(hass, config):
device_id = service.data[ATTR_DEVICE_SERIAL] device_id = service.data[ATTR_DEVICE_SERIAL]
try: try:
await hass.async_add_executor_job(HUB.disable_autolock, device_id) await hass.async_add_executor_job(HUB.disable_autolock, device_id)
_LOGGER.debug("Disabling autolock on%s", ATTR_DEVICE_SERIAL) LOGGER.debug("Disabling autolock on%s", ATTR_DEVICE_SERIAL)
except verisure.Error as ex: except verisure.Error as ex:
_LOGGER.error("Could not disable autolock, %s", ex) LOGGER.error("Could not disable autolock, %s", ex)
hass.services.register( hass.services.register(
DOMAIN, SERVICE_DISABLE_AUTOLOCK, disable_autolock, schema=DEVICE_SERIAL_SCHEMA DOMAIN, SERVICE_DISABLE_AUTOLOCK, disable_autolock, schema=DEVICE_SERIAL_SCHEMA
@ -127,9 +122,9 @@ def setup(hass, config):
device_id = service.data[ATTR_DEVICE_SERIAL] device_id = service.data[ATTR_DEVICE_SERIAL]
try: try:
await hass.async_add_executor_job(HUB.enable_autolock, device_id) await hass.async_add_executor_job(HUB.enable_autolock, device_id)
_LOGGER.debug("Enabling autolock on %s", ATTR_DEVICE_SERIAL) LOGGER.debug("Enabling autolock on %s", ATTR_DEVICE_SERIAL)
except verisure.Error as ex: except verisure.Error as ex:
_LOGGER.error("Could not enable autolock, %s", ex) LOGGER.error("Could not enable autolock, %s", ex)
hass.services.register( hass.services.register(
DOMAIN, SERVICE_ENABLE_AUTOLOCK, enable_autolock, schema=DEVICE_SERIAL_SCHEMA DOMAIN, SERVICE_ENABLE_AUTOLOCK, enable_autolock, schema=DEVICE_SERIAL_SCHEMA
@ -147,8 +142,6 @@ class VerisureHub:
self.config = domain_config self.config = domain_config
self._lock = threading.Lock()
self.session = verisure.Session( self.session = verisure.Session(
domain_config[CONF_USERNAME], domain_config[CONF_PASSWORD] domain_config[CONF_USERNAME], domain_config[CONF_PASSWORD]
) )
@ -160,7 +153,7 @@ class VerisureHub:
try: try:
self.session.login() self.session.login()
except verisure.Error as ex: except verisure.Error as ex:
_LOGGER.error("Could not log in to verisure, %s", ex) LOGGER.error("Could not log in to verisure, %s", ex)
return False return False
if self.giid: if self.giid:
return self.set_giid() return self.set_giid()
@ -171,7 +164,7 @@ class VerisureHub:
try: try:
self.session.logout() self.session.logout()
except verisure.Error as ex: except verisure.Error as ex:
_LOGGER.error("Could not log out from verisure, %s", ex) LOGGER.error("Could not log out from verisure, %s", ex)
return False return False
return True return True
@ -180,7 +173,7 @@ class VerisureHub:
try: try:
self.session.set_giid(self.giid) self.session.set_giid(self.giid)
except verisure.Error as ex: except verisure.Error as ex:
_LOGGER.error("Could not set installation GIID, %s", ex) LOGGER.error("Could not set installation GIID, %s", ex)
return False return False
return True return True
@ -189,9 +182,9 @@ class VerisureHub:
try: try:
self.overview = self.session.get_overview() self.overview = self.session.get_overview()
except verisure.ResponseError as ex: except verisure.ResponseError as ex:
_LOGGER.error("Could not read overview, %s", ex) LOGGER.error("Could not read overview, %s", ex)
if ex.status_code == HTTP_SERVICE_UNAVAILABLE: # Service unavailable if ex.status_code == HTTP_SERVICE_UNAVAILABLE: # Service unavailable
_LOGGER.info("Trying to log in again") LOGGER.info("Trying to log in again")
self.login() self.login()
else: else:
raise raise
@ -217,7 +210,7 @@ class VerisureHub:
def get(self, jpath, *args): def get(self, jpath, *args):
"""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 if res else [] return res or []
def get_first(self, jpath, *args): def get_first(self, jpath, *args):
"""Get first value from the overview that matches the jsonpath.""" """Get first value from the overview that matches the jsonpath."""
@ -227,4 +220,4 @@ class VerisureHub:
def get_image_info(self, jpath, *args): def get_image_info(self, jpath, *args):
"""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 if res else [] return res or []

View File

@ -1,5 +1,4 @@
"""Support for Verisure alarm control panels.""" """Support for Verisure alarm control panels."""
import logging
from time import sleep from time import sleep
import homeassistant.components.alarm_control_panel as alarm import homeassistant.components.alarm_control_panel as alarm
@ -13,9 +12,8 @@ from homeassistant.const import (
STATE_ALARM_DISARMED, STATE_ALARM_DISARMED,
) )
from . import CONF_ALARM, CONF_CODE_DIGITS, CONF_GIID, HUB as hub from . import HUB as hub
from .const import CONF_ALARM, CONF_CODE_DIGITS, CONF_GIID, LOGGER
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_entities, discovery_info=None): def setup_platform(hass, config, add_entities, discovery_info=None):
@ -32,12 +30,12 @@ def set_arm_state(state, code=None):
transaction_id = hub.session.set_arm_state(code, state)[ transaction_id = hub.session.set_arm_state(code, state)[
"armStateChangeTransactionId" "armStateChangeTransactionId"
] ]
_LOGGER.info("verisure set arm state %s", state) LOGGER.info("verisure set arm state %s", state)
transaction = {} transaction = {}
while "result" not in transaction: while "result" not in transaction:
sleep(0.5) sleep(0.5)
transaction = hub.session.get_arm_state_transaction(transaction_id) transaction = hub.session.get_arm_state_transaction(transaction_id)
hub.update_overview(no_throttle=True) hub.update_overview()
class VerisureAlarm(alarm.AlarmControlPanelEntity): class VerisureAlarm(alarm.AlarmControlPanelEntity):
@ -58,7 +56,7 @@ class VerisureAlarm(alarm.AlarmControlPanelEntity):
if giid in aliass: if giid in aliass:
return "{} alarm".format(aliass[giid]) return "{} alarm".format(aliass[giid])
_LOGGER.error("Verisure installation giid not found: %s", giid) LOGGER.error("Verisure installation giid not found: %s", giid)
return "{} alarm".format(hub.session.installations[0]["alias"]) return "{} alarm".format(hub.session.installations[0]["alias"])
@ -93,7 +91,7 @@ class VerisureAlarm(alarm.AlarmControlPanelEntity):
elif status == "ARMED_AWAY": elif status == "ARMED_AWAY":
self._state = STATE_ALARM_ARMED_AWAY self._state = STATE_ALARM_ARMED_AWAY
elif status != "PENDING": elif status != "PENDING":
_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=None):

View File

@ -1,14 +1,12 @@
"""Support for Verisure cameras.""" """Support for Verisure cameras."""
import errno import errno
import logging
import os import os
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 . import CONF_SMARTCAM, HUB as hub from . import HUB as hub
from .const import CONF_SMARTCAM, LOGGER
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_entities, discovery_info=None): def setup_platform(hass, config, add_entities, discovery_info=None):
@ -17,16 +15,14 @@ def setup_platform(hass, config, add_entities, discovery_info=None):
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 = [
smartcams.extend( VerisureSmartcam(hass, device_label, directory_path)
[ for device_label in hub.get("$.customerImageCameras[*].deviceLabel")
VerisureSmartcam(hass, device_label, directory_path) ]
for device_label in hub.get("$.customerImageCameras[*].deviceLabel")
]
)
add_entities(smartcams) add_entities(smartcams)
@ -47,9 +43,9 @@ class VerisureSmartcam(Camera):
"""Return image response.""" """Return image response."""
self.check_imagelist() self.check_imagelist()
if not self._image: if not self._image:
_LOGGER.debug("No image to display") LOGGER.debug("No image to display")
return return
_LOGGER.debug("Trying to open %s", self._image) LOGGER.debug("Trying to open %s", self._image)
with open(self._image, "rb") as file: with open(self._image, "rb") as file:
return file.read() return file.read()
@ -63,14 +59,14 @@ class VerisureSmartcam(Camera):
return return
new_image_id = image_ids[0] new_image_id = image_ids[0]
if new_image_id in ("-1", self._image_id): if new_image_id in ("-1", self._image_id):
_LOGGER.debug("The image is the same, or loading image_id") LOGGER.debug("The image is the same, or loading image_id")
return return
_LOGGER.debug("Download new image %s", new_image_id) LOGGER.debug("Download new image %s", new_image_id)
new_image_path = os.path.join( new_image_path = os.path.join(
self._directory_path, "{}{}".format(new_image_id, ".jpg") self._directory_path, "{}{}".format(new_image_id, ".jpg")
) )
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)
self._image_id = new_image_id self._image_id = new_image_id
@ -83,7 +79,7 @@ class VerisureSmartcam(Camera):
) )
try: try:
os.remove(remove_image) os.remove(remove_image)
_LOGGER.debug("Deleting old image %s", remove_image) LOGGER.debug("Deleting old image %s", remove_image)
except OSError as error: except OSError as error:
if error.errno != errno.ENOENT: if error.errno != errno.ENOENT:
raise raise

View File

@ -0,0 +1,28 @@
"""Constants for the Verisure integration."""
from datetime import timedelta
import logging
DOMAIN = "verisure"
LOGGER = logging.getLogger(__package__)
ATTR_DEVICE_SERIAL = "device_serial"
CONF_ALARM = "alarm"
CONF_CODE_DIGITS = "code_digits"
CONF_DOOR_WINDOW = "door_window"
CONF_GIID = "giid"
CONF_HYDROMETERS = "hygrometers"
CONF_LOCKS = "locks"
CONF_DEFAULT_LOCK_CODE = "default_lock_code"
CONF_MOUSE = "mouse"
CONF_SMARTPLUGS = "smartplugs"
CONF_THERMOMETERS = "thermometers"
CONF_SMARTCAM = "smartcam"
DEFAULT_SCAN_INTERVAL = timedelta(minutes=1)
MIN_SCAN_INTERVAL = timedelta(minutes=1)
SERVICE_CAPTURE_SMARTCAM = "capture_smartcam"
SERVICE_DISABLE_AUTOLOCK = "disable_autolock"
SERVICE_ENABLE_AUTOLOCK = "enable_autolock"

View File

@ -1,13 +1,11 @@
"""Support for Verisure locks.""" """Support for Verisure locks."""
import logging
from time import monotonic, sleep from time import monotonic, sleep
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 . import CONF_CODE_DIGITS, CONF_DEFAULT_LOCK_CODE, CONF_LOCKS, HUB as hub from . import HUB as hub
from .const import CONF_CODE_DIGITS, CONF_DEFAULT_LOCK_CODE, CONF_LOCKS, LOGGER
_LOGGER = logging.getLogger(__name__)
def setup_platform(hass, config, add_entities, discovery_info=None): def setup_platform(hass, config, add_entities, discovery_info=None):
@ -83,7 +81,7 @@ class VerisureDoorlock(LockEntity):
elif status == "LOCKED": elif status == "LOCKED":
self._state = STATE_LOCKED self._state = STATE_LOCKED
elif status != "PENDING": elif status != "PENDING":
_LOGGER.error("Unknown lock state %s", status) LOGGER.error("Unknown lock state %s", status)
self._changed_by = hub.get_first( self._changed_by = hub.get_first(
"$.doorLockStatusList[?(@.deviceLabel=='%s')].userString", "$.doorLockStatusList[?(@.deviceLabel=='%s')].userString",
self._device_label, self._device_label,
@ -101,7 +99,7 @@ class VerisureDoorlock(LockEntity):
code = kwargs.get(ATTR_CODE, self._default_lock_code) code = kwargs.get(ATTR_CODE, self._default_lock_code)
if code is None: if code is None:
_LOGGER.error("Code required but none provided") LOGGER.error("Code required but none provided")
return return
self.set_lock_state(code, STATE_UNLOCKED) self.set_lock_state(code, STATE_UNLOCKED)
@ -113,7 +111,7 @@ class VerisureDoorlock(LockEntity):
code = kwargs.get(ATTR_CODE, self._default_lock_code) code = kwargs.get(ATTR_CODE, self._default_lock_code)
if code is None: if code is None:
_LOGGER.error("Code required but none provided") LOGGER.error("Code required but none provided")
return return
self.set_lock_state(code, STATE_LOCKED) self.set_lock_state(code, STATE_LOCKED)
@ -124,7 +122,7 @@ class VerisureDoorlock(LockEntity):
transaction_id = hub.session.set_lock_state( transaction_id = hub.session.set_lock_state(
code, self._device_label, lock_state code, self._device_label, lock_state
)["doorLockStateChangeTransactionId"] )["doorLockStateChangeTransactionId"]
_LOGGER.debug("Verisure doorlock %s", state) LOGGER.debug("Verisure doorlock %s", state)
transaction = {} transaction = {}
attempts = 0 attempts = 0
while "result" not in transaction: while "result" not in transaction:

View File

@ -3,5 +3,5 @@
"name": "Verisure", "name": "Verisure",
"documentation": "https://www.home-assistant.io/integrations/verisure", "documentation": "https://www.home-assistant.io/integrations/verisure",
"requirements": ["jsonpath==0.82", "vsure==1.5.4"], "requirements": ["jsonpath==0.82", "vsure==1.5.4"],
"codeowners": [] "codeowners": ["@frenck"]
} }

View File

@ -2,7 +2,8 @@
from homeassistant.const import PERCENTAGE, TEMP_CELSIUS from homeassistant.const import PERCENTAGE, TEMP_CELSIUS
from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity import Entity
from . import CONF_HYDROMETERS, CONF_MOUSE, CONF_THERMOMETERS, HUB as hub from . import HUB as hub
from .const import CONF_HYDROMETERS, CONF_MOUSE, CONF_THERMOMETERS
def setup_platform(hass, config, add_entities, discovery_info=None): def setup_platform(hass, config, add_entities, discovery_info=None):