diff --git a/homeassistant/components/homekit_controller/__init__.py b/homeassistant/components/homekit_controller/__init__.py index 3e481db96da..072e323ecd1 100644 --- a/homeassistant/components/homekit_controller/__init__.py +++ b/homeassistant/components/homekit_controller/__init__.py @@ -1,4 +1,5 @@ """Support for Homekit device discovery.""" +import asyncio import json import logging import os @@ -74,6 +75,8 @@ class HKDevice(): self.configurator = hass.components.configurator self._connection_warning_logged = False + self.pairing_lock = asyncio.Lock(loop=hass.loop) + self.pairing = self.controller.pairings.get(hkid) if self.pairing is not None: @@ -168,6 +171,32 @@ class HKDevice(): 'name': 'HomeKit code', 'type': 'string'}]) + async def get_characteristics(self, *args, **kwargs): + """Read latest state from homekit accessory.""" + async with self.pairing_lock: + chars = await self.hass.async_add_executor_job( + self.pairing.get_characteristics, + *args, + **kwargs, + ) + return chars + + async def put_characteristics(self, characteristics): + """Control a HomeKit device state from Home Assistant.""" + chars = [] + for row in characteristics: + chars.append(( + row['aid'], + row['iid'], + row['value'], + )) + + async with self.pairing_lock: + await self.hass.async_add_executor_job( + self.pairing.put_characteristics, + chars + ) + class HomeKitEntity(Entity): """Representation of a Home Assistant HomeKit device.""" @@ -238,15 +267,15 @@ class HomeKitEntity(Entity): # pylint: disable=not-callable setup_fn(char) - def update(self): + async def async_update(self): """Obtain a HomeKit device's state.""" # pylint: disable=import-error from homekit.exceptions import AccessoryDisconnectedError - pairing = self._accessory.pairing - try: - new_values_dict = pairing.get_characteristics(self._chars_to_poll) + new_values_dict = await self._accessory.get_characteristics( + self._chars_to_poll + ) except AccessoryDisconnectedError: return @@ -280,22 +309,6 @@ class HomeKitEntity(Entity): """Define the homekit characteristics the entity cares about.""" raise NotImplementedError - def update_characteristics(self, characteristics): - """Synchronise a HomeKit device state with Home Assistant.""" - pass - - def put_characteristics(self, characteristics): - """Control a HomeKit device state from Home Assistant.""" - chars = [] - for row in characteristics: - chars.append(( - row['aid'], - row['iid'], - row['value'], - )) - - self._accessory.pairing.put_characteristics(chars) - def setup(hass, config): """Set up for Homekit devices.""" diff --git a/homeassistant/components/homekit_controller/alarm_control_panel.py b/homeassistant/components/homekit_controller/alarm_control_panel.py index 5d366b6e27b..61352c3bedc 100644 --- a/homeassistant/components/homekit_controller/alarm_control_panel.py +++ b/homeassistant/components/homekit_controller/alarm_control_panel.py @@ -74,28 +74,28 @@ class HomeKitAlarmControlPanel(HomeKitEntity, AlarmControlPanel): """Return the state of the device.""" return self._state - def alarm_disarm(self, code=None): + async def async_alarm_disarm(self, code=None): """Send disarm command.""" - self.set_alarm_state(STATE_ALARM_DISARMED, code) + await self.set_alarm_state(STATE_ALARM_DISARMED, code) - def alarm_arm_away(self, code=None): + async def async_alarm_arm_away(self, code=None): """Send arm command.""" - self.set_alarm_state(STATE_ALARM_ARMED_AWAY, code) + await self.set_alarm_state(STATE_ALARM_ARMED_AWAY, code) - def alarm_arm_home(self, code=None): + async def async_alarm_arm_home(self, code=None): """Send stay command.""" - self.set_alarm_state(STATE_ALARM_ARMED_HOME, code) + await self.set_alarm_state(STATE_ALARM_ARMED_HOME, code) - def alarm_arm_night(self, code=None): + async def async_alarm_arm_night(self, code=None): """Send night command.""" - self.set_alarm_state(STATE_ALARM_ARMED_NIGHT, code) + await self.set_alarm_state(STATE_ALARM_ARMED_NIGHT, code) - def set_alarm_state(self, state, code=None): + async def set_alarm_state(self, state, code=None): """Send state command.""" characteristics = [{'aid': self._aid, 'iid': self._chars['security-system-state.target'], 'value': TARGET_STATE_MAP[state]}] - self.put_characteristics(characteristics) + await self._accessory.put_characteristics(characteristics) @property def device_state_attributes(self): diff --git a/homeassistant/components/homekit_controller/climate.py b/homeassistant/components/homekit_controller/climate.py index ceadcd46b9d..8696d2b1f97 100644 --- a/homeassistant/components/homekit_controller/climate.py +++ b/homeassistant/components/homekit_controller/climate.py @@ -80,21 +80,21 @@ class HomeKitClimateDevice(HomeKitEntity, ClimateDevice): def _update_temperature_target(self, value): self._target_temp = value - def set_temperature(self, **kwargs): + async def async_set_temperature(self, **kwargs): """Set new target temperature.""" temp = kwargs.get(ATTR_TEMPERATURE) characteristics = [{'aid': self._aid, 'iid': self._chars['temperature.target'], 'value': temp}] - self.put_characteristics(characteristics) + await self._accessory.put_characteristics(characteristics) - def set_operation_mode(self, operation_mode): + async def async_set_operation_mode(self, operation_mode): """Set new target operation mode.""" characteristics = [{'aid': self._aid, 'iid': self._chars['heating-cooling.target'], 'value': MODE_HASS_TO_HOMEKIT[operation_mode]}] - self.put_characteristics(characteristics) + await self._accessory.put_characteristics(characteristics) @property def state(self): diff --git a/homeassistant/components/homekit_controller/cover.py b/homeassistant/components/homekit_controller/cover.py index 3951cf577d4..1426112094e 100644 --- a/homeassistant/components/homekit_controller/cover.py +++ b/homeassistant/components/homekit_controller/cover.py @@ -114,20 +114,20 @@ class HomeKitGarageDoorCover(HomeKitEntity, CoverDevice): """Return if the cover is opening or not.""" return self._state == STATE_OPENING - def open_cover(self, **kwargs): + async def async_open_cover(self, **kwargs): """Send open command.""" - self.set_door_state(STATE_OPEN) + await self.set_door_state(STATE_OPEN) - def close_cover(self, **kwargs): + async def async_close_cover(self, **kwargs): """Send close command.""" - self.set_door_state(STATE_CLOSED) + await self.set_door_state(STATE_CLOSED) - def set_door_state(self, state): + async def set_door_state(self, state): """Send state command.""" characteristics = [{'aid': self._aid, 'iid': self._chars['door-state.target'], 'value': TARGET_GARAGE_STATE_MAP[state]}] - self.put_characteristics(characteristics) + await self._accessory.put_characteristics(characteristics) @property def device_state_attributes(self): @@ -232,41 +232,41 @@ class HomeKitWindowCover(HomeKitEntity, CoverDevice): """Return if the cover is opening or not.""" return self._state == STATE_OPENING - def open_cover(self, **kwargs): + async def async_open_cover(self, **kwargs): """Send open command.""" - self.set_cover_position(position=100) + await self.async_set_cover_position(position=100) - def close_cover(self, **kwargs): + async def close_cover(self, **kwargs): """Send close command.""" - self.set_cover_position(position=0) + await self.async_set_cover_position(position=0) - def set_cover_position(self, **kwargs): + async def async_set_cover_position(self, **kwargs): """Send position command.""" position = kwargs[ATTR_POSITION] characteristics = [{'aid': self._aid, 'iid': self._chars['position.target'], 'value': position}] - self.put_characteristics(characteristics) + await self._accessory.put_characteristics(characteristics) @property def current_cover_tilt_position(self): """Return current position of cover tilt.""" return self._tilt_position - def set_cover_tilt_position(self, **kwargs): + async def async_set_cover_tilt_position(self, **kwargs): """Move the cover tilt to a specific position.""" tilt_position = kwargs[ATTR_TILT_POSITION] if 'vertical-tilt.target' in self._chars: characteristics = [{'aid': self._aid, 'iid': self._chars['vertical-tilt.target'], 'value': tilt_position}] - self.put_characteristics(characteristics) + await self._accessory.put_characteristics(characteristics) elif 'horizontal-tilt.target' in self._chars: characteristics = [{'aid': self._aid, 'iid': self._chars['horizontal-tilt.target'], 'value': tilt_position}] - self.put_characteristics(characteristics) + await self._accessory.put_characteristics(characteristics) @property def device_state_attributes(self): diff --git a/homeassistant/components/homekit_controller/light.py b/homeassistant/components/homekit_controller/light.py index f39e793c184..193d0326b75 100644 --- a/homeassistant/components/homekit_controller/light.py +++ b/homeassistant/components/homekit_controller/light.py @@ -101,7 +101,7 @@ class HomeKitLight(HomeKitEntity, Light): """Flag supported features.""" return self._features - def turn_on(self, **kwargs): + async def async_turn_on(self, **kwargs): """Turn the specified light on.""" hs_color = kwargs.get(ATTR_HS_COLOR) temperature = kwargs.get(ATTR_COLOR_TEMP) @@ -127,11 +127,11 @@ class HomeKitLight(HomeKitEntity, Light): characteristics.append({'aid': self._aid, 'iid': self._chars['on'], 'value': True}) - self.put_characteristics(characteristics) + await self._accessory.put_characteristics(characteristics) - def turn_off(self, **kwargs): + async def async_turn_off(self, **kwargs): """Turn the specified light off.""" characteristics = [{'aid': self._aid, 'iid': self._chars['on'], 'value': False}] - self.put_characteristics(characteristics) + await self._accessory.put_characteristics(characteristics) diff --git a/homeassistant/components/homekit_controller/lock.py b/homeassistant/components/homekit_controller/lock.py index 635d457198a..6da5fa35655 100644 --- a/homeassistant/components/homekit_controller/lock.py +++ b/homeassistant/components/homekit_controller/lock.py @@ -75,20 +75,20 @@ class HomeKitLock(HomeKitEntity, LockDevice): """Return True if entity is available.""" return self._state is not None - def lock(self, **kwargs): + async def async_lock(self, **kwargs): """Lock the device.""" - self._set_lock_state(STATE_LOCKED) + await self._set_lock_state(STATE_LOCKED) - def unlock(self, **kwargs): + async def async_unlock(self, **kwargs): """Unlock the device.""" - self._set_lock_state(STATE_UNLOCKED) + await self._set_lock_state(STATE_UNLOCKED) - def _set_lock_state(self, state): + async def _set_lock_state(self, state): """Send state command.""" characteristics = [{'aid': self._aid, 'iid': self._chars['lock-mechanism.target-state'], 'value': TARGET_STATE_MAP[state]}] - self.put_characteristics(characteristics) + await self._accessory.put_characteristics(characteristics) @property def device_state_attributes(self): diff --git a/homeassistant/components/homekit_controller/switch.py b/homeassistant/components/homekit_controller/switch.py index daa4ede6898..21f10e6243c 100644 --- a/homeassistant/components/homekit_controller/switch.py +++ b/homeassistant/components/homekit_controller/switch.py @@ -48,20 +48,20 @@ class HomeKitSwitch(HomeKitEntity, SwitchDevice): """Return true if device is on.""" return self._on - def turn_on(self, **kwargs): + async def async_turn_on(self, **kwargs): """Turn the specified switch on.""" self._on = True characteristics = [{'aid': self._aid, 'iid': self._chars['on'], 'value': True}] - self.put_characteristics(characteristics) + await self._accessory.put_characteristics(characteristics) - def turn_off(self, **kwargs): + async def async_turn_off(self, **kwargs): """Turn the specified switch off.""" characteristics = [{'aid': self._aid, 'iid': self._chars['on'], 'value': False}] - self.put_characteristics(characteristics) + await self._accessory.put_characteristics(characteristics) @property def device_state_attributes(self):