diff --git a/homeassistant/components/alarm_control_panel/verisure.py b/homeassistant/components/alarm_control_panel/verisure.py index 32f28865a41..66764f58c26 100644 --- a/homeassistant/components/alarm_control_panel/verisure.py +++ b/homeassistant/components/alarm_control_panel/verisure.py @@ -5,6 +5,7 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/alarm_control_panel.verisure/ """ import logging +from time import sleep import homeassistant.components.alarm_control_panel as alarm from homeassistant.components.verisure import HUB as hub @@ -20,20 +21,29 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Verisure platform.""" alarms = [] if int(hub.config.get(CONF_ALARM, 1)): - hub.update_alarms() - alarms.extend([ - VerisureAlarm(value.id) - for value in hub.alarm_status.values() - ]) + hub.update_overview() + alarms.append(VerisureAlarm()) add_devices(alarms) +def set_arm_state(state, code=None): + """Send set arm state command.""" + transaction_id = hub.session.set_arm_state(code, state)[ + 'armStateChangeTransactionId'] + _LOGGER.info('verisure set arm state %s', state) + transaction = {} + while 'result' not in transaction: + sleep(0.5) + transaction = hub.session.get_arm_state_transaction(transaction_id) + # pylint: disable=unexpected-keyword-arg + hub.update_overview(no_throttle=True) + + class VerisureAlarm(alarm.AlarmControlPanel): """Representation of a Verisure alarm status.""" - def __init__(self, device_id): - """Initialize the Verisure alarm panel.""" - self._id = device_id + def __init__(self): + """Initalize the Verisure alarm panel.""" self._state = STATE_UNKNOWN self._digits = hub.config.get(CONF_CODE_DIGITS) self._changed_by = None @@ -41,18 +51,13 @@ class VerisureAlarm(alarm.AlarmControlPanel): @property def name(self): """Return the name of the device.""" - return 'Alarm {}'.format(self._id) + return '{} alarm'.format(hub.session.installations[0]['alias']) @property def state(self): """Return the state of the device.""" return self._state - @property - def available(self): - """Return True if entity is available.""" - return hub.available - @property def code_format(self): """Return the code format as regex.""" @@ -65,33 +70,26 @@ class VerisureAlarm(alarm.AlarmControlPanel): def update(self): """Update alarm status.""" - hub.update_alarms() - - if hub.alarm_status[self._id].status == 'unarmed': + hub.update_overview() + status = hub.get_first("$.armState.statusType") + if status == 'DISARMED': self._state = STATE_ALARM_DISARMED - elif hub.alarm_status[self._id].status == 'armedhome': + elif status == 'ARMED_HOME': self._state = STATE_ALARM_ARMED_HOME - elif hub.alarm_status[self._id].status == 'armed': + elif status == 'ARMED_AWAY': self._state = STATE_ALARM_ARMED_AWAY - elif hub.alarm_status[self._id].status != 'pending': - _LOGGER.error( - "Unknown alarm state %s", hub.alarm_status[self._id].status) - self._changed_by = hub.alarm_status[self._id].name + elif status != 'PENDING': + _LOGGER.error('Unknown alarm state %s', status) + self._changed_by = hub.get_first("$.armState.name") def alarm_disarm(self, code=None): """Send disarm command.""" - hub.my_pages.alarm.set(code, 'DISARMED') - _LOGGER.info("Verisure alarm disarming") - hub.my_pages.alarm.wait_while_pending() + set_arm_state('DISARMED', code) def alarm_arm_home(self, code=None): """Send arm home command.""" - hub.my_pages.alarm.set(code, 'ARMED_HOME') - _LOGGER.info("Verisure alarm arming home") - hub.my_pages.alarm.wait_while_pending() + set_arm_state('ARMED_HOME', code) def alarm_arm_away(self, code=None): """Send arm away command.""" - hub.my_pages.alarm.set(code, 'ARMED_AWAY') - _LOGGER.info("Verisure alarm arming away") - hub.my_pages.alarm.wait_while_pending() + set_arm_state('ARMED_AWAY', code) diff --git a/homeassistant/components/binary_sensor/verisure.py b/homeassistant/components/binary_sensor/verisure.py new file mode 100644 index 00000000000..f6c0123ad0a --- /dev/null +++ b/homeassistant/components/binary_sensor/verisure.py @@ -0,0 +1,59 @@ +""" +Interfaces with Verisure sensors. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/binary_sensor.verisure/ +""" +import logging + +from homeassistant.components.verisure import HUB as hub +from homeassistant.components.binary_sensor import BinarySensorDevice +from homeassistant.components.verisure import CONF_DOOR_WINDOW + +_LOGGER = logging.getLogger(__name__) + + +def setup_platform(hass, config, add_devices, discovery_info=None): + """Setup Verisure binary sensors.""" + sensors = [] + hub.update_overview() + + if int(hub.config.get(CONF_DOOR_WINDOW, 1)): + sensors.extend([ + VerisureDoorWindowSensor(device_label) + for device_label in hub.get( + "$.doorWindow.doorWindowDevice[*].deviceLabel")]) + add_devices(sensors) + + +class VerisureDoorWindowSensor(BinarySensorDevice): + """Verisure door window sensor.""" + + def __init__(self, device_label): + """Initialize the modbus coil sensor.""" + self._device_label = device_label + + @property + def name(self): + """Return the name of the binary sensor.""" + return hub.get_first( + "$.doorWindow.doorWindowDevice[?(@.deviceLabel=='%s')].area", + self._device_label) + " door window" + + @property + def is_on(self): + """Return the state of the sensor.""" + return hub.get_first( + "$.doorWindow.doorWindowDevice[?(@.deviceLabel=='%s')].state", + self._device_label) == "OPEN" + + @property + def available(self): + """Return True if entity is available.""" + return hub.get_first( + "$.doorWindow.doorWindowDevice[?(@.deviceLabel=='%s')]", + self._device_label) is not None + + def update(self): + """Update the state of the sensor.""" + hub.update_overview() diff --git a/homeassistant/components/camera/verisure.py b/homeassistant/components/camera/verisure.py index 1c2e7e382fe..fbe91ad91a8 100644 --- a/homeassistant/components/camera/verisure.py +++ b/homeassistant/components/camera/verisure.py @@ -24,22 +24,23 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if not os.access(directory_path, os.R_OK): _LOGGER.error("file path %s is not readable", directory_path) return False - hub.update_smartcam() + hub.update_overview() smartcams = [] smartcams.extend([ - VerisureSmartcam(hass, value.deviceLabel, directory_path) - for value in hub.smartcam_status.values()]) + VerisureSmartcam(hass, device_label, directory_path) + for device_label in hub.get( + "$.customerImageCameras[*].deviceLabel")]) add_devices(smartcams) class VerisureSmartcam(Camera): """Representation of a Verisure camera.""" - def __init__(self, hass, device_id, directory_path): + def __init__(self, hass, device_label, directory_path): """Initialize Verisure File Camera component.""" super().__init__() - self._device_id = device_id + self._device_label = device_label self._directory_path = directory_path self._image = None self._image_id = None @@ -58,28 +59,27 @@ class VerisureSmartcam(Camera): def check_imagelist(self): """Check the contents of the image list.""" - hub.update_smartcam_imagelist() - if (self._device_id not in hub.smartcam_dict or - not hub.smartcam_dict[self._device_id]): + hub.update_smartcam_imageseries() + image_ids = hub.get_image_info( + "$.imageSeries[?(@.deviceLabel=='%s')].image[0].imageId", + self._device_label) + if not image_ids: return - images = hub.smartcam_dict[self._device_id] - new_image_id = images[0] - _LOGGER.debug("self._device_id=%s, self._images=%s, " - "self._new_image_id=%s", self._device_id, - images, new_image_id) + new_image_id = image_ids[0] if (new_image_id == '-1' or self._image_id == new_image_id): _LOGGER.debug("The image is the same, or loading image_id") return _LOGGER.debug("Download new image %s", new_image_id) - hub.my_pages.smartcam.download_image( - self._device_id, new_image_id, self._directory_path) + new_image_path = os.path.join( + self._directory_path, '{}{}'.format(new_image_id, '.jpg')) + hub.session.download_image( + self._device_label, new_image_id, new_image_path) _LOGGER.debug("Old image_id=%s", self._image_id) self.delete_image(self) self._image_id = new_image_id - self._image = os.path.join( - self._directory_path, '{}{}'.format(self._image_id, '.jpg')) + self._image = new_image_path def delete_image(self, event): """Delete an old image.""" @@ -95,4 +95,6 @@ class VerisureSmartcam(Camera): @property def name(self): """Return the name of this camera.""" - return hub.smartcam_status[self._device_id].location + return hub.get_first( + "$.customerImageCameras[?(@.deviceLabel=='%s')].area", + self._device_label) + " camera" diff --git a/homeassistant/components/lock/verisure.py b/homeassistant/components/lock/verisure.py index e4fa2104da6..7a24dd6bb37 100644 --- a/homeassistant/components/lock/verisure.py +++ b/homeassistant/components/lock/verisure.py @@ -5,7 +5,8 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/verisure/ """ import logging - +from time import sleep +from time import time from homeassistant.components.verisure import HUB as hub from homeassistant.components.verisure import (CONF_LOCKS, CONF_CODE_DIGITS) from homeassistant.components.lock import LockDevice @@ -19,28 +20,32 @@ def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Verisure platform.""" locks = [] if int(hub.config.get(CONF_LOCKS, 1)): - hub.update_locks() + hub.update_overview() locks.extend([ - VerisureDoorlock(device_id) - for device_id in hub.lock_status - ]) + VerisureDoorlock(device_label) + for device_label in hub.get( + "$.doorLockStatusList[*].deviceLabel")]) + add_devices(locks) class VerisureDoorlock(LockDevice): """Representation of a Verisure doorlock.""" - def __init__(self, device_id): + def __init__(self, device_label): """Initialize the Verisure lock.""" - self._id = device_id + self._device_label = device_label self._state = STATE_UNKNOWN self._digits = hub.config.get(CONF_CODE_DIGITS) self._changed_by = None + self._change_timestamp = 0 @property def name(self): """Return the name of the lock.""" - return '{}'.format(hub.lock_status[self._id].location) + return hub.get_first( + "$.doorLockStatusList[?(@.deviceLabel=='%s')].area", + self._device_label) + " lock" @property def state(self): @@ -50,7 +55,9 @@ class VerisureDoorlock(LockDevice): @property def available(self): """Return True if entity is available.""" - return hub.available + return hub.get_first( + "$.doorLockStatusList[?(@.deviceLabel=='%s')]", + self._device_label) is not None @property def changed_by(self): @@ -64,32 +71,52 @@ class VerisureDoorlock(LockDevice): def update(self): """Update lock status.""" - hub.update_locks() - - if hub.lock_status[self._id].status == 'unlocked': + if time() - self._change_timestamp < 10: + return + hub.update_overview() + status = hub.get_first( + "$.doorLockStatusList[?(@.deviceLabel=='%s')].lockedState", + self._device_label) + if status == 'UNLOCKED': self._state = STATE_UNLOCKED - elif hub.lock_status[self._id].status == 'locked': + elif status == 'LOCKED': self._state = STATE_LOCKED - elif hub.lock_status[self._id].status != 'pending': - _LOGGER.error( - "Unknown lock state %s", hub.lock_status[self._id].status) - self._changed_by = hub.lock_status[self._id].name + elif status != 'PENDING': + _LOGGER.error('Unknown lock state %s', status) + self._changed_by = hub.get_first( + "$.doorLockStatusList[?(@.deviceLabel=='%s')].userString", + self._device_label) @property def is_locked(self): """Return true if lock is locked.""" - return hub.lock_status[self._id].status + return self._state == STATE_LOCKED def unlock(self, **kwargs): """Send unlock command.""" - hub.my_pages.lock.set(kwargs[ATTR_CODE], self._id, 'UNLOCKED') - _LOGGER.debug("Verisure doorlock unlocking") - hub.my_pages.lock.wait_while_pending() - self.update() + if self._state == STATE_UNLOCKED: + return + self.set_lock_state(kwargs[ATTR_CODE], STATE_UNLOCKED) def lock(self, **kwargs): """Send lock command.""" - hub.my_pages.lock.set(kwargs[ATTR_CODE], self._id, 'LOCKED') - _LOGGER.debug("Verisure doorlock locking") - hub.my_pages.lock.wait_while_pending() - self.update() + if self._state == STATE_LOCKED: + return + self.set_lock_state(kwargs[ATTR_CODE], STATE_LOCKED) + + def set_lock_state(self, code, state): + """Send set lock state command.""" + lock_state = 'lock' if state == STATE_LOCKED else 'unlock' + transaction_id = hub.session.set_lock_state( + code, + self._device_label, + lock_state)['doorLockStateChangeTransactionId'] + _LOGGER.debug("Verisure doorlock %s", state) + transaction = {} + while 'result' not in transaction: + sleep(0.5) + transaction = hub.session.get_lock_state_transaction( + transaction_id) + if transaction['result'] == 'OK': + self._state = state + self._change_timestamp = time() diff --git a/homeassistant/components/sensor/verisure.py b/homeassistant/components/sensor/verisure.py index 4b22512fd4d..5ab999ccabf 100644 --- a/homeassistant/components/sensor/verisure.py +++ b/homeassistant/components/sensor/verisure.py @@ -18,31 +18,25 @@ _LOGGER = logging.getLogger(__name__) def setup_platform(hass, config, add_devices, discovery_info=None): """Set up the Verisure platform.""" sensors = [] + hub.update_overview() if int(hub.config.get(CONF_THERMOMETERS, 1)): - hub.update_climate() sensors.extend([ - VerisureThermometer(value.id) - for value in hub.climate_status.values() - if hasattr(value, 'temperature') and value.temperature - ]) + VerisureThermometer(device_label) + for device_label in hub.get( + '$.climateValues[?(@.temperature)].deviceLabel')]) if int(hub.config.get(CONF_HYDROMETERS, 1)): - hub.update_climate() sensors.extend([ - VerisureHygrometer(value.id) - for value in hub.climate_status.values() - if hasattr(value, 'humidity') and value.humidity - ]) + VerisureHygrometer(device_label) + for device_label in hub.get( + '$.climateValues[?(@.humidity)].deviceLabel')]) if int(hub.config.get(CONF_MOUSE, 1)): - hub.update_mousedetection() sensors.extend([ - VerisureMouseDetection(value.deviceLabel) - for value in hub.mouse_status.values() - # is this if needed? - if hasattr(value, 'amountText') and value.amountText - ]) + VerisureMouseDetection(device_label) + for device_label in hub.get( + "$.eventCounts[?(@.deviceType=='MOUSE1')].deviceLabel")]) add_devices(sensors) @@ -50,26 +44,30 @@ def setup_platform(hass, config, add_devices, discovery_info=None): class VerisureThermometer(Entity): """Representation of a Verisure thermometer.""" - def __init__(self, device_id): + def __init__(self, device_label): """Initialize the sensor.""" - self._id = device_id + self._device_label = device_label @property def name(self): """Return the name of the device.""" - return '{} {}'.format( - hub.climate_status[self._id].location, 'Temperature') + return hub.get_first( + "$.climateValues[?(@.deviceLabel=='%s')].deviceArea", + self._device_label) + " temperature" @property def state(self): """Return the state of the device.""" - # Remove ° character - return hub.climate_status[self._id].temperature[:-1] + return hub.get_first( + "$.climateValues[?(@.deviceLabel=='%s')].temperature", + self._device_label) @property def available(self): """Return True if entity is available.""" - return hub.available + return hub.get_first( + "$.climateValues[?(@.deviceLabel=='%s')].temperature", + self._device_label) is not None @property def unit_of_measurement(self): @@ -78,71 +76,80 @@ class VerisureThermometer(Entity): def update(self): """Update the sensor.""" - hub.update_climate() + hub.update_overview() class VerisureHygrometer(Entity): """Representation of a Verisure hygrometer.""" - def __init__(self, device_id): + def __init__(self, device_label): """Initialize the sensor.""" - self._id = device_id + self._device_label = device_label @property def name(self): - """Return the name of the sensor.""" - return '{} {}'.format( - hub.climate_status[self._id].location, 'Humidity') + """Return the name of the device.""" + return hub.get_first( + "$.climateValues[?(@.deviceLabel=='%s')].deviceArea", + self._device_label) + " humidity" @property def state(self): - """Return the state of the sensor.""" - # remove % character - return hub.climate_status[self._id].humidity[:-1] + """Return the state of the device.""" + return hub.get_first( + "$.climateValues[?(@.deviceLabel=='%s')].humidity", + self._device_label) @property def available(self): """Return True if entity is available.""" - return hub.available + return hub.get_first( + "$.climateValues[?(@.deviceLabel=='%s')].humidity", + self._device_label) is not None @property def unit_of_measurement(self): - """Return the unit of measurement of this sensor.""" - return "%" + """Return the unit of measurement of this entity.""" + return '%' def update(self): """Update the sensor.""" - hub.update_climate() + hub.update_overview() class VerisureMouseDetection(Entity): """Representation of a Verisure mouse detector.""" - def __init__(self, device_id): + def __init__(self, device_label): """Initialize the sensor.""" - self._id = device_id + self._device_label = device_label @property def name(self): - """Return the name of the sensor.""" - return '{} {}'.format( - hub.mouse_status[self._id].location, 'Mouse') + """Return the name of the device.""" + return hub.get_first( + "$.eventCounts[?(@.deviceLabel=='%s')].area", + self._device_label) + " mouse" @property def state(self): - """Return the state of the sensor.""" - return hub.mouse_status[self._id].count + """Return the state of the device.""" + return hub.get_first( + "$.eventCounts[?(@.deviceLabel=='%s')].detections", + self._device_label) @property def available(self): """Return True if entity is available.""" - return hub.available + return hub.get_first( + "$.eventCounts[?(@.deviceLabel=='%s')]", + self._device_label) is not None @property def unit_of_measurement(self): - """Return the unit of measurement of this sensor.""" - return "Mice" + """Return the unit of measurement of this entity.""" + return 'Mice' def update(self): """Update the sensor.""" - hub.update_mousedetection() + hub.update_overview() diff --git a/homeassistant/components/switch/verisure.py b/homeassistant/components/switch/verisure.py index 3aeb092f35b..597e1aa5959 100644 --- a/homeassistant/components/switch/verisure.py +++ b/homeassistant/components/switch/verisure.py @@ -5,6 +5,7 @@ For more details about this platform, please refer to the documentation at https://home-assistant.io/components/switch.verisure/ """ import logging +from time import time from homeassistant.components.verisure import HUB as hub from homeassistant.components.verisure import CONF_SMARTPLUGS @@ -18,11 +19,11 @@ def setup_platform(hass, config, add_devices, discovery_info=None): if not int(hub.config.get(CONF_SMARTPLUGS, 1)): return False - hub.update_smartplugs() + hub.update_overview() switches = [] switches.extend([ - VerisureSmartplug(value.deviceLabel) - for value in hub.smartplug_status.values()]) + VerisureSmartplug(device_label) + for device_label in hub.get('$.smartPlugs[*].deviceLabel')]) add_devices(switches) @@ -31,35 +32,46 @@ class VerisureSmartplug(SwitchDevice): def __init__(self, device_id): """Initialize the Verisure device.""" - self._id = device_id + self._device_label = device_id + self._change_timestamp = 0 + self._state = False @property def name(self): """Return the name or location of the smartplug.""" - return hub.smartplug_status[self._id].location + return hub.get_first( + "$.smartPlugs[?(@.deviceLabel == '%s')].area", + self._device_label) + " switch" @property def is_on(self): """Return true if on.""" - return hub.smartplug_status[self._id].status == 'on' + if time() - self._change_timestamp < 10: + return self._state + self._state = hub.get_first( + "$.smartPlugs[?(@.deviceLabel == '%s')].currentState", + self._device_label) == "ON" + return self._state @property def available(self): """Return True if entity is available.""" - return hub.available + return hub.get_first( + "$.smartPlugs[?(@.deviceLabel == '%s')]", + self._device_label) is not None def turn_on(self): """Set smartplug status on.""" - hub.my_pages.smartplug.set(self._id, 'on') - hub.my_pages.smartplug.wait_while_updating(self._id, 'on') - self.update() + hub.session.set_smartplug_state(self._device_label, True) + self._state = True + self._change_timestamp = time() def turn_off(self): """Set smartplug status off.""" - hub.my_pages.smartplug.set(self._id, 'off') - hub.my_pages.smartplug.wait_while_updating(self._id, 'off') - self.update() + hub.session.set_smartplug_state(self._device_label, False) + self._state = False + self._change_timestamp = time() def update(self): """Get the latest date of the smartplug.""" - hub.update_smartplugs() + hub.update_overview() diff --git a/homeassistant/components/verisure.py b/homeassistant/components/verisure.py index 72837b07019..1ec1f9e537d 100644 --- a/homeassistant/components/verisure.py +++ b/homeassistant/components/verisure.py @@ -6,19 +6,19 @@ https://home-assistant.io/components/verisure/ """ import logging import threading -import time import os.path from datetime import timedelta import voluptuous as vol -from homeassistant.const import CONF_PASSWORD, CONF_USERNAME +from homeassistant.const import (CONF_PASSWORD, CONF_USERNAME, + EVENT_HOMEASSISTANT_STOP) from homeassistant.helpers import discovery from homeassistant.util import Throttle import homeassistant.config as conf_util import homeassistant.helpers.config_validation as cv -REQUIREMENTS = ['vsure==0.11.1'] +REQUIREMENTS = ['vsure==1.3.6', 'jsonpath==0.75'] _LOGGER = logging.getLogger(__name__) @@ -26,6 +26,7 @@ ATTR_DEVICE_SERIAL = 'device_serial' CONF_ALARM = 'alarm' CONF_CODE_DIGITS = 'code_digits' +CONF_DOOR_WINDOW = 'door_window' CONF_HYDROMETERS = 'hygrometers' CONF_LOCKS = 'locks' CONF_MOUSE = 'mouse' @@ -45,6 +46,7 @@ CONFIG_SCHEMA = vol.Schema({ vol.Required(CONF_USERNAME): cv.string, vol.Optional(CONF_ALARM, default=True): cv.boolean, vol.Optional(CONF_CODE_DIGITS, default=4): cv.positive_int, + vol.Optional(CONF_DOOR_WINDOW, default=True): cv.boolean, vol.Optional(CONF_HYDROMETERS, default=True): cv.boolean, vol.Optional(CONF_LOCKS, default=True): cv.boolean, vol.Optional(CONF_MOUSE, default=True): cv.boolean, @@ -66,9 +68,12 @@ def setup(hass, config): HUB = VerisureHub(config[DOMAIN], verisure) if not HUB.login(): return False + hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP, + lambda event: HUB.logout()) + HUB.update_overview() for component in ('sensor', 'switch', 'alarm_control_panel', 'lock', - 'camera'): + 'camera', 'binary_sensor'): discovery.load_platform(hass, component, DOMAIN, {}, config) descriptions = conf_util.load_yaml_config_file( @@ -93,132 +98,73 @@ class VerisureHub(object): def __init__(self, domain_config, verisure): """Initialize the Verisure hub.""" - self.alarm_status = {} - self.lock_status = {} - self.climate_status = {} - self.mouse_status = {} - self.smartplug_status = {} - self.smartcam_status = {} - self.smartcam_dict = {} + self.overview = {} + self.imageseries = {} self.config = domain_config self._verisure = verisure self._lock = threading.Lock() - # When MyPages is brought up from maintenance it sometimes give us a - # "wrong password" message. We will continue to retry after maintenance - # regardless of that error. - self._disable_wrong_password_error = False - self._password_retries = 1 - self._reconnect_timeout = time.time() - - self.my_pages = verisure.MyPages( + self.session = verisure.Session( domain_config[CONF_USERNAME], domain_config[CONF_PASSWORD]) + import jsonpath + self.jsonpath = jsonpath.jsonpath + def login(self): - """Login to Verisure MyPages.""" + """Login to Verisure.""" try: - self.my_pages.login() + self.session.login() except self._verisure.Error as ex: - _LOGGER.error("Could not log in to verisure mypages, %s", ex) + _LOGGER.error('Could not log in to verisure, %s', ex) return False return True - @Throttle(timedelta(seconds=1)) - def update_alarms(self): - """Update the status of the alarm.""" - self.update_component( - self.my_pages.alarm.get, - self.alarm_status) - - @Throttle(timedelta(seconds=1)) - def update_locks(self): - """Update the status of the locks.""" - self.update_component( - self.my_pages.lock.get, - self.lock_status) + def logout(self): + """Logout from Verisure.""" + try: + self.session.logout() + except self._verisure.Error as ex: + _LOGGER.error('Could not log out from verisure, %s', ex) + return False + return True @Throttle(timedelta(seconds=60)) - def update_climate(self): - """Update the status of the climate units.""" - self.update_component( - self.my_pages.climate.get, - self.climate_status) + def update_overview(self): + """Update the overview.""" + try: + self.overview = self.session.get_overview() + except self._verisure.ResponseError as ex: + _LOGGER.error('Could not read overview, %s', ex) + if ex.status_code == 503: # Service unavailable + _LOGGER.info('Trying to log in again') + self.login() + else: + raise @Throttle(timedelta(seconds=60)) - def update_mousedetection(self): - """Update the status of the mouse detectors.""" - self.update_component( - self.my_pages.mousedetection.get, - self.mouse_status) - - @Throttle(timedelta(seconds=1)) - def update_smartplugs(self): - """Update the status of the smartplugs.""" - self.update_component( - self.my_pages.smartplug.get, - self.smartplug_status) - - @Throttle(timedelta(seconds=30)) - def update_smartcam(self): - """Update the status of the smartcam.""" - self.update_component( - self.my_pages.smartcam.get, - self.smartcam_status) - - @Throttle(timedelta(seconds=30)) - def update_smartcam_imagelist(self): - """Update the imagelist for the camera.""" - _LOGGER.debug("Running update imagelist") - self.smartcam_dict = self.my_pages.smartcam.get_imagelist() - _LOGGER.debug("New dict: %s", self.smartcam_dict) + def update_smartcam_imageseries(self): + """Update the image series.""" + self.imageseries = self.session.get_camera_imageseries() @Throttle(timedelta(seconds=30)) def smartcam_capture(self, device_id): """Capture a new image from a smartcam.""" - self.my_pages.smartcam.capture(device_id) + self.session.capture_image(device_id) - @property - def available(self): - """Return True if hub is available.""" - return self._password_retries >= 0 + def get(self, jpath, *args): + """Get values from the overview that matches the jsonpath.""" + res = self.jsonpath(self.overview, jpath % args) + return res if res else [] - def update_component(self, get_function, status): - """Update the status of Verisure components.""" - try: - for overview in get_function(): - try: - status[overview.id] = overview - except AttributeError: - status[overview.deviceLabel] = overview - except self._verisure.Error as ex: - _LOGGER.info("Caught connection error %s, tries to reconnect", ex) - self.reconnect() + def get_first(self, jpath, *args): + """Get first value from the overview that matches the jsonpath.""" + res = self.get(jpath, *args) + return res[0] if res else None - def reconnect(self): - """Reconnect to Verisure MyPages.""" - if (self._reconnect_timeout > time.time() or - not self._lock.acquire(blocking=False) or - self._password_retries < 0): - return - try: - self.my_pages.login() - self._disable_wrong_password_error = False - self._password_retries = 1 - except self._verisure.LoginError as ex: - _LOGGER.error("Wrong user name or password for Verisure MyPages") - if self._disable_wrong_password_error: - self._reconnect_timeout = time.time() + 60*60 - else: - self._password_retries = self._password_retries - 1 - except self._verisure.MaintenanceError: - self._disable_wrong_password_error = True - self._reconnect_timeout = time.time() + 60*60 - _LOGGER.error("Verisure MyPages down for maintenance") - except self._verisure.Error as ex: - _LOGGER.error("Could not login to Verisure MyPages, %s", ex) - self._reconnect_timeout = time.time() + 60 - finally: - self._lock.release() + def get_image_info(self, jpath, *args): + """Get values from the imageseries that matches the jsonpath.""" + res = self.jsonpath(self.imageseries, jpath % args) + return res if res else [] diff --git a/requirements_all.txt b/requirements_all.txt index 161386db61d..ee2de706846 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -327,6 +327,9 @@ insteonlocal==0.52 # homeassistant.components.insteon_plm insteonplm==0.7.4 +# homeassistant.components.verisure +jsonpath==0.75 + # homeassistant.components.media_player.kodi # homeassistant.components.notify.kodi jsonrpc-async==0.6 @@ -893,7 +896,7 @@ uvcclient==0.10.0 volvooncall==0.3.3 # homeassistant.components.verisure -vsure==0.11.1 +vsure==1.3.6 # homeassistant.components.sensor.vasttrafik vtjp==0.1.14