Files
core/homeassistant/components/homekit/security_systems.py
maxclaey 4218b31e7b Add support for alarm system, switch and thermostat to homekit (#12819)
* Added support for security system, switch and thermostat
* Processing review
* Only perform set call when the call didn't come from HomeKit
* Added support for alarm_code
* Take into account review remarks
* Provide tests for HomeKit security systems, switches and thermostats
* Support STATE_AUTO
* Guard if state exists
* Improve support for thermostat auto mode
* Provide both high and low at the same time for home assistant
* Set default values within accepted ranges
* Added tests for auto mode
* Fix thermostat test error
* Use attributes.get instead of indexing for safety
* Avoid hardcoded attributes in tests
2018-03-07 13:17:52 +01:00

93 lines
3.7 KiB
Python

"""Class to hold all alarm control panel accessories."""
import logging
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT, STATE_ALARM_DISARMED,
ATTR_ENTITY_ID, ATTR_CODE)
from homeassistant.helpers.event import async_track_state_change
from . import TYPES
from .accessories import HomeAccessory, add_preload_service
from .const import (
SERV_SECURITY_SYSTEM, CHAR_CURRENT_SECURITY_STATE,
CHAR_TARGET_SECURITY_STATE)
_LOGGER = logging.getLogger(__name__)
HASS_TO_HOMEKIT = {STATE_ALARM_DISARMED: 3, STATE_ALARM_ARMED_HOME: 0,
STATE_ALARM_ARMED_AWAY: 1, STATE_ALARM_ARMED_NIGHT: 2}
HOMEKIT_TO_HASS = {c: s for s, c in HASS_TO_HOMEKIT.items()}
STATE_TO_SERVICE = {STATE_ALARM_DISARMED: 'alarm_disarm',
STATE_ALARM_ARMED_HOME: 'alarm_arm_home',
STATE_ALARM_ARMED_AWAY: 'alarm_arm_away',
STATE_ALARM_ARMED_NIGHT: 'alarm_arm_night'}
@TYPES.register('SecuritySystem')
class SecuritySystem(HomeAccessory):
"""Generate an SecuritySystem accessory for an alarm control panel."""
def __init__(self, hass, entity_id, display_name, alarm_code=None):
"""Initialize a SecuritySystem accessory object."""
super().__init__(display_name, entity_id, 'ALARM_SYSTEM')
self._hass = hass
self._entity_id = entity_id
self._alarm_code = alarm_code
self.flag_target_state = False
self.service_alarm = add_preload_service(self, SERV_SECURITY_SYSTEM)
self.char_current_state = self.service_alarm. \
get_characteristic(CHAR_CURRENT_SECURITY_STATE)
self.char_current_state.value = 3
self.char_target_state = self.service_alarm. \
get_characteristic(CHAR_TARGET_SECURITY_STATE)
self.char_target_state.value = 3
self.char_target_state.setter_callback = self.set_security_state
def run(self):
"""Method called be object after driver is started."""
state = self._hass.states.get(self._entity_id)
self.update_security_state(new_state=state)
async_track_state_change(self._hass, self._entity_id,
self.update_security_state)
def set_security_state(self, value):
"""Move security state to value if call came from HomeKit."""
_LOGGER.debug("%s: Set security state to %d",
self._entity_id, value)
self.flag_target_state = True
hass_value = HOMEKIT_TO_HASS[value]
service = STATE_TO_SERVICE[hass_value]
params = {ATTR_ENTITY_ID: self._entity_id}
if self._alarm_code is not None:
params[ATTR_CODE] = self._alarm_code
self._hass.services.call('alarm_control_panel', service, params)
def update_security_state(self, entity_id=None,
old_state=None, new_state=None):
"""Update security state after state changed."""
if new_state is None:
return
hass_state = new_state.state
if hass_state not in HASS_TO_HOMEKIT:
return
current_security_state = HASS_TO_HOMEKIT[hass_state]
self.char_current_state.set_value(current_security_state)
_LOGGER.debug("%s: Updated current state to %s (%d)",
self._entity_id, hass_state,
current_security_state)
if not self.flag_target_state:
self.char_target_state.set_value(current_security_state,
should_callback=False)
elif self.char_target_state.get_value() \
== self.char_current_state.get_value():
self.flag_target_state = False