Added support for lock connected to Verisure system.
This commit is contained in:
parent
23c5159f6c
commit
41f908ed39
3 changed files with 148 additions and 12 deletions
|
@ -17,7 +17,7 @@ from homeassistant.helpers.entity import Entity
|
|||
from homeassistant.const import (
|
||||
STATE_LOCKED, STATE_UNLOCKED, STATE_UNKNOWN, SERVICE_LOCK, SERVICE_UNLOCK,
|
||||
ATTR_ENTITY_ID)
|
||||
from homeassistant.components import (group, wink)
|
||||
from homeassistant.components import (group, verisure, wink)
|
||||
|
||||
DOMAIN = 'lock'
|
||||
SCAN_INTERVAL = 30
|
||||
|
@ -28,12 +28,15 @@ ENTITY_ID_ALL_LOCKS = group.ENTITY_ID_FORMAT.format('all_locks')
|
|||
ENTITY_ID_FORMAT = DOMAIN + '.{}'
|
||||
|
||||
ATTR_LOCKED = "locked"
|
||||
ATTR_CODE = 'code'
|
||||
ATTR_CODE_FORMAT = 'code_format'
|
||||
|
||||
MIN_TIME_BETWEEN_SCANS = timedelta(seconds=10)
|
||||
|
||||
# Maps discovered services to their platforms
|
||||
DISCOVERY_PLATFORMS = {
|
||||
wink.DISCOVER_LOCKS: 'wink'
|
||||
wink.DISCOVER_LOCKS: 'wink',
|
||||
verisure.DISCOVER_LOCKS: 'verisure'
|
||||
}
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
@ -45,15 +48,25 @@ def is_locked(hass, entity_id=None):
|
|||
return hass.states.is_state(entity_id, STATE_LOCKED)
|
||||
|
||||
|
||||
def lock(hass, entity_id=None):
|
||||
def lock(hass, entity_id=None, code=None):
|
||||
""" Locks all or specified locks. """
|
||||
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
|
||||
data = {}
|
||||
if code:
|
||||
data[ATTR_CODE] = code
|
||||
if entity_id:
|
||||
data[ATTR_ENTITY_ID] = entity_id
|
||||
|
||||
hass.services.call(DOMAIN, SERVICE_LOCK, data)
|
||||
|
||||
|
||||
def unlock(hass, entity_id=None):
|
||||
def unlock(hass, entity_id=None, code=None):
|
||||
""" Unlocks all or specified locks. """
|
||||
data = {ATTR_ENTITY_ID: entity_id} if entity_id else None
|
||||
data = {}
|
||||
if code:
|
||||
data[ATTR_CODE] = code
|
||||
if entity_id:
|
||||
data[ATTR_ENTITY_ID] = entity_id
|
||||
|
||||
hass.services.call(DOMAIN, SERVICE_UNLOCK, data)
|
||||
|
||||
|
||||
|
@ -68,11 +81,16 @@ def setup(hass, config):
|
|||
""" Handles calls to the lock services. """
|
||||
target_locks = component.extract_from_service(service)
|
||||
|
||||
if ATTR_CODE not in service.data:
|
||||
code = None
|
||||
else:
|
||||
code = service.data[ATTR_CODE]
|
||||
|
||||
for item in target_locks:
|
||||
if service.service == SERVICE_LOCK:
|
||||
item.lock()
|
||||
item.lock(code=code)
|
||||
else:
|
||||
item.unlock()
|
||||
item.unlock(code=code)
|
||||
|
||||
if item.should_poll:
|
||||
item.update_ha_state(True)
|
||||
|
@ -91,19 +109,34 @@ class LockDevice(Entity):
|
|||
""" Represents a lock within Home Assistant. """
|
||||
# pylint: disable=no-self-use
|
||||
|
||||
@property
|
||||
def code_format(self):
|
||||
""" regex for code format or None if no code is required. """
|
||||
return None
|
||||
|
||||
@property
|
||||
def is_locked(self):
|
||||
""" Is the lock locked or unlocked. """
|
||||
return None
|
||||
|
||||
def lock(self):
|
||||
def lock(self, **kwargs):
|
||||
""" Locks the lock. """
|
||||
raise NotImplementedError()
|
||||
|
||||
def unlock(self):
|
||||
def unlock(self, **kwargs):
|
||||
""" Unlocks the lock. """
|
||||
raise NotImplementedError()
|
||||
|
||||
@property
|
||||
def state_attributes(self):
|
||||
""" Return the state attributes. """
|
||||
if self.code_format is None:
|
||||
return None
|
||||
state_attr = {
|
||||
ATTR_CODE_FORMAT: self.code_format,
|
||||
}
|
||||
return state_attr
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
locked = self.is_locked
|
||||
|
|
92
homeassistant/components/lock/verisure.py
Normal file
92
homeassistant/components/lock/verisure.py
Normal file
|
@ -0,0 +1,92 @@
|
|||
"""
|
||||
homeassistant.components.lock.verisure
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Interfaces with Verisure locks.
|
||||
|
||||
For more details about this platform, please refer to the documentation at
|
||||
https://home-assistant.io/components/verisure/
|
||||
"""
|
||||
import logging
|
||||
|
||||
import homeassistant.components.verisure as verisure
|
||||
from homeassistant.components.lock import LockDevice
|
||||
|
||||
from homeassistant.const import (
|
||||
STATE_UNKNOWN,
|
||||
STATE_LOCKED, STATE_UNLOCKED)
|
||||
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
ATTR_CODE = 'code'
|
||||
|
||||
|
||||
def setup_platform(hass, config, add_devices, discovery_info=None):
|
||||
""" Sets up the Verisure platform. """
|
||||
|
||||
if not verisure.MY_PAGES:
|
||||
_LOGGER.error('A connection has not been made to Verisure mypages.')
|
||||
return False
|
||||
|
||||
locks = []
|
||||
|
||||
locks.extend([VerisureDoorlock(value)
|
||||
for value in verisure.LOCK_STATUS.values()
|
||||
if verisure.SHOW_LOCKS])
|
||||
|
||||
add_devices(locks)
|
||||
|
||||
|
||||
# pylint: disable=abstract-method
|
||||
class VerisureDoorlock(LockDevice):
|
||||
""" Represents a Verisure doorlock status. """
|
||||
|
||||
def __init__(self, lock_status, code=None):
|
||||
self._id = lock_status.id
|
||||
self._state = STATE_UNKNOWN
|
||||
self._code = code
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
""" Returns the name of the device. """
|
||||
return 'Lock {}'.format(self._id)
|
||||
|
||||
@property
|
||||
def state(self):
|
||||
""" Returns the state of the device. """
|
||||
return self._state
|
||||
|
||||
@property
|
||||
def code_format(self):
|
||||
""" Six digit code required. """
|
||||
return '^\\d{%s}$' % verisure.CODE_DIGITS
|
||||
|
||||
def update(self):
|
||||
""" Update lock status """
|
||||
verisure.update_lock()
|
||||
|
||||
if verisure.LOCK_STATUS[self._id].status == 'unlocked':
|
||||
self._state = STATE_UNLOCKED
|
||||
elif verisure.LOCK_STATUS[self._id].status == 'locked':
|
||||
self._state = STATE_LOCKED
|
||||
elif verisure.LOCK_STATUS[self._id].status != 'pending':
|
||||
_LOGGER.error(
|
||||
'Unknown lock state %s',
|
||||
verisure.LOCK_STATUS[self._id].status)
|
||||
|
||||
@property
|
||||
def is_locked(self):
|
||||
""" True if device is locked. """
|
||||
return verisure.LOCK_STATUS[self._id].status
|
||||
|
||||
def unlock(self, **kwargs):
|
||||
""" Send unlock command. """
|
||||
verisure.MY_PAGES.lock.set(kwargs[ATTR_CODE], self._id, 'UNLOCKED')
|
||||
_LOGGER.info('verisure doorlock unlocking')
|
||||
verisure.MY_PAGES.lock.wait_while_pending()
|
||||
verisure.update_lock()
|
||||
|
||||
def lock(self, **kwargs):
|
||||
""" Send lock command. """
|
||||
verisure.MY_PAGES.lock.set(kwargs[ATTR_CODE], self._id, 'LOCKED')
|
||||
_LOGGER.info('verisure doorlock locking')
|
||||
verisure.MY_PAGES.lock.wait_while_pending()
|
||||
verisure.update_lock()
|
|
@ -26,6 +26,7 @@ DOMAIN = "verisure"
|
|||
DISCOVER_SENSORS = 'verisure.sensors'
|
||||
DISCOVER_SWITCHES = 'verisure.switches'
|
||||
DISCOVER_ALARMS = 'verisure.alarm_control_panel'
|
||||
DISCOVER_LOCKS = 'verisure.lock'
|
||||
|
||||
DEPENDENCIES = ['alarm_control_panel']
|
||||
REQUIREMENTS = ['vsure==0.5.0']
|
||||
|
@ -36,6 +37,7 @@ MY_PAGES = None
|
|||
ALARM_STATUS = {}
|
||||
SMARTPLUG_STATUS = {}
|
||||
CLIMATE_STATUS = {}
|
||||
LOCK_STATUS = {}
|
||||
|
||||
VERISURE_LOGIN_ERROR = None
|
||||
VERISURE_ERROR = None
|
||||
|
@ -44,6 +46,7 @@ SHOW_THERMOMETERS = True
|
|||
SHOW_HYGROMETERS = True
|
||||
SHOW_ALARM = True
|
||||
SHOW_SMARTPLUGS = True
|
||||
SHOW_LOCKS = True
|
||||
CODE_DIGITS = 4
|
||||
|
||||
# if wrong password was given don't try again
|
||||
|
@ -63,11 +66,12 @@ def setup(hass, config):
|
|||
from verisure import MyPages, LoginError, Error
|
||||
|
||||
global SHOW_THERMOMETERS, SHOW_HYGROMETERS,\
|
||||
SHOW_ALARM, SHOW_SMARTPLUGS, CODE_DIGITS
|
||||
SHOW_ALARM, SHOW_SMARTPLUGS, SHOW_LOCKS, CODE_DIGITS
|
||||
SHOW_THERMOMETERS = int(config[DOMAIN].get('thermometers', '1'))
|
||||
SHOW_HYGROMETERS = int(config[DOMAIN].get('hygrometers', '1'))
|
||||
SHOW_ALARM = int(config[DOMAIN].get('alarm', '1'))
|
||||
SHOW_SMARTPLUGS = int(config[DOMAIN].get('smartplugs', '1'))
|
||||
SHOW_LOCKS = int(config[DOMAIN].get('locks', '1'))
|
||||
CODE_DIGITS = int(config[DOMAIN].get('code_digits', '4'))
|
||||
|
||||
global MY_PAGES
|
||||
|
@ -87,11 +91,13 @@ def setup(hass, config):
|
|||
update_alarm()
|
||||
update_climate()
|
||||
update_smartplug()
|
||||
update_lock()
|
||||
|
||||
# Load components for the devices in the ISY controller that we support
|
||||
for comp_name, discovery in ((('sensor', DISCOVER_SENSORS),
|
||||
('switch', DISCOVER_SWITCHES),
|
||||
('alarm_control_panel', DISCOVER_ALARMS))):
|
||||
('alarm_control_panel', DISCOVER_ALARMS),
|
||||
('lock', DISCOVER_LOCKS))):
|
||||
component = get_component(comp_name)
|
||||
_LOGGER.info(config[DOMAIN])
|
||||
bootstrap.setup_component(hass, component.DOMAIN, config)
|
||||
|
@ -134,6 +140,11 @@ def update_smartplug():
|
|||
update_component(MY_PAGES.smartplug.get, SMARTPLUG_STATUS)
|
||||
|
||||
|
||||
def update_lock():
|
||||
""" Updates the status of alarms. """
|
||||
update_component(MY_PAGES.lock.get, LOCK_STATUS)
|
||||
|
||||
|
||||
def update_component(get_function, status):
|
||||
""" Updates the status of verisure components. """
|
||||
if WRONG_PASSWORD_GIVEN:
|
||||
|
|
Loading…
Add table
Reference in a new issue