Homekit refactor (#13707)

This commit is contained in:
cdce8p 2018-04-11 22:24:14 +02:00 committed by Johann Kellerman
parent 8d48164f25
commit 2a5751c09d
22 changed files with 275 additions and 332 deletions

View File

@ -8,11 +8,9 @@ from zlib import adler32
import voluptuous as vol
from homeassistant.components.climate import (
SUPPORT_TARGET_TEMPERATURE_HIGH, SUPPORT_TARGET_TEMPERATURE_LOW)
from homeassistant.components.cover import SUPPORT_SET_POSITION
from homeassistant.const import (
ATTR_CODE, ATTR_SUPPORTED_FEATURES, ATTR_UNIT_OF_MEASUREMENT,
ATTR_SUPPORTED_FEATURES, ATTR_UNIT_OF_MEASUREMENT,
CONF_PORT, TEMP_CELSIUS, TEMP_FAHRENHEIT,
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
import homeassistant.helpers.config_validation as cv
@ -79,63 +77,46 @@ def get_accessory(hass, state, aid, config):
state.entity_id)
return None
if state.domain == 'sensor':
unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
if unit == TEMP_CELSIUS or unit == TEMP_FAHRENHEIT:
_LOGGER.debug('Add "%s" as "%s"',
state.entity_id, 'TemperatureSensor')
return TYPES['TemperatureSensor'](hass, state.entity_id,
state.name, aid=aid)
elif unit == '%':
_LOGGER.debug('Add "%s" as %s"',
state.entity_id, 'HumiditySensor')
return TYPES['HumiditySensor'](hass, state.entity_id, state.name,
aid=aid)
a_type = None
config = config or {}
if state.domain == 'alarm_control_panel':
a_type = 'SecuritySystem'
elif state.domain == 'binary_sensor' or state.domain == 'device_tracker':
_LOGGER.debug('Add "%s" as "%s"', state.entity_id, 'BinarySensor')
return TYPES['BinarySensor'](hass, state.entity_id,
state.name, aid=aid)
a_type = 'BinarySensor'
elif state.domain == 'climate':
a_type = 'Thermostat'
elif state.domain == 'cover':
# Only add covers that support set_cover_position
features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
if features & SUPPORT_SET_POSITION:
_LOGGER.debug('Add "%s" as "%s"',
state.entity_id, 'WindowCovering')
return TYPES['WindowCovering'](hass, state.entity_id, state.name,
aid=aid)
elif state.domain == 'alarm_control_panel':
_LOGGER.debug('Add "%s" as "%s"', state.entity_id, 'SecuritySystem')
return TYPES['SecuritySystem'](hass, state.entity_id, state.name,
alarm_code=config.get(ATTR_CODE),
aid=aid)
elif state.domain == 'climate':
features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
support_temp_range = SUPPORT_TARGET_TEMPERATURE_LOW | \
SUPPORT_TARGET_TEMPERATURE_HIGH
# Check if climate device supports auto mode
support_auto = bool(features & support_temp_range)
_LOGGER.debug('Add "%s" as "%s"', state.entity_id, 'Thermostat')
return TYPES['Thermostat'](hass, state.entity_id,
state.name, support_auto, aid=aid)
a_type = 'WindowCovering'
elif state.domain == 'light':
_LOGGER.debug('Add "%s" as "%s"', state.entity_id, 'Light')
return TYPES['Light'](hass, state.entity_id, state.name, aid=aid)
a_type = 'Light'
elif state.domain == 'lock':
return TYPES['Lock'](hass, state.entity_id, state.name, aid=aid)
a_type = 'Lock'
elif state.domain == 'sensor':
unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
if unit == TEMP_CELSIUS or unit == TEMP_FAHRENHEIT:
a_type = 'TemperatureSensor'
elif unit == '%':
a_type = 'HumiditySensor'
elif state.domain == 'switch' or state.domain == 'remote' \
or state.domain == 'input_boolean' or state.domain == 'script':
_LOGGER.debug('Add "%s" as "%s"', state.entity_id, 'Switch')
return TYPES['Switch'](hass, state.entity_id, state.name, aid=aid)
a_type = 'Switch'
return None
if a_type is None:
return None
_LOGGER.debug('Add "%s" as "%s"', state.entity_id, a_type)
return TYPES[a_type](hass, state.name, state.entity_id, aid, config=config)
def generate_aid(entity_id):
@ -151,7 +132,7 @@ class HomeKit():
def __init__(self, hass, port, entity_filter, entity_config):
"""Initialize a HomeKit object."""
self._hass = hass
self.hass = hass
self._port = port
self._filter = entity_filter
self._config = entity_config
@ -164,11 +145,11 @@ class HomeKit():
"""Setup bridge and accessory driver."""
from .accessories import HomeBridge, HomeDriver
self._hass.bus.async_listen_once(
self.hass.bus.async_listen_once(
EVENT_HOMEASSISTANT_STOP, self.stop)
path = self._hass.config.path(HOMEKIT_FILE)
self.bridge = HomeBridge(self._hass)
path = self.hass.config.path(HOMEKIT_FILE)
self.bridge = HomeBridge(self.hass)
self.driver = HomeDriver(self.bridge, self._port, get_local_ip(), path)
def add_bridge_accessory(self, state):
@ -177,7 +158,7 @@ class HomeKit():
return
aid = generate_aid(state.entity_id)
conf = self._config.pop(state.entity_id, {})
acc = get_accessory(self._hass, state, aid, conf)
acc = get_accessory(self.hass, state, aid, conf)
if acc is not None:
self.bridge.add_accessory(acc)
@ -192,12 +173,12 @@ class HomeKit():
type_covers, type_lights, type_locks, type_security_systems,
type_sensors, type_switches, type_thermostats)
for state in self._hass.states.all():
for state in self.hass.states.all():
self.add_bridge_accessory(state)
self.bridge.set_broker(self.driver)
if not self.bridge.paired:
show_setup_message(self.bridge, self._hass)
show_setup_message(self.hass, self.bridge)
_LOGGER.debug('Driver start')
self.driver.start()

View File

@ -7,14 +7,14 @@ import logging
from pyhap.accessory import Accessory, Bridge, Category
from pyhap.accessory_driver import AccessoryDriver
from homeassistant.core import callback
from homeassistant.core import callback as ha_callback
from homeassistant.helpers.event import (
async_track_state_change, track_point_in_utc_time)
from homeassistant.util import dt as dt_util
from .const import (
DEBOUNCE_TIMEOUT, ACCESSORY_MODEL, ACCESSORY_NAME, BRIDGE_MODEL,
BRIDGE_NAME, MANUFACTURER, SERV_ACCESSORY_INFO, CHAR_MANUFACTURER,
DEBOUNCE_TIMEOUT, BRIDGE_MODEL, BRIDGE_NAME, MANUFACTURER,
SERV_ACCESSORY_INFO, CHAR_MANUFACTURER,
CHAR_MODEL, CHAR_NAME, CHAR_SERIAL_NUMBER)
from .util import (
show_setup_message, dismiss_setup_message)
@ -24,7 +24,7 @@ _LOGGER = logging.getLogger(__name__)
def debounce(func):
"""Decorator function. Debounce callbacks form HomeKit."""
@callback
@ha_callback
def call_later_listener(*args):
"""Callback listener called from call_later."""
# pylint: disable=unsubscriptable-object
@ -72,6 +72,18 @@ def add_preload_service(acc, service, chars=None):
return service
def setup_char(char_name, service, value=None, properties=None, callback=None):
"""Helper function to return fully configured characteristic."""
char = service.get_characteristic(char_name)
if value:
char.value = value
if properties:
char.override_properties(properties)
if callback:
char.setter_callback = callback
return char
def set_accessory_info(acc, name, model, manufacturer=MANUFACTURER,
serial_number='0000'):
"""Set the default accessory information."""
@ -85,14 +97,13 @@ def set_accessory_info(acc, name, model, manufacturer=MANUFACTURER,
class HomeAccessory(Accessory):
"""Adapter class for Accessory."""
# pylint: disable=no-member
def __init__(self, name=ACCESSORY_NAME, model=ACCESSORY_MODEL,
category='OTHER', **kwargs):
def __init__(self, hass, name, entity_id, aid, category):
"""Initialize a Accessory object."""
super().__init__(name, **kwargs)
set_accessory_info(self, name, model)
super().__init__(name, aid=aid)
set_accessory_info(self, name, model=entity_id)
self.category = getattr(Category, category, Category.OTHER)
self.entity_id = entity_id
self.hass = hass
def _set_services(self):
add_preload_service(self, SERV_ACCESSORY_INFO)
@ -100,19 +111,33 @@ class HomeAccessory(Accessory):
def run(self):
"""Method called by accessory after driver is started."""
state = self.hass.states.get(self.entity_id)
self.update_state(new_state=state)
self.update_state_callback(new_state=state)
async_track_state_change(
self.hass, self.entity_id, self.update_state)
self.hass, self.entity_id, self.update_state_callback)
def update_state_callback(self, entity_id=None, old_state=None,
new_state=None):
"""Callback from state change listener."""
_LOGGER.debug('New_state: %s', new_state)
if new_state is None:
return
self.update_state(new_state)
def update_state(self, new_state):
"""Method called on state change to update HomeKit value.
Overridden by accessory types.
"""
pass
class HomeBridge(Bridge):
"""Adapter class for Bridge."""
def __init__(self, hass, name=BRIDGE_NAME,
model=BRIDGE_MODEL, **kwargs):
def __init__(self, hass, name=BRIDGE_NAME):
"""Initialize a Bridge object."""
super().__init__(name, **kwargs)
set_accessory_info(self, name, model)
super().__init__(name)
set_accessory_info(self, name, model=BRIDGE_MODEL)
self.hass = hass
def _set_services(self):
@ -130,7 +155,7 @@ class HomeBridge(Bridge):
def remove_paired_client(self, client_uuid):
"""Override super function to show setup message if unpaired."""
super().remove_paired_client(client_uuid)
show_setup_message(self, self.hass)
show_setup_message(self.hass, self)
class HomeDriver(AccessoryDriver):

View File

@ -18,8 +18,6 @@ DEFAULT_PORT = 51827
SERVICE_HOMEKIT_START = 'start'
# #### STRING CONSTANTS ####
ACCESSORY_MODEL = 'homekit.accessory'
ACCESSORY_NAME = 'Home Accessory'
BRIDGE_MODEL = 'homekit.bridge'
BRIDGE_NAME = 'Home Assistant'
MANUFACTURER = 'HomeAssistant'

View File

@ -4,12 +4,11 @@ import logging
from homeassistant.components.cover import ATTR_CURRENT_POSITION
from . import TYPES
from .accessories import HomeAccessory, add_preload_service
from .accessories import HomeAccessory, add_preload_service, setup_char
from .const import (
CATEGORY_WINDOW_COVERING, SERV_WINDOW_COVERING,
CHAR_CURRENT_POSITION, CHAR_TARGET_POSITION, CHAR_POSITION_STATE)
_LOGGER = logging.getLogger(__name__)
@ -20,29 +19,20 @@ class WindowCovering(HomeAccessory):
The cover entity must support: set_cover_position.
"""
def __init__(self, hass, entity_id, display_name, **kwargs):
def __init__(self, *args, config):
"""Initialize a WindowCovering accessory object."""
super().__init__(display_name, entity_id,
CATEGORY_WINDOW_COVERING, **kwargs)
self.hass = hass
self.entity_id = entity_id
super().__init__(*args, category=CATEGORY_WINDOW_COVERING)
self.current_position = None
self.homekit_target = None
serv_cover = add_preload_service(self, SERV_WINDOW_COVERING)
self.char_current_position = serv_cover. \
get_characteristic(CHAR_CURRENT_POSITION)
self.char_target_position = serv_cover. \
get_characteristic(CHAR_TARGET_POSITION)
self.char_position_state = serv_cover. \
get_characteristic(CHAR_POSITION_STATE)
self.char_current_position.value = 0
self.char_target_position.value = 0
self.char_position_state.value = 0
self.char_target_position.setter_callback = self.move_cover
self.char_current_position = setup_char(
CHAR_CURRENT_POSITION, serv_cover, value=0)
self.char_target_position = setup_char(
CHAR_TARGET_POSITION, serv_cover, value=0,
callback=self.move_cover)
self.char_position_state = setup_char(
CHAR_POSITION_STATE, serv_cover, value=0)
def move_cover(self, value):
"""Move cover to value if call came from HomeKit."""
@ -56,11 +46,8 @@ class WindowCovering(HomeAccessory):
self.hass.components.cover.set_cover_position(
value, self.entity_id)
def update_state(self, entity_id=None, old_state=None, new_state=None):
def update_state(self, new_state):
"""Update cover position after state changed."""
if new_state is None:
return
current_position = new_state.attributes.get(ATTR_CURRENT_POSITION)
if isinstance(current_position, int):
self.current_position = current_position

View File

@ -7,7 +7,8 @@ from homeassistant.components.light import (
from homeassistant.const import ATTR_SUPPORTED_FEATURES, STATE_ON, STATE_OFF
from . import TYPES
from .accessories import HomeAccessory, add_preload_service, debounce
from .accessories import (
HomeAccessory, add_preload_service, debounce, setup_char)
from .const import (
CATEGORY_LIGHT, SERV_LIGHTBULB, CHAR_COLOR_TEMPERATURE,
CHAR_BRIGHTNESS, CHAR_HUE, CHAR_ON, CHAR_SATURATION)
@ -24,12 +25,9 @@ class Light(HomeAccessory):
Currently supports: state, brightness, color temperature, rgb_color.
"""
def __init__(self, hass, entity_id, name, **kwargs):
def __init__(self, *args, config):
"""Initialize a new Light accessory object."""
super().__init__(name, entity_id, CATEGORY_LIGHT, **kwargs)
self.hass = hass
self.entity_id = entity_id
super().__init__(*args, category=CATEGORY_LIGHT)
self._flag = {CHAR_ON: False, CHAR_BRIGHTNESS: False,
CHAR_HUE: False, CHAR_SATURATION: False,
CHAR_COLOR_TEMPERATURE: False, RGB_COLOR: False}
@ -49,36 +47,29 @@ class Light(HomeAccessory):
self._saturation = None
serv_light = add_preload_service(self, SERV_LIGHTBULB, self.chars)
self.char_on = serv_light.get_characteristic(CHAR_ON)
self.char_on.setter_callback = self.set_state
self.char_on.value = self._state
self.char_on = setup_char(
CHAR_ON, serv_light, value=self._state, callback=self.set_state)
if CHAR_BRIGHTNESS in self.chars:
self.char_brightness = serv_light \
.get_characteristic(CHAR_BRIGHTNESS)
self.char_brightness.setter_callback = self.set_brightness
self.char_brightness.value = 0
self.char_brightness = setup_char(
CHAR_BRIGHTNESS, serv_light, value=0,
callback=self.set_brightness)
if CHAR_COLOR_TEMPERATURE in self.chars:
self.char_color_temperature = serv_light \
.get_characteristic(CHAR_COLOR_TEMPERATURE)
self.char_color_temperature.setter_callback = \
self.set_color_temperature
min_mireds = self.hass.states.get(self.entity_id) \
.attributes.get(ATTR_MIN_MIREDS, 153)
max_mireds = self.hass.states.get(self.entity_id) \
.attributes.get(ATTR_MAX_MIREDS, 500)
self.char_color_temperature.override_properties({
'minValue': min_mireds, 'maxValue': max_mireds})
self.char_color_temperature.value = min_mireds
self.char_color_temperature = setup_char(
CHAR_COLOR_TEMPERATURE, serv_light, value=min_mireds,
properties={'minValue': min_mireds, 'maxValue': max_mireds},
callback=self.set_color_temperature)
if CHAR_HUE in self.chars:
self.char_hue = serv_light.get_characteristic(CHAR_HUE)
self.char_hue.setter_callback = self.set_hue
self.char_hue.value = 0
self.char_hue = setup_char(
CHAR_HUE, serv_light, value=0, callback=self.set_hue)
if CHAR_SATURATION in self.chars:
self.char_saturation = serv_light \
.get_characteristic(CHAR_SATURATION)
self.char_saturation.setter_callback = self.set_saturation
self.char_saturation.value = 75
self.char_saturation = setup_char(
CHAR_SATURATION, serv_light, value=75,
callback=self.set_saturation)
def set_state(self, value):
"""Set state if call came from HomeKit."""
@ -136,11 +127,8 @@ class Light(HomeAccessory):
self.hass.components.light.turn_on(
self.entity_id, hs_color=color)
def update_state(self, entity_id=None, old_state=None, new_state=None):
def update_state(self, new_state):
"""Update light after state change."""
if not new_state:
return
# Handle State
state = new_state.state
if state in (STATE_ON, STATE_OFF):
@ -162,7 +150,8 @@ class Light(HomeAccessory):
if CHAR_COLOR_TEMPERATURE in self.chars:
color_temperature = new_state.attributes.get(ATTR_COLOR_TEMP)
if not self._flag[CHAR_COLOR_TEMPERATURE] \
and isinstance(color_temperature, int):
and isinstance(color_temperature, int) and \
self.char_color_temperature.value != color_temperature:
self.char_color_temperature.set_value(color_temperature)
self._flag[CHAR_COLOR_TEMPERATURE] = False

View File

@ -5,7 +5,7 @@ from homeassistant.components.lock import (
ATTR_ENTITY_ID, STATE_LOCKED, STATE_UNLOCKED, STATE_UNKNOWN)
from . import TYPES
from .accessories import HomeAccessory, add_preload_service
from .accessories import HomeAccessory, add_preload_service, setup_char
from .const import (
CATEGORY_LOCK, SERV_LOCK, CHAR_LOCK_CURRENT_STATE, CHAR_LOCK_TARGET_STATE)
@ -27,25 +27,18 @@ class Lock(HomeAccessory):
The lock entity must support: unlock and lock.
"""
def __init__(self, hass, entity_id, name, **kwargs):
def __init__(self, *args, config):
"""Initialize a Lock accessory object."""
super().__init__(name, entity_id, CATEGORY_LOCK, **kwargs)
self.hass = hass
self.entity_id = entity_id
super().__init__(*args, category=CATEGORY_LOCK)
self.flag_target_state = False
serv_lock_mechanism = add_preload_service(self, SERV_LOCK)
self.char_current_state = serv_lock_mechanism. \
get_characteristic(CHAR_LOCK_CURRENT_STATE)
self.char_target_state = serv_lock_mechanism. \
get_characteristic(CHAR_LOCK_TARGET_STATE)
self.char_current_state.value = HASS_TO_HOMEKIT[STATE_UNKNOWN]
self.char_target_state.value = HASS_TO_HOMEKIT[STATE_LOCKED]
self.char_target_state.setter_callback = self.set_state
self.char_current_state = setup_char(
CHAR_LOCK_CURRENT_STATE, serv_lock_mechanism,
value=HASS_TO_HOMEKIT[STATE_UNKNOWN])
self.char_target_state = setup_char(
CHAR_LOCK_TARGET_STATE, serv_lock_mechanism,
value=HASS_TO_HOMEKIT[STATE_LOCKED], callback=self.set_state)
def set_state(self, value):
"""Set lock state to value if call came from HomeKit."""
@ -58,11 +51,8 @@ class Lock(HomeAccessory):
params = {ATTR_ENTITY_ID: self.entity_id}
self.hass.services.call('lock', service, params)
def update_state(self, entity_id=None, old_state=None, new_state=None):
def update_state(self, new_state):
"""Update lock after state changed."""
if new_state is None:
return
hass_state = new_state.state
if hass_state in HASS_TO_HOMEKIT:
current_lock_state = HASS_TO_HOMEKIT[hass_state]

View File

@ -7,7 +7,7 @@ from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_CODE)
from . import TYPES
from .accessories import HomeAccessory, add_preload_service
from .accessories import HomeAccessory, add_preload_service, setup_char
from .const import (
CATEGORY_ALARM_SYSTEM, SERV_SECURITY_SYSTEM,
CHAR_CURRENT_SECURITY_STATE, CHAR_TARGET_SECURITY_STATE)
@ -27,26 +27,18 @@ STATE_TO_SERVICE = {STATE_ALARM_DISARMED: 'alarm_disarm',
class SecuritySystem(HomeAccessory):
"""Generate an SecuritySystem accessory for an alarm control panel."""
def __init__(self, hass, entity_id, display_name, alarm_code, **kwargs):
def __init__(self, *args, config):
"""Initialize a SecuritySystem accessory object."""
super().__init__(display_name, entity_id,
CATEGORY_ALARM_SYSTEM, **kwargs)
self.hass = hass
self.entity_id = entity_id
self._alarm_code = alarm_code
super().__init__(*args, category=CATEGORY_ALARM_SYSTEM)
self._alarm_code = config[ATTR_CODE]
self.flag_target_state = False
serv_alarm = add_preload_service(self, SERV_SECURITY_SYSTEM)
self.char_current_state = serv_alarm. \
get_characteristic(CHAR_CURRENT_SECURITY_STATE)
self.char_current_state.value = 3
self.char_target_state = serv_alarm. \
get_characteristic(CHAR_TARGET_SECURITY_STATE)
self.char_target_state.value = 3
self.char_target_state.setter_callback = self.set_security_state
self.char_current_state = setup_char(
CHAR_CURRENT_SECURITY_STATE, serv_alarm, value=3)
self.char_target_state = setup_char(
CHAR_TARGET_SECURITY_STATE, serv_alarm, value=3,
callback=self.set_security_state)
def set_security_state(self, value):
"""Move security state to value if call came from HomeKit."""
@ -61,11 +53,8 @@ class SecuritySystem(HomeAccessory):
params[ATTR_CODE] = self._alarm_code
self.hass.services.call('alarm_control_panel', service, params)
def update_state(self, entity_id=None, old_state=None, new_state=None):
def update_state(self, new_state):
"""Update security state after state changed."""
if new_state is None:
return
hass_state = new_state.state
if hass_state in HASS_TO_HOMEKIT:
current_security_state = HASS_TO_HOMEKIT[hass_state]

View File

@ -6,7 +6,7 @@ from homeassistant.const import (
ATTR_DEVICE_CLASS, STATE_ON, STATE_HOME)
from . import TYPES
from .accessories import HomeAccessory, add_preload_service
from .accessories import HomeAccessory, add_preload_service, setup_char
from .const import (
CATEGORY_SENSOR, SERV_HUMIDITY_SENSOR, SERV_TEMPERATURE_SENSOR,
CHAR_CURRENT_HUMIDITY, CHAR_CURRENT_TEMPERATURE, PROP_CELSIUS,
@ -20,10 +20,8 @@ from .const import (
DEVICE_CLASS_SMOKE, SERV_SMOKE_SENSOR, CHAR_SMOKE_DETECTED)
from .util import convert_to_float, temperature_to_homekit
_LOGGER = logging.getLogger(__name__)
BINARY_SENSOR_SERVICE_MAP = {
DEVICE_CLASS_CO2: (SERV_CARBON_DIOXIDE_SENSOR,
CHAR_CARBON_DIOXIDE_DETECTED),
@ -43,24 +41,17 @@ class TemperatureSensor(HomeAccessory):
Sensor entity must return temperature in °C, °F.
"""
def __init__(self, hass, entity_id, name, **kwargs):
def __init__(self, *args, config):
"""Initialize a TemperatureSensor accessory object."""
super().__init__(name, entity_id, CATEGORY_SENSOR, **kwargs)
self.hass = hass
self.entity_id = entity_id
super().__init__(*args, category=CATEGORY_SENSOR)
serv_temp = add_preload_service(self, SERV_TEMPERATURE_SENSOR)
self.char_temp = serv_temp.get_characteristic(CHAR_CURRENT_TEMPERATURE)
self.char_temp.override_properties(properties=PROP_CELSIUS)
self.char_temp.value = 0
self.char_temp = setup_char(
CHAR_CURRENT_TEMPERATURE, serv_temp, value=0,
properties=PROP_CELSIUS)
self.unit = None
def update_state(self, entity_id=None, old_state=None, new_state=None):
def update_state(self, new_state):
"""Update temperature after state changed."""
if new_state is None:
return
unit = new_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT, TEMP_CELSIUS)
temperature = convert_to_float(new_state.state)
if temperature:
@ -74,23 +65,15 @@ class TemperatureSensor(HomeAccessory):
class HumiditySensor(HomeAccessory):
"""Generate a HumiditySensor accessory as humidity sensor."""
def __init__(self, hass, entity_id, name, *args, **kwargs):
def __init__(self, *args, config):
"""Initialize a HumiditySensor accessory object."""
super().__init__(name, entity_id, CATEGORY_SENSOR, *args, **kwargs)
self.hass = hass
self.entity_id = entity_id
super().__init__(*args, category=CATEGORY_SENSOR)
serv_humidity = add_preload_service(self, SERV_HUMIDITY_SENSOR)
self.char_humidity = serv_humidity \
.get_characteristic(CHAR_CURRENT_HUMIDITY)
self.char_humidity.value = 0
self.char_humidity = setup_char(
CHAR_CURRENT_HUMIDITY, serv_humidity, value=0)
def update_state(self, entity_id=None, old_state=None, new_state=None):
def update_state(self, new_state):
"""Update accessory after state change."""
if new_state is None:
return
humidity = convert_to_float(new_state.state)
if humidity:
self.char_humidity.set_value(humidity)
@ -102,28 +85,20 @@ class HumiditySensor(HomeAccessory):
class BinarySensor(HomeAccessory):
"""Generate a BinarySensor accessory as binary sensor."""
def __init__(self, hass, entity_id, name, **kwargs):
def __init__(self, *args, config):
"""Initialize a BinarySensor accessory object."""
super().__init__(name, entity_id, CATEGORY_SENSOR, **kwargs)
self.hass = hass
self.entity_id = entity_id
device_class = hass.states.get(entity_id).attributes \
super().__init__(*args, category=CATEGORY_SENSOR)
device_class = self.hass.states.get(self.entity_id).attributes \
.get(ATTR_DEVICE_CLASS)
service_char = BINARY_SENSOR_SERVICE_MAP[device_class] \
if device_class in BINARY_SENSOR_SERVICE_MAP \
else BINARY_SENSOR_SERVICE_MAP[DEVICE_CLASS_OCCUPANCY]
service = add_preload_service(self, service_char[0])
self.char_detected = service.get_characteristic(service_char[1])
self.char_detected.value = 0
self.char_detected = setup_char(service_char[1], service, value=0)
def update_state(self, entity_id=None, old_state=None, new_state=None):
def update_state(self, new_state):
"""Update accessory after state change."""
if new_state is None:
return
state = new_state.state
detected = (state == STATE_ON) or (state == STATE_HOME)
self.char_detected.set_value(detected)

View File

@ -6,7 +6,7 @@ from homeassistant.const import (
from homeassistant.core import split_entity_id
from . import TYPES
from .accessories import HomeAccessory, add_preload_service
from .accessories import HomeAccessory, add_preload_service, setup_char
from .const import CATEGORY_SWITCH, SERV_SWITCH, CHAR_ON
_LOGGER = logging.getLogger(__name__)
@ -16,20 +16,15 @@ _LOGGER = logging.getLogger(__name__)
class Switch(HomeAccessory):
"""Generate a Switch accessory."""
def __init__(self, hass, entity_id, display_name, **kwargs):
def __init__(self, *args, config):
"""Initialize a Switch accessory object to represent a remote."""
super().__init__(display_name, entity_id, CATEGORY_SWITCH, **kwargs)
self.hass = hass
self.entity_id = entity_id
self._domain = split_entity_id(entity_id)[0]
super().__init__(*args, category=CATEGORY_SWITCH)
self._domain = split_entity_id(self.entity_id)[0]
self.flag_target_state = False
serv_switch = add_preload_service(self, SERV_SWITCH)
self.char_on = serv_switch.get_characteristic(CHAR_ON)
self.char_on.value = False
self.char_on.setter_callback = self.set_state
self.char_on = setup_char(
CHAR_ON, serv_switch, value=False, callback=self.set_state)
def set_state(self, value):
"""Move switch state to value if call came from HomeKit."""
@ -40,15 +35,11 @@ class Switch(HomeAccessory):
self.hass.services.call(self._domain, service,
{ATTR_ENTITY_ID: self.entity_id})
def update_state(self, entity_id=None, old_state=None, new_state=None):
def update_state(self, new_state):
"""Update switch state after state changed."""
if new_state is None:
return
current_state = (new_state.state == STATE_ON)
if not self.flag_target_state:
_LOGGER.debug('%s: Set current state to %s',
self.entity_id, current_state)
self.char_on.set_value(current_state)
self.flag_target_state = False

View File

@ -5,12 +5,15 @@ from homeassistant.components.climate import (
ATTR_CURRENT_TEMPERATURE, ATTR_TEMPERATURE,
ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW,
ATTR_OPERATION_MODE, ATTR_OPERATION_LIST,
STATE_HEAT, STATE_COOL, STATE_AUTO)
STATE_HEAT, STATE_COOL, STATE_AUTO,
SUPPORT_TARGET_TEMPERATURE_HIGH, SUPPORT_TARGET_TEMPERATURE_LOW)
from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT, STATE_OFF, TEMP_CELSIUS, TEMP_FAHRENHEIT)
ATTR_SUPPORTED_FEATURES, ATTR_UNIT_OF_MEASUREMENT,
STATE_OFF, TEMP_CELSIUS, TEMP_FAHRENHEIT)
from . import TYPES
from .accessories import HomeAccessory, add_preload_service, debounce
from .accessories import (
HomeAccessory, add_preload_service, debounce, setup_char)
from .const import (
CATEGORY_THERMOSTAT, SERV_THERMOSTAT, CHAR_CURRENT_HEATING_COOLING,
CHAR_TARGET_HEATING_COOLING, CHAR_CURRENT_TEMPERATURE,
@ -26,74 +29,63 @@ HC_HASS_TO_HOMEKIT = {STATE_OFF: 0, STATE_HEAT: 1,
STATE_COOL: 2, STATE_AUTO: 3}
HC_HOMEKIT_TO_HASS = {c: s for s, c in HC_HASS_TO_HOMEKIT.items()}
SUPPORT_TEMP_RANGE = SUPPORT_TARGET_TEMPERATURE_LOW | \
SUPPORT_TARGET_TEMPERATURE_HIGH
@TYPES.register('Thermostat')
class Thermostat(HomeAccessory):
"""Generate a Thermostat accessory for a climate."""
def __init__(self, hass, entity_id, display_name, support_auto, **kwargs):
def __init__(self, *args, config):
"""Initialize a Thermostat accessory object."""
super().__init__(display_name, entity_id,
CATEGORY_THERMOSTAT, **kwargs)
self.hass = hass
self.entity_id = entity_id
self._call_timer = None
super().__init__(*args, category=CATEGORY_THERMOSTAT)
self._unit = TEMP_CELSIUS
self.heat_cool_flag_target_state = False
self.temperature_flag_target_state = False
self.coolingthresh_flag_target_state = False
self.heatingthresh_flag_target_state = False
# Add additional characteristics if auto mode is supported
extra_chars = [
CHAR_COOLING_THRESHOLD_TEMPERATURE,
CHAR_HEATING_THRESHOLD_TEMPERATURE] if support_auto else None
self.chars = []
features = self.hass.states.get(self.entity_id) \
.attributes.get(ATTR_SUPPORTED_FEATURES)
if features & SUPPORT_TEMP_RANGE:
self.chars.extend((CHAR_COOLING_THRESHOLD_TEMPERATURE,
CHAR_HEATING_THRESHOLD_TEMPERATURE))
# Preload the thermostat service
serv_thermostat = add_preload_service(self, SERV_THERMOSTAT,
extra_chars)
serv_thermostat = add_preload_service(
self, SERV_THERMOSTAT, self.chars)
# Current and target mode characteristics
self.char_current_heat_cool = serv_thermostat. \
get_characteristic(CHAR_CURRENT_HEATING_COOLING)
self.char_current_heat_cool.value = 0
self.char_target_heat_cool = serv_thermostat. \
get_characteristic(CHAR_TARGET_HEATING_COOLING)
self.char_target_heat_cool.value = 0
self.char_target_heat_cool.setter_callback = self.set_heat_cool
self.char_current_heat_cool = setup_char(
CHAR_CURRENT_HEATING_COOLING, serv_thermostat, value=0)
self.char_target_heat_cool = setup_char(
CHAR_TARGET_HEATING_COOLING, serv_thermostat, value=0,
callback=self.set_heat_cool)
# Current and target temperature characteristics
self.char_current_temp = serv_thermostat. \
get_characteristic(CHAR_CURRENT_TEMPERATURE)
self.char_current_temp.value = 21.0
self.char_target_temp = serv_thermostat. \
get_characteristic(CHAR_TARGET_TEMPERATURE)
self.char_target_temp.value = 21.0
self.char_target_temp.setter_callback = self.set_target_temperature
self.char_current_temp = setup_char(
CHAR_CURRENT_TEMPERATURE, serv_thermostat, value=21.0)
self.char_target_temp = setup_char(
CHAR_TARGET_TEMPERATURE, serv_thermostat, value=21.0,
callback=self.set_target_temperature)
# Display units characteristic
self.char_display_units = serv_thermostat. \
get_characteristic(CHAR_TEMP_DISPLAY_UNITS)
self.char_display_units.value = 0
self.char_display_units = setup_char(
CHAR_TEMP_DISPLAY_UNITS, serv_thermostat, value=0)
# If the device supports it: high and low temperature characteristics
if support_auto:
self.char_cooling_thresh_temp = serv_thermostat. \
get_characteristic(CHAR_COOLING_THRESHOLD_TEMPERATURE)
self.char_cooling_thresh_temp.value = 23.0
self.char_cooling_thresh_temp.setter_callback = \
self.set_cooling_threshold
self.char_heating_thresh_temp = serv_thermostat. \
get_characteristic(CHAR_HEATING_THRESHOLD_TEMPERATURE)
self.char_heating_thresh_temp.value = 19.0
self.char_heating_thresh_temp.setter_callback = \
self.set_heating_threshold
else:
self.char_cooling_thresh_temp = None
self.char_heating_thresh_temp = None
self.char_cooling_thresh_temp = None
self.char_heating_thresh_temp = None
if CHAR_COOLING_THRESHOLD_TEMPERATURE in self.chars:
self.char_cooling_thresh_temp = setup_char(
CHAR_COOLING_THRESHOLD_TEMPERATURE, serv_thermostat,
value=23.0, callback=self.set_cooling_threshold)
if CHAR_HEATING_THRESHOLD_TEMPERATURE in self.chars:
self.char_heating_thresh_temp = setup_char(
CHAR_HEATING_THRESHOLD_TEMPERATURE, serv_thermostat,
value=19.0, callback=self.set_heating_threshold)
def set_heat_cool(self, value):
"""Move operation mode to value if call came from HomeKit."""
@ -141,11 +133,8 @@ class Thermostat(HomeAccessory):
self.hass.components.climate.set_temperature(
temperature=value, entity_id=self.entity_id)
def update_state(self, entity_id=None, old_state=None, new_state=None):
def update_state(self, new_state):
"""Update security state after state changed."""
if new_state is None:
return
self._unit = new_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT,
TEMP_CELSIUS)

View File

@ -33,7 +33,7 @@ def validate_entity_config(values):
return entities
def show_setup_message(bridge, hass):
def show_setup_message(hass, bridge):
"""Display persistent notification with setup information."""
pin = bridge.pincode.decode()
_LOGGER.info('Pincode: %s', pin)

View File

@ -10,9 +10,8 @@ from homeassistant.components.homekit.accessories import (
add_preload_service, set_accessory_info,
debounce, HomeAccessory, HomeBridge, HomeDriver)
from homeassistant.components.homekit.const import (
ACCESSORY_MODEL, ACCESSORY_NAME, BRIDGE_MODEL, BRIDGE_NAME,
SERV_ACCESSORY_INFO, CHAR_MANUFACTURER, CHAR_MODEL,
CHAR_NAME, CHAR_SERIAL_NUMBER)
BRIDGE_MODEL, BRIDGE_NAME, SERV_ACCESSORY_INFO,
CHAR_MANUFACTURER, CHAR_MODEL, CHAR_NAME, CHAR_SERIAL_NUMBER)
from homeassistant.const import ATTR_NOW, EVENT_TIME_CHANGED
import homeassistant.util.dt as dt_util
@ -92,7 +91,7 @@ class TestAccessories(unittest.TestCase):
def test_set_accessory_info(self):
"""Test setting the basic accessory information."""
# Test HomeAccessory
acc = HomeAccessory()
acc = HomeAccessory('HA', 'Home Accessory', 'homekit.accessory', 2, '')
set_accessory_info(acc, 'name', 'model', 'manufacturer', '0000')
serv = acc.get_service(SERV_ACCESSORY_INFO)
@ -104,7 +103,7 @@ class TestAccessories(unittest.TestCase):
serv.get_characteristic(CHAR_SERIAL_NUMBER).value, '0000')
# Test HomeBridge
acc = HomeBridge(None)
acc = HomeBridge('hass')
set_accessory_info(acc, 'name', 'model', 'manufacturer', '0000')
serv = acc.get_service(SERV_ACCESSORY_INFO)
@ -116,26 +115,37 @@ class TestAccessories(unittest.TestCase):
def test_home_accessory(self):
"""Test HomeAccessory class."""
acc = HomeAccessory()
self.assertEqual(acc.display_name, ACCESSORY_NAME)
hass = get_test_home_assistant()
acc = HomeAccessory(hass, 'Home Accessory', 'homekit.accessory', 2, '')
self.assertEqual(acc.hass, hass)
self.assertEqual(acc.display_name, 'Home Accessory')
self.assertEqual(acc.category, 1) # Category.OTHER
self.assertEqual(len(acc.services), 1)
serv = acc.services[0] # SERV_ACCESSORY_INFO
self.assertEqual(
serv.get_characteristic(CHAR_MODEL).value, ACCESSORY_MODEL)
serv.get_characteristic(CHAR_MODEL).value, 'homekit.accessory')
acc = HomeAccessory('test_name', 'test_model', 'FAN', aid=2)
hass.states.set('homekit.accessory', 'on')
hass.block_till_done()
acc.run()
hass.states.set('homekit.accessory', 'off')
hass.block_till_done()
acc = HomeAccessory('hass', 'test_name', 'test_model', 2, '')
self.assertEqual(acc.display_name, 'test_name')
self.assertEqual(acc.category, 3) # Category.FAN
self.assertEqual(acc.aid, 2)
self.assertEqual(len(acc.services), 1)
serv = acc.services[0] # SERV_ACCESSORY_INFO
self.assertEqual(
serv.get_characteristic(CHAR_MODEL).value, 'test_model')
hass.stop()
def test_home_bridge(self):
"""Test HomeBridge class."""
bridge = HomeBridge(None)
bridge = HomeBridge('hass')
self.assertEqual(bridge.hass, 'hass')
self.assertEqual(bridge.display_name, BRIDGE_NAME)
self.assertEqual(bridge.category, 2) # Category.BRIDGE
self.assertEqual(len(bridge.services), 1)
@ -144,12 +154,10 @@ class TestAccessories(unittest.TestCase):
self.assertEqual(
serv.get_characteristic(CHAR_MODEL).value, BRIDGE_MODEL)
bridge = HomeBridge('hass', 'test_name', 'test_model')
bridge = HomeBridge('hass', 'test_name')
self.assertEqual(bridge.display_name, 'test_name')
self.assertEqual(len(bridge.services), 1)
serv = bridge.services[0] # SERV_ACCESSORY_INFO
self.assertEqual(
serv.get_characteristic(CHAR_MODEL).value, 'test_model')
# setup_message
bridge.setup_message()
@ -174,11 +182,11 @@ class TestAccessories(unittest.TestCase):
self.assertEqual(
mock_remove_paired_client.call_args, call('client_uuid'))
self.assertEqual(mock_show_msg.call_args, call(bridge, 'hass'))
self.assertEqual(mock_show_msg.call_args, call('hass', bridge))
def test_home_driver(self):
"""Test HomeDriver class."""
bridge = HomeBridge(None)
bridge = HomeBridge('hass')
ip_address = '127.0.0.1'
port = 51826
path = '.homekit.state'

View File

@ -19,14 +19,14 @@ CONFIG = {}
def test_get_accessory_invalid_aid(caplog):
"""Test with unsupported component."""
assert get_accessory(None, State('light.demo', 'on'),
aid=None, config=None) is None
None, config=None) is None
assert caplog.records[0].levelname == 'WARNING'
assert 'invalid aid' in caplog.records[0].msg
def test_not_supported():
"""Test if none is returned if entity isn't supported."""
assert get_accessory(None, State('demo.demo', 'on'), aid=2, config=None) \
assert get_accessory(None, State('demo.demo', 'on'), 2, config=None) \
is None
@ -48,7 +48,6 @@ class TestGetAccessories(unittest.TestCase):
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS})
get_accessory(None, state, 2, {})
# pylint: disable=invalid-name
def test_sensor_temperature_fahrenheit(self):
"""Test temperature sensor with Fahrenheit as unit."""
with patch.dict(TYPES, {'TemperatureSensor': self.mock_type}):
@ -91,8 +90,9 @@ class TestGetAccessories(unittest.TestCase):
get_accessory(None, state, 2, config)
# pylint: disable=unsubscriptable-object
print(self.mock_type.call_args[1])
self.assertEqual(
self.mock_type.call_args[1].get('alarm_code'), '1234')
self.mock_type.call_args[1]['config'][ATTR_CODE], '1234')
def test_climate(self):
"""Test climate devices."""
@ -100,10 +100,6 @@ class TestGetAccessories(unittest.TestCase):
state = State('climate.test', 'auto')
get_accessory(None, state, 2, {})
# pylint: disable=unsubscriptable-object
self.assertEqual(
self.mock_type.call_args[0][-1], False) # support_auto
def test_light(self):
"""Test light devices."""
with patch.dict(TYPES, {'Light': self.mock_type}):
@ -119,10 +115,6 @@ class TestGetAccessories(unittest.TestCase):
SUPPORT_TARGET_TEMPERATURE_HIGH})
get_accessory(None, state, 2, {})
# pylint: disable=unsubscriptable-object
self.assertEqual(
self.mock_type.call_args[0][-1], True) # support_auto
def test_switch(self):
"""Test switch."""
with patch.dict(TYPES, {'Switch': self.mock_type}):
@ -140,3 +132,9 @@ class TestGetAccessories(unittest.TestCase):
with patch.dict(TYPES, {'Switch': self.mock_type}):
state = State('input_boolean.test', 'on')
get_accessory(None, state, 2, {})
def test_lock(self):
"""Test lock."""
with patch.dict(TYPES, {'Lock': self.mock_type}):
state = State('lock.test', 'locked')
get_accessory(None, state, 2, {})

View File

@ -173,7 +173,7 @@ class TestHomeKit(unittest.TestCase):
self.assertEqual(mock_add_bridge_acc.mock_calls, [call(state)])
self.assertEqual(mock_show_setup_msg.mock_calls, [
call(homekit.bridge, self.hass)])
call(self.hass, homekit.bridge)])
self.assertEqual(homekit.driver.mock_calls, [call.start()])
self.assertTrue(homekit.started)

View File

@ -35,7 +35,7 @@ class TestHomekitSensors(unittest.TestCase):
"""Test if accessory and HA are updated accordingly."""
window_cover = 'cover.window'
acc = WindowCovering(self.hass, window_cover, 'Cover', aid=2)
acc = WindowCovering(self.hass, 'Cover', window_cover, 2, config=None)
acc.run()
self.assertEqual(acc.aid, 2)

View File

@ -50,9 +50,11 @@ class TestHomekitLights(unittest.TestCase):
def test_light_basic(self):
"""Test light with char state."""
entity_id = 'light.demo'
self.hass.states.set(entity_id, STATE_ON,
{ATTR_SUPPORTED_FEATURES: 0})
acc = self.light_cls(self.hass, entity_id, 'Light', aid=2)
self.hass.block_till_done()
acc = self.light_cls(self.hass, 'Light', entity_id, 2, config=None)
self.assertEqual(acc.aid, 2)
self.assertEqual(acc.category, 5) # Lightbulb
self.assertEqual(acc.char_on.value, 0)
@ -94,9 +96,11 @@ class TestHomekitLights(unittest.TestCase):
def test_light_brightness(self):
"""Test light with brightness."""
entity_id = 'light.demo'
self.hass.states.set(entity_id, STATE_ON, {
ATTR_SUPPORTED_FEATURES: SUPPORT_BRIGHTNESS, ATTR_BRIGHTNESS: 255})
acc = self.light_cls(self.hass, entity_id, 'Light', aid=2)
self.hass.block_till_done()
acc = self.light_cls(self.hass, 'Light', entity_id, 2, config=None)
self.assertEqual(acc.char_brightness.value, 0)
acc.run()
@ -135,10 +139,12 @@ class TestHomekitLights(unittest.TestCase):
def test_light_color_temperature(self):
"""Test light with color temperature."""
entity_id = 'light.demo'
self.hass.states.set(entity_id, STATE_ON, {
ATTR_SUPPORTED_FEATURES: SUPPORT_COLOR_TEMP,
ATTR_COLOR_TEMP: 190})
acc = self.light_cls(self.hass, entity_id, 'Light', aid=2)
self.hass.block_till_done()
acc = self.light_cls(self.hass, 'Light', entity_id, 2, config=None)
self.assertEqual(acc.char_color_temperature.value, 153)
acc.run()
@ -157,10 +163,12 @@ class TestHomekitLights(unittest.TestCase):
def test_light_rgb_color(self):
"""Test light with rgb_color."""
entity_id = 'light.demo'
self.hass.states.set(entity_id, STATE_ON, {
ATTR_SUPPORTED_FEATURES: SUPPORT_COLOR,
ATTR_HS_COLOR: (260, 90)})
acc = self.light_cls(self.hass, entity_id, 'Light', aid=2)
self.hass.block_till_done()
acc = self.light_cls(self.hass, 'Light', entity_id, 2, config=None)
self.assertEqual(acc.char_hue.value, 0)
self.assertEqual(acc.char_saturation.value, 75)

View File

@ -33,7 +33,7 @@ class TestHomekitSensors(unittest.TestCase):
"""Test if accessory and HA are updated accordingly."""
kitchen_lock = 'lock.kitchen_door'
acc = Lock(self.hass, kitchen_lock, 'Lock', aid=2)
acc = Lock(self.hass, 'Lock', kitchen_lock, 2, config=None)
acc.run()
self.assertEqual(acc.aid, 2)

View File

@ -35,8 +35,8 @@ class TestHomekitSecuritySystems(unittest.TestCase):
"""Test if accessory and HA are updated accordingly."""
acp = 'alarm_control_panel.test'
acc = SecuritySystem(self.hass, acp, 'SecuritySystem',
alarm_code='1234', aid=2)
acc = SecuritySystem(self.hass, 'SecuritySystem', acp,
2, config={ATTR_CODE: '1234'})
acc.run()
self.assertEqual(acc.aid, 2)
@ -107,8 +107,8 @@ class TestHomekitSecuritySystems(unittest.TestCase):
"""Test accessory if security_system doesn't require a alarm_code."""
acp = 'alarm_control_panel.test'
acc = SecuritySystem(self.hass, acp, 'SecuritySystem',
alarm_code=None, aid=2)
acc = SecuritySystem(self.hass, 'SecuritySystem', acp,
2, config={ATTR_CODE: None})
acc.run()
# Set from HomeKit

View File

@ -26,7 +26,8 @@ class TestHomekitSensors(unittest.TestCase):
"""Test if accessory is updated after state change."""
entity_id = 'sensor.temperature'
acc = TemperatureSensor(self.hass, entity_id, 'Temperature', aid=2)
acc = TemperatureSensor(self.hass, 'Temperature', entity_id,
2, config=None)
acc.run()
self.assertEqual(acc.aid, 2)
@ -54,7 +55,7 @@ class TestHomekitSensors(unittest.TestCase):
"""Test if accessory is updated after state change."""
entity_id = 'sensor.humidity'
acc = HumiditySensor(self.hass, entity_id, 'Humidity', aid=2)
acc = HumiditySensor(self.hass, 'Humidity', entity_id, 2, config=None)
acc.run()
self.assertEqual(acc.aid, 2)
@ -78,7 +79,8 @@ class TestHomekitSensors(unittest.TestCase):
{ATTR_DEVICE_CLASS: "opening"})
self.hass.block_till_done()
acc = BinarySensor(self.hass, entity_id, 'Window Opening', aid=2)
acc = BinarySensor(self.hass, 'Window Opening', entity_id,
2, config=None)
acc.run()
self.assertEqual(acc.aid, 2)
@ -118,6 +120,7 @@ class TestHomekitSensors(unittest.TestCase):
{ATTR_DEVICE_CLASS: device_class})
self.hass.block_till_done()
acc = BinarySensor(self.hass, entity_id, 'Binary Sensor', aid=2)
acc = BinarySensor(self.hass, 'Binary Sensor', entity_id,
2, config=None)
self.assertEqual(acc.get_service(service).display_name, service)
self.assertEqual(acc.char_detected.display_name, char)

View File

@ -34,7 +34,7 @@ class TestHomekitSwitches(unittest.TestCase):
entity_id = 'switch.test'
domain = split_entity_id(entity_id)[0]
acc = Switch(self.hass, entity_id, 'Switch', aid=2)
acc = Switch(self.hass, 'Switch', entity_id, 2, config=None)
acc.run()
self.assertEqual(acc.aid, 2)
@ -70,7 +70,7 @@ class TestHomekitSwitches(unittest.TestCase):
entity_id = 'remote.test'
domain = split_entity_id(entity_id)[0]
acc = Switch(self.hass, entity_id, 'Switch', aid=2)
acc = Switch(self.hass, 'Switch', entity_id, 2, config=None)
acc.run()
self.assertEqual(acc.char_on.value, False)
@ -89,7 +89,7 @@ class TestHomekitSwitches(unittest.TestCase):
entity_id = 'input_boolean.test'
domain = split_entity_id(entity_id)[0]
acc = Switch(self.hass, entity_id, 'Switch', aid=2)
acc = Switch(self.hass, 'Switch', entity_id, 2, config=None)
acc.run()
self.assertEqual(acc.char_on.value, False)

View File

@ -7,8 +7,9 @@ from homeassistant.components.climate import (
ATTR_TARGET_TEMP_LOW, ATTR_TARGET_TEMP_HIGH, ATTR_OPERATION_MODE,
ATTR_OPERATION_LIST, STATE_COOL, STATE_HEAT, STATE_AUTO)
from homeassistant.const import (
ATTR_SERVICE, EVENT_CALL_SERVICE, ATTR_SERVICE_DATA,
ATTR_UNIT_OF_MEASUREMENT, STATE_OFF, TEMP_CELSIUS, TEMP_FAHRENHEIT)
ATTR_SERVICE, ATTR_SERVICE_DATA, ATTR_SUPPORTED_FEATURES,
ATTR_UNIT_OF_MEASUREMENT, EVENT_CALL_SERVICE,
STATE_OFF, TEMP_CELSIUS, TEMP_FAHRENHEIT)
from tests.common import get_test_home_assistant
from tests.components.homekit.test_accessories import patch_debounce
@ -52,7 +53,10 @@ class TestHomekitThermostats(unittest.TestCase):
"""Test if accessory and HA are updated accordingly."""
climate = 'climate.test'
acc = self.thermostat_cls(self.hass, climate, 'Climate', False, aid=2)
self.hass.states.set(climate, STATE_OFF, {ATTR_SUPPORTED_FEATURES: 0})
self.hass.block_till_done()
acc = self.thermostat_cls(self.hass, 'Climate', climate,
2, config=None)
acc.run()
self.assertEqual(acc.aid, 2)
@ -187,7 +191,11 @@ class TestHomekitThermostats(unittest.TestCase):
"""Test if accessory and HA are updated accordingly."""
climate = 'climate.test'
acc = self.thermostat_cls(self.hass, climate, 'Climate', True)
# support_auto = True
self.hass.states.set(climate, STATE_OFF, {ATTR_SUPPORTED_FEATURES: 6})
self.hass.block_till_done()
acc = self.thermostat_cls(self.hass, 'Climate', climate,
2, config=None)
acc.run()
self.assertEqual(acc.char_cooling_thresh_temp.value, 23.0)
@ -257,7 +265,11 @@ class TestHomekitThermostats(unittest.TestCase):
"""Test if accessory and HA are updated accordingly."""
climate = 'climate.test'
acc = self.thermostat_cls(self.hass, climate, 'Climate', True)
# support_auto = True
self.hass.states.set(climate, STATE_OFF, {ATTR_SUPPORTED_FEATURES: 6})
self.hass.block_till_done()
acc = self.thermostat_cls(self.hass, 'Climate', climate,
2, config=None)
acc.run()
self.hass.states.set(climate, STATE_AUTO,

View File

@ -58,7 +58,7 @@ class TestUtil(unittest.TestCase):
"""Test show setup message as persistence notification."""
bridge = HomeBridge(self.hass)
show_setup_message(bridge, self.hass)
show_setup_message(self.hass, bridge)
self.hass.block_till_done()
data = self.events[0].data