mirror of
https://github.com/home-assistant/core.git
synced 2025-07-27 15:17:35 +00:00
Homekit refactor (#13707)
This commit is contained in:
parent
8d48164f25
commit
2a5751c09d
@ -8,11 +8,9 @@ from zlib import adler32
|
|||||||
|
|
||||||
import voluptuous as vol
|
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.components.cover import SUPPORT_SET_POSITION
|
||||||
from homeassistant.const import (
|
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,
|
CONF_PORT, TEMP_CELSIUS, TEMP_FAHRENHEIT,
|
||||||
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
|
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
@ -79,64 +77,47 @@ def get_accessory(hass, state, aid, config):
|
|||||||
state.entity_id)
|
state.entity_id)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if state.domain == 'sensor':
|
a_type = None
|
||||||
unit = state.attributes.get(ATTR_UNIT_OF_MEASUREMENT)
|
config = config or {}
|
||||||
if unit == TEMP_CELSIUS or unit == TEMP_FAHRENHEIT:
|
|
||||||
_LOGGER.debug('Add "%s" as "%s"',
|
if state.domain == 'alarm_control_panel':
|
||||||
state.entity_id, 'TemperatureSensor')
|
a_type = 'SecuritySystem'
|
||||||
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)
|
|
||||||
|
|
||||||
elif state.domain == 'binary_sensor' or state.domain == 'device_tracker':
|
elif state.domain == 'binary_sensor' or state.domain == 'device_tracker':
|
||||||
_LOGGER.debug('Add "%s" as "%s"', state.entity_id, 'BinarySensor')
|
a_type = 'BinarySensor'
|
||||||
return TYPES['BinarySensor'](hass, state.entity_id,
|
|
||||||
state.name, aid=aid)
|
elif state.domain == 'climate':
|
||||||
|
a_type = 'Thermostat'
|
||||||
|
|
||||||
elif state.domain == 'cover':
|
elif state.domain == 'cover':
|
||||||
# Only add covers that support set_cover_position
|
# Only add covers that support set_cover_position
|
||||||
features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
features = state.attributes.get(ATTR_SUPPORTED_FEATURES, 0)
|
||||||
if features & SUPPORT_SET_POSITION:
|
if features & SUPPORT_SET_POSITION:
|
||||||
_LOGGER.debug('Add "%s" as "%s"',
|
a_type = 'WindowCovering'
|
||||||
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)
|
|
||||||
|
|
||||||
elif state.domain == 'light':
|
elif state.domain == 'light':
|
||||||
_LOGGER.debug('Add "%s" as "%s"', state.entity_id, 'Light')
|
a_type = 'Light'
|
||||||
return TYPES['Light'](hass, state.entity_id, state.name, aid=aid)
|
|
||||||
|
|
||||||
elif state.domain == 'lock':
|
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' \
|
elif state.domain == 'switch' or state.domain == 'remote' \
|
||||||
or state.domain == 'input_boolean' or state.domain == 'script':
|
or state.domain == 'input_boolean' or state.domain == 'script':
|
||||||
_LOGGER.debug('Add "%s" as "%s"', state.entity_id, 'Switch')
|
a_type = 'Switch'
|
||||||
return TYPES['Switch'](hass, state.entity_id, state.name, aid=aid)
|
|
||||||
|
|
||||||
|
if a_type is None:
|
||||||
return 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):
|
def generate_aid(entity_id):
|
||||||
"""Generate accessory aid with zlib adler32."""
|
"""Generate accessory aid with zlib adler32."""
|
||||||
@ -151,7 +132,7 @@ class HomeKit():
|
|||||||
|
|
||||||
def __init__(self, hass, port, entity_filter, entity_config):
|
def __init__(self, hass, port, entity_filter, entity_config):
|
||||||
"""Initialize a HomeKit object."""
|
"""Initialize a HomeKit object."""
|
||||||
self._hass = hass
|
self.hass = hass
|
||||||
self._port = port
|
self._port = port
|
||||||
self._filter = entity_filter
|
self._filter = entity_filter
|
||||||
self._config = entity_config
|
self._config = entity_config
|
||||||
@ -164,11 +145,11 @@ class HomeKit():
|
|||||||
"""Setup bridge and accessory driver."""
|
"""Setup bridge and accessory driver."""
|
||||||
from .accessories import HomeBridge, HomeDriver
|
from .accessories import HomeBridge, HomeDriver
|
||||||
|
|
||||||
self._hass.bus.async_listen_once(
|
self.hass.bus.async_listen_once(
|
||||||
EVENT_HOMEASSISTANT_STOP, self.stop)
|
EVENT_HOMEASSISTANT_STOP, self.stop)
|
||||||
|
|
||||||
path = self._hass.config.path(HOMEKIT_FILE)
|
path = self.hass.config.path(HOMEKIT_FILE)
|
||||||
self.bridge = HomeBridge(self._hass)
|
self.bridge = HomeBridge(self.hass)
|
||||||
self.driver = HomeDriver(self.bridge, self._port, get_local_ip(), path)
|
self.driver = HomeDriver(self.bridge, self._port, get_local_ip(), path)
|
||||||
|
|
||||||
def add_bridge_accessory(self, state):
|
def add_bridge_accessory(self, state):
|
||||||
@ -177,7 +158,7 @@ class HomeKit():
|
|||||||
return
|
return
|
||||||
aid = generate_aid(state.entity_id)
|
aid = generate_aid(state.entity_id)
|
||||||
conf = self._config.pop(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:
|
if acc is not None:
|
||||||
self.bridge.add_accessory(acc)
|
self.bridge.add_accessory(acc)
|
||||||
|
|
||||||
@ -192,12 +173,12 @@ class HomeKit():
|
|||||||
type_covers, type_lights, type_locks, type_security_systems,
|
type_covers, type_lights, type_locks, type_security_systems,
|
||||||
type_sensors, type_switches, type_thermostats)
|
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.add_bridge_accessory(state)
|
||||||
self.bridge.set_broker(self.driver)
|
self.bridge.set_broker(self.driver)
|
||||||
|
|
||||||
if not self.bridge.paired:
|
if not self.bridge.paired:
|
||||||
show_setup_message(self.bridge, self._hass)
|
show_setup_message(self.hass, self.bridge)
|
||||||
|
|
||||||
_LOGGER.debug('Driver start')
|
_LOGGER.debug('Driver start')
|
||||||
self.driver.start()
|
self.driver.start()
|
||||||
|
@ -7,14 +7,14 @@ import logging
|
|||||||
from pyhap.accessory import Accessory, Bridge, Category
|
from pyhap.accessory import Accessory, Bridge, Category
|
||||||
from pyhap.accessory_driver import AccessoryDriver
|
from pyhap.accessory_driver import AccessoryDriver
|
||||||
|
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback as ha_callback
|
||||||
from homeassistant.helpers.event import (
|
from homeassistant.helpers.event import (
|
||||||
async_track_state_change, track_point_in_utc_time)
|
async_track_state_change, track_point_in_utc_time)
|
||||||
from homeassistant.util import dt as dt_util
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from .const import (
|
from .const import (
|
||||||
DEBOUNCE_TIMEOUT, ACCESSORY_MODEL, ACCESSORY_NAME, BRIDGE_MODEL,
|
DEBOUNCE_TIMEOUT, BRIDGE_MODEL, BRIDGE_NAME, MANUFACTURER,
|
||||||
BRIDGE_NAME, MANUFACTURER, SERV_ACCESSORY_INFO, CHAR_MANUFACTURER,
|
SERV_ACCESSORY_INFO, CHAR_MANUFACTURER,
|
||||||
CHAR_MODEL, CHAR_NAME, CHAR_SERIAL_NUMBER)
|
CHAR_MODEL, CHAR_NAME, CHAR_SERIAL_NUMBER)
|
||||||
from .util import (
|
from .util import (
|
||||||
show_setup_message, dismiss_setup_message)
|
show_setup_message, dismiss_setup_message)
|
||||||
@ -24,7 +24,7 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
|
|
||||||
def debounce(func):
|
def debounce(func):
|
||||||
"""Decorator function. Debounce callbacks form HomeKit."""
|
"""Decorator function. Debounce callbacks form HomeKit."""
|
||||||
@callback
|
@ha_callback
|
||||||
def call_later_listener(*args):
|
def call_later_listener(*args):
|
||||||
"""Callback listener called from call_later."""
|
"""Callback listener called from call_later."""
|
||||||
# pylint: disable=unsubscriptable-object
|
# pylint: disable=unsubscriptable-object
|
||||||
@ -72,6 +72,18 @@ def add_preload_service(acc, service, chars=None):
|
|||||||
return service
|
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,
|
def set_accessory_info(acc, name, model, manufacturer=MANUFACTURER,
|
||||||
serial_number='0000'):
|
serial_number='0000'):
|
||||||
"""Set the default accessory information."""
|
"""Set the default accessory information."""
|
||||||
@ -85,14 +97,13 @@ def set_accessory_info(acc, name, model, manufacturer=MANUFACTURER,
|
|||||||
class HomeAccessory(Accessory):
|
class HomeAccessory(Accessory):
|
||||||
"""Adapter class for Accessory."""
|
"""Adapter class for Accessory."""
|
||||||
|
|
||||||
# pylint: disable=no-member
|
def __init__(self, hass, name, entity_id, aid, category):
|
||||||
|
|
||||||
def __init__(self, name=ACCESSORY_NAME, model=ACCESSORY_MODEL,
|
|
||||||
category='OTHER', **kwargs):
|
|
||||||
"""Initialize a Accessory object."""
|
"""Initialize a Accessory object."""
|
||||||
super().__init__(name, **kwargs)
|
super().__init__(name, aid=aid)
|
||||||
set_accessory_info(self, name, model)
|
set_accessory_info(self, name, model=entity_id)
|
||||||
self.category = getattr(Category, category, Category.OTHER)
|
self.category = getattr(Category, category, Category.OTHER)
|
||||||
|
self.entity_id = entity_id
|
||||||
|
self.hass = hass
|
||||||
|
|
||||||
def _set_services(self):
|
def _set_services(self):
|
||||||
add_preload_service(self, SERV_ACCESSORY_INFO)
|
add_preload_service(self, SERV_ACCESSORY_INFO)
|
||||||
@ -100,19 +111,33 @@ class HomeAccessory(Accessory):
|
|||||||
def run(self):
|
def run(self):
|
||||||
"""Method called by accessory after driver is started."""
|
"""Method called by accessory after driver is started."""
|
||||||
state = self.hass.states.get(self.entity_id)
|
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(
|
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):
|
class HomeBridge(Bridge):
|
||||||
"""Adapter class for Bridge."""
|
"""Adapter class for Bridge."""
|
||||||
|
|
||||||
def __init__(self, hass, name=BRIDGE_NAME,
|
def __init__(self, hass, name=BRIDGE_NAME):
|
||||||
model=BRIDGE_MODEL, **kwargs):
|
|
||||||
"""Initialize a Bridge object."""
|
"""Initialize a Bridge object."""
|
||||||
super().__init__(name, **kwargs)
|
super().__init__(name)
|
||||||
set_accessory_info(self, name, model)
|
set_accessory_info(self, name, model=BRIDGE_MODEL)
|
||||||
self.hass = hass
|
self.hass = hass
|
||||||
|
|
||||||
def _set_services(self):
|
def _set_services(self):
|
||||||
@ -130,7 +155,7 @@ class HomeBridge(Bridge):
|
|||||||
def remove_paired_client(self, client_uuid):
|
def remove_paired_client(self, client_uuid):
|
||||||
"""Override super function to show setup message if unpaired."""
|
"""Override super function to show setup message if unpaired."""
|
||||||
super().remove_paired_client(client_uuid)
|
super().remove_paired_client(client_uuid)
|
||||||
show_setup_message(self, self.hass)
|
show_setup_message(self.hass, self)
|
||||||
|
|
||||||
|
|
||||||
class HomeDriver(AccessoryDriver):
|
class HomeDriver(AccessoryDriver):
|
||||||
|
@ -18,8 +18,6 @@ DEFAULT_PORT = 51827
|
|||||||
SERVICE_HOMEKIT_START = 'start'
|
SERVICE_HOMEKIT_START = 'start'
|
||||||
|
|
||||||
# #### STRING CONSTANTS ####
|
# #### STRING CONSTANTS ####
|
||||||
ACCESSORY_MODEL = 'homekit.accessory'
|
|
||||||
ACCESSORY_NAME = 'Home Accessory'
|
|
||||||
BRIDGE_MODEL = 'homekit.bridge'
|
BRIDGE_MODEL = 'homekit.bridge'
|
||||||
BRIDGE_NAME = 'Home Assistant'
|
BRIDGE_NAME = 'Home Assistant'
|
||||||
MANUFACTURER = 'HomeAssistant'
|
MANUFACTURER = 'HomeAssistant'
|
||||||
|
@ -4,12 +4,11 @@ import logging
|
|||||||
from homeassistant.components.cover import ATTR_CURRENT_POSITION
|
from homeassistant.components.cover import ATTR_CURRENT_POSITION
|
||||||
|
|
||||||
from . import TYPES
|
from . import TYPES
|
||||||
from .accessories import HomeAccessory, add_preload_service
|
from .accessories import HomeAccessory, add_preload_service, setup_char
|
||||||
from .const import (
|
from .const import (
|
||||||
CATEGORY_WINDOW_COVERING, SERV_WINDOW_COVERING,
|
CATEGORY_WINDOW_COVERING, SERV_WINDOW_COVERING,
|
||||||
CHAR_CURRENT_POSITION, CHAR_TARGET_POSITION, CHAR_POSITION_STATE)
|
CHAR_CURRENT_POSITION, CHAR_TARGET_POSITION, CHAR_POSITION_STATE)
|
||||||
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@ -20,29 +19,20 @@ class WindowCovering(HomeAccessory):
|
|||||||
The cover entity must support: set_cover_position.
|
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."""
|
"""Initialize a WindowCovering accessory object."""
|
||||||
super().__init__(display_name, entity_id,
|
super().__init__(*args, category=CATEGORY_WINDOW_COVERING)
|
||||||
CATEGORY_WINDOW_COVERING, **kwargs)
|
|
||||||
|
|
||||||
self.hass = hass
|
|
||||||
self.entity_id = entity_id
|
|
||||||
|
|
||||||
self.current_position = None
|
self.current_position = None
|
||||||
self.homekit_target = None
|
self.homekit_target = None
|
||||||
|
|
||||||
serv_cover = add_preload_service(self, SERV_WINDOW_COVERING)
|
serv_cover = add_preload_service(self, SERV_WINDOW_COVERING)
|
||||||
self.char_current_position = serv_cover. \
|
self.char_current_position = setup_char(
|
||||||
get_characteristic(CHAR_CURRENT_POSITION)
|
CHAR_CURRENT_POSITION, serv_cover, value=0)
|
||||||
self.char_target_position = serv_cover. \
|
self.char_target_position = setup_char(
|
||||||
get_characteristic(CHAR_TARGET_POSITION)
|
CHAR_TARGET_POSITION, serv_cover, value=0,
|
||||||
self.char_position_state = serv_cover. \
|
callback=self.move_cover)
|
||||||
get_characteristic(CHAR_POSITION_STATE)
|
self.char_position_state = setup_char(
|
||||||
self.char_current_position.value = 0
|
CHAR_POSITION_STATE, serv_cover, value=0)
|
||||||
self.char_target_position.value = 0
|
|
||||||
self.char_position_state.value = 0
|
|
||||||
|
|
||||||
self.char_target_position.setter_callback = self.move_cover
|
|
||||||
|
|
||||||
def move_cover(self, value):
|
def move_cover(self, value):
|
||||||
"""Move cover to value if call came from HomeKit."""
|
"""Move cover to value if call came from HomeKit."""
|
||||||
@ -56,11 +46,8 @@ class WindowCovering(HomeAccessory):
|
|||||||
self.hass.components.cover.set_cover_position(
|
self.hass.components.cover.set_cover_position(
|
||||||
value, self.entity_id)
|
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."""
|
"""Update cover position after state changed."""
|
||||||
if new_state is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
current_position = new_state.attributes.get(ATTR_CURRENT_POSITION)
|
current_position = new_state.attributes.get(ATTR_CURRENT_POSITION)
|
||||||
if isinstance(current_position, int):
|
if isinstance(current_position, int):
|
||||||
self.current_position = current_position
|
self.current_position = current_position
|
||||||
|
@ -7,7 +7,8 @@ from homeassistant.components.light import (
|
|||||||
from homeassistant.const import ATTR_SUPPORTED_FEATURES, STATE_ON, STATE_OFF
|
from homeassistant.const import ATTR_SUPPORTED_FEATURES, STATE_ON, STATE_OFF
|
||||||
|
|
||||||
from . import TYPES
|
from . import TYPES
|
||||||
from .accessories import HomeAccessory, add_preload_service, debounce
|
from .accessories import (
|
||||||
|
HomeAccessory, add_preload_service, debounce, setup_char)
|
||||||
from .const import (
|
from .const import (
|
||||||
CATEGORY_LIGHT, SERV_LIGHTBULB, CHAR_COLOR_TEMPERATURE,
|
CATEGORY_LIGHT, SERV_LIGHTBULB, CHAR_COLOR_TEMPERATURE,
|
||||||
CHAR_BRIGHTNESS, CHAR_HUE, CHAR_ON, CHAR_SATURATION)
|
CHAR_BRIGHTNESS, CHAR_HUE, CHAR_ON, CHAR_SATURATION)
|
||||||
@ -24,12 +25,9 @@ class Light(HomeAccessory):
|
|||||||
Currently supports: state, brightness, color temperature, rgb_color.
|
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."""
|
"""Initialize a new Light accessory object."""
|
||||||
super().__init__(name, entity_id, CATEGORY_LIGHT, **kwargs)
|
super().__init__(*args, category=CATEGORY_LIGHT)
|
||||||
|
|
||||||
self.hass = hass
|
|
||||||
self.entity_id = entity_id
|
|
||||||
self._flag = {CHAR_ON: False, CHAR_BRIGHTNESS: False,
|
self._flag = {CHAR_ON: False, CHAR_BRIGHTNESS: False,
|
||||||
CHAR_HUE: False, CHAR_SATURATION: False,
|
CHAR_HUE: False, CHAR_SATURATION: False,
|
||||||
CHAR_COLOR_TEMPERATURE: False, RGB_COLOR: False}
|
CHAR_COLOR_TEMPERATURE: False, RGB_COLOR: False}
|
||||||
@ -49,36 +47,29 @@ class Light(HomeAccessory):
|
|||||||
self._saturation = None
|
self._saturation = None
|
||||||
|
|
||||||
serv_light = add_preload_service(self, SERV_LIGHTBULB, self.chars)
|
serv_light = add_preload_service(self, SERV_LIGHTBULB, self.chars)
|
||||||
self.char_on = serv_light.get_characteristic(CHAR_ON)
|
self.char_on = setup_char(
|
||||||
self.char_on.setter_callback = self.set_state
|
CHAR_ON, serv_light, value=self._state, callback=self.set_state)
|
||||||
self.char_on.value = self._state
|
|
||||||
|
|
||||||
if CHAR_BRIGHTNESS in self.chars:
|
if CHAR_BRIGHTNESS in self.chars:
|
||||||
self.char_brightness = serv_light \
|
self.char_brightness = setup_char(
|
||||||
.get_characteristic(CHAR_BRIGHTNESS)
|
CHAR_BRIGHTNESS, serv_light, value=0,
|
||||||
self.char_brightness.setter_callback = self.set_brightness
|
callback=self.set_brightness)
|
||||||
self.char_brightness.value = 0
|
|
||||||
if CHAR_COLOR_TEMPERATURE in self.chars:
|
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) \
|
min_mireds = self.hass.states.get(self.entity_id) \
|
||||||
.attributes.get(ATTR_MIN_MIREDS, 153)
|
.attributes.get(ATTR_MIN_MIREDS, 153)
|
||||||
max_mireds = self.hass.states.get(self.entity_id) \
|
max_mireds = self.hass.states.get(self.entity_id) \
|
||||||
.attributes.get(ATTR_MAX_MIREDS, 500)
|
.attributes.get(ATTR_MAX_MIREDS, 500)
|
||||||
self.char_color_temperature.override_properties({
|
self.char_color_temperature = setup_char(
|
||||||
'minValue': min_mireds, 'maxValue': max_mireds})
|
CHAR_COLOR_TEMPERATURE, serv_light, value=min_mireds,
|
||||||
self.char_color_temperature.value = min_mireds
|
properties={'minValue': min_mireds, 'maxValue': max_mireds},
|
||||||
|
callback=self.set_color_temperature)
|
||||||
if CHAR_HUE in self.chars:
|
if CHAR_HUE in self.chars:
|
||||||
self.char_hue = serv_light.get_characteristic(CHAR_HUE)
|
self.char_hue = setup_char(
|
||||||
self.char_hue.setter_callback = self.set_hue
|
CHAR_HUE, serv_light, value=0, callback=self.set_hue)
|
||||||
self.char_hue.value = 0
|
|
||||||
if CHAR_SATURATION in self.chars:
|
if CHAR_SATURATION in self.chars:
|
||||||
self.char_saturation = serv_light \
|
self.char_saturation = setup_char(
|
||||||
.get_characteristic(CHAR_SATURATION)
|
CHAR_SATURATION, serv_light, value=75,
|
||||||
self.char_saturation.setter_callback = self.set_saturation
|
callback=self.set_saturation)
|
||||||
self.char_saturation.value = 75
|
|
||||||
|
|
||||||
def set_state(self, value):
|
def set_state(self, value):
|
||||||
"""Set state if call came from HomeKit."""
|
"""Set state if call came from HomeKit."""
|
||||||
@ -136,11 +127,8 @@ class Light(HomeAccessory):
|
|||||||
self.hass.components.light.turn_on(
|
self.hass.components.light.turn_on(
|
||||||
self.entity_id, hs_color=color)
|
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."""
|
"""Update light after state change."""
|
||||||
if not new_state:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Handle State
|
# Handle State
|
||||||
state = new_state.state
|
state = new_state.state
|
||||||
if state in (STATE_ON, STATE_OFF):
|
if state in (STATE_ON, STATE_OFF):
|
||||||
@ -162,7 +150,8 @@ class Light(HomeAccessory):
|
|||||||
if CHAR_COLOR_TEMPERATURE in self.chars:
|
if CHAR_COLOR_TEMPERATURE in self.chars:
|
||||||
color_temperature = new_state.attributes.get(ATTR_COLOR_TEMP)
|
color_temperature = new_state.attributes.get(ATTR_COLOR_TEMP)
|
||||||
if not self._flag[CHAR_COLOR_TEMPERATURE] \
|
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.char_color_temperature.set_value(color_temperature)
|
||||||
self._flag[CHAR_COLOR_TEMPERATURE] = False
|
self._flag[CHAR_COLOR_TEMPERATURE] = False
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ from homeassistant.components.lock import (
|
|||||||
ATTR_ENTITY_ID, STATE_LOCKED, STATE_UNLOCKED, STATE_UNKNOWN)
|
ATTR_ENTITY_ID, STATE_LOCKED, STATE_UNLOCKED, STATE_UNKNOWN)
|
||||||
|
|
||||||
from . import TYPES
|
from . import TYPES
|
||||||
from .accessories import HomeAccessory, add_preload_service
|
from .accessories import HomeAccessory, add_preload_service, setup_char
|
||||||
from .const import (
|
from .const import (
|
||||||
CATEGORY_LOCK, SERV_LOCK, CHAR_LOCK_CURRENT_STATE, CHAR_LOCK_TARGET_STATE)
|
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.
|
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."""
|
"""Initialize a Lock accessory object."""
|
||||||
super().__init__(name, entity_id, CATEGORY_LOCK, **kwargs)
|
super().__init__(*args, category=CATEGORY_LOCK)
|
||||||
|
|
||||||
self.hass = hass
|
|
||||||
self.entity_id = entity_id
|
|
||||||
|
|
||||||
self.flag_target_state = False
|
self.flag_target_state = False
|
||||||
|
|
||||||
serv_lock_mechanism = add_preload_service(self, SERV_LOCK)
|
serv_lock_mechanism = add_preload_service(self, SERV_LOCK)
|
||||||
self.char_current_state = serv_lock_mechanism. \
|
self.char_current_state = setup_char(
|
||||||
get_characteristic(CHAR_LOCK_CURRENT_STATE)
|
CHAR_LOCK_CURRENT_STATE, serv_lock_mechanism,
|
||||||
self.char_target_state = serv_lock_mechanism. \
|
value=HASS_TO_HOMEKIT[STATE_UNKNOWN])
|
||||||
get_characteristic(CHAR_LOCK_TARGET_STATE)
|
self.char_target_state = setup_char(
|
||||||
|
CHAR_LOCK_TARGET_STATE, serv_lock_mechanism,
|
||||||
self.char_current_state.value = HASS_TO_HOMEKIT[STATE_UNKNOWN]
|
value=HASS_TO_HOMEKIT[STATE_LOCKED], callback=self.set_state)
|
||||||
self.char_target_state.value = HASS_TO_HOMEKIT[STATE_LOCKED]
|
|
||||||
|
|
||||||
self.char_target_state.setter_callback = self.set_state
|
|
||||||
|
|
||||||
def set_state(self, value):
|
def set_state(self, value):
|
||||||
"""Set lock state to value if call came from HomeKit."""
|
"""Set lock state to value if call came from HomeKit."""
|
||||||
@ -58,11 +51,8 @@ class Lock(HomeAccessory):
|
|||||||
params = {ATTR_ENTITY_ID: self.entity_id}
|
params = {ATTR_ENTITY_ID: self.entity_id}
|
||||||
self.hass.services.call('lock', service, params)
|
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."""
|
"""Update lock after state changed."""
|
||||||
if new_state is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
hass_state = new_state.state
|
hass_state = new_state.state
|
||||||
if hass_state in HASS_TO_HOMEKIT:
|
if hass_state in HASS_TO_HOMEKIT:
|
||||||
current_lock_state = HASS_TO_HOMEKIT[hass_state]
|
current_lock_state = HASS_TO_HOMEKIT[hass_state]
|
||||||
|
@ -7,7 +7,7 @@ from homeassistant.const import (
|
|||||||
ATTR_ENTITY_ID, ATTR_CODE)
|
ATTR_ENTITY_ID, ATTR_CODE)
|
||||||
|
|
||||||
from . import TYPES
|
from . import TYPES
|
||||||
from .accessories import HomeAccessory, add_preload_service
|
from .accessories import HomeAccessory, add_preload_service, setup_char
|
||||||
from .const import (
|
from .const import (
|
||||||
CATEGORY_ALARM_SYSTEM, SERV_SECURITY_SYSTEM,
|
CATEGORY_ALARM_SYSTEM, SERV_SECURITY_SYSTEM,
|
||||||
CHAR_CURRENT_SECURITY_STATE, CHAR_TARGET_SECURITY_STATE)
|
CHAR_CURRENT_SECURITY_STATE, CHAR_TARGET_SECURITY_STATE)
|
||||||
@ -27,26 +27,18 @@ STATE_TO_SERVICE = {STATE_ALARM_DISARMED: 'alarm_disarm',
|
|||||||
class SecuritySystem(HomeAccessory):
|
class SecuritySystem(HomeAccessory):
|
||||||
"""Generate an SecuritySystem accessory for an alarm control panel."""
|
"""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."""
|
"""Initialize a SecuritySystem accessory object."""
|
||||||
super().__init__(display_name, entity_id,
|
super().__init__(*args, category=CATEGORY_ALARM_SYSTEM)
|
||||||
CATEGORY_ALARM_SYSTEM, **kwargs)
|
self._alarm_code = config[ATTR_CODE]
|
||||||
|
|
||||||
self.hass = hass
|
|
||||||
self.entity_id = entity_id
|
|
||||||
self._alarm_code = alarm_code
|
|
||||||
|
|
||||||
self.flag_target_state = False
|
self.flag_target_state = False
|
||||||
|
|
||||||
serv_alarm = add_preload_service(self, SERV_SECURITY_SYSTEM)
|
serv_alarm = add_preload_service(self, SERV_SECURITY_SYSTEM)
|
||||||
self.char_current_state = serv_alarm. \
|
self.char_current_state = setup_char(
|
||||||
get_characteristic(CHAR_CURRENT_SECURITY_STATE)
|
CHAR_CURRENT_SECURITY_STATE, serv_alarm, value=3)
|
||||||
self.char_current_state.value = 3
|
self.char_target_state = setup_char(
|
||||||
self.char_target_state = serv_alarm. \
|
CHAR_TARGET_SECURITY_STATE, serv_alarm, value=3,
|
||||||
get_characteristic(CHAR_TARGET_SECURITY_STATE)
|
callback=self.set_security_state)
|
||||||
self.char_target_state.value = 3
|
|
||||||
|
|
||||||
self.char_target_state.setter_callback = self.set_security_state
|
|
||||||
|
|
||||||
def set_security_state(self, value):
|
def set_security_state(self, value):
|
||||||
"""Move security state to value if call came from HomeKit."""
|
"""Move security state to value if call came from HomeKit."""
|
||||||
@ -61,11 +53,8 @@ class SecuritySystem(HomeAccessory):
|
|||||||
params[ATTR_CODE] = self._alarm_code
|
params[ATTR_CODE] = self._alarm_code
|
||||||
self.hass.services.call('alarm_control_panel', service, params)
|
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."""
|
"""Update security state after state changed."""
|
||||||
if new_state is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
hass_state = new_state.state
|
hass_state = new_state.state
|
||||||
if hass_state in HASS_TO_HOMEKIT:
|
if hass_state in HASS_TO_HOMEKIT:
|
||||||
current_security_state = HASS_TO_HOMEKIT[hass_state]
|
current_security_state = HASS_TO_HOMEKIT[hass_state]
|
||||||
|
@ -6,7 +6,7 @@ from homeassistant.const import (
|
|||||||
ATTR_DEVICE_CLASS, STATE_ON, STATE_HOME)
|
ATTR_DEVICE_CLASS, STATE_ON, STATE_HOME)
|
||||||
|
|
||||||
from . import TYPES
|
from . import TYPES
|
||||||
from .accessories import HomeAccessory, add_preload_service
|
from .accessories import HomeAccessory, add_preload_service, setup_char
|
||||||
from .const import (
|
from .const import (
|
||||||
CATEGORY_SENSOR, SERV_HUMIDITY_SENSOR, SERV_TEMPERATURE_SENSOR,
|
CATEGORY_SENSOR, SERV_HUMIDITY_SENSOR, SERV_TEMPERATURE_SENSOR,
|
||||||
CHAR_CURRENT_HUMIDITY, CHAR_CURRENT_TEMPERATURE, PROP_CELSIUS,
|
CHAR_CURRENT_HUMIDITY, CHAR_CURRENT_TEMPERATURE, PROP_CELSIUS,
|
||||||
@ -20,10 +20,8 @@ from .const import (
|
|||||||
DEVICE_CLASS_SMOKE, SERV_SMOKE_SENSOR, CHAR_SMOKE_DETECTED)
|
DEVICE_CLASS_SMOKE, SERV_SMOKE_SENSOR, CHAR_SMOKE_DETECTED)
|
||||||
from .util import convert_to_float, temperature_to_homekit
|
from .util import convert_to_float, temperature_to_homekit
|
||||||
|
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
BINARY_SENSOR_SERVICE_MAP = {
|
BINARY_SENSOR_SERVICE_MAP = {
|
||||||
DEVICE_CLASS_CO2: (SERV_CARBON_DIOXIDE_SENSOR,
|
DEVICE_CLASS_CO2: (SERV_CARBON_DIOXIDE_SENSOR,
|
||||||
CHAR_CARBON_DIOXIDE_DETECTED),
|
CHAR_CARBON_DIOXIDE_DETECTED),
|
||||||
@ -43,24 +41,17 @@ class TemperatureSensor(HomeAccessory):
|
|||||||
Sensor entity must return temperature in °C, °F.
|
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."""
|
"""Initialize a TemperatureSensor accessory object."""
|
||||||
super().__init__(name, entity_id, CATEGORY_SENSOR, **kwargs)
|
super().__init__(*args, category=CATEGORY_SENSOR)
|
||||||
|
|
||||||
self.hass = hass
|
|
||||||
self.entity_id = entity_id
|
|
||||||
|
|
||||||
serv_temp = add_preload_service(self, SERV_TEMPERATURE_SENSOR)
|
serv_temp = add_preload_service(self, SERV_TEMPERATURE_SENSOR)
|
||||||
self.char_temp = serv_temp.get_characteristic(CHAR_CURRENT_TEMPERATURE)
|
self.char_temp = setup_char(
|
||||||
self.char_temp.override_properties(properties=PROP_CELSIUS)
|
CHAR_CURRENT_TEMPERATURE, serv_temp, value=0,
|
||||||
self.char_temp.value = 0
|
properties=PROP_CELSIUS)
|
||||||
self.unit = None
|
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."""
|
"""Update temperature after state changed."""
|
||||||
if new_state is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
unit = new_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT, TEMP_CELSIUS)
|
unit = new_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT, TEMP_CELSIUS)
|
||||||
temperature = convert_to_float(new_state.state)
|
temperature = convert_to_float(new_state.state)
|
||||||
if temperature:
|
if temperature:
|
||||||
@ -74,23 +65,15 @@ class TemperatureSensor(HomeAccessory):
|
|||||||
class HumiditySensor(HomeAccessory):
|
class HumiditySensor(HomeAccessory):
|
||||||
"""Generate a HumiditySensor accessory as humidity sensor."""
|
"""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."""
|
"""Initialize a HumiditySensor accessory object."""
|
||||||
super().__init__(name, entity_id, CATEGORY_SENSOR, *args, **kwargs)
|
super().__init__(*args, category=CATEGORY_SENSOR)
|
||||||
|
|
||||||
self.hass = hass
|
|
||||||
self.entity_id = entity_id
|
|
||||||
|
|
||||||
serv_humidity = add_preload_service(self, SERV_HUMIDITY_SENSOR)
|
serv_humidity = add_preload_service(self, SERV_HUMIDITY_SENSOR)
|
||||||
self.char_humidity = serv_humidity \
|
self.char_humidity = setup_char(
|
||||||
.get_characteristic(CHAR_CURRENT_HUMIDITY)
|
CHAR_CURRENT_HUMIDITY, serv_humidity, value=0)
|
||||||
self.char_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."""
|
"""Update accessory after state change."""
|
||||||
if new_state is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
humidity = convert_to_float(new_state.state)
|
humidity = convert_to_float(new_state.state)
|
||||||
if humidity:
|
if humidity:
|
||||||
self.char_humidity.set_value(humidity)
|
self.char_humidity.set_value(humidity)
|
||||||
@ -102,28 +85,20 @@ class HumiditySensor(HomeAccessory):
|
|||||||
class BinarySensor(HomeAccessory):
|
class BinarySensor(HomeAccessory):
|
||||||
"""Generate a BinarySensor accessory as binary sensor."""
|
"""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."""
|
"""Initialize a BinarySensor accessory object."""
|
||||||
super().__init__(name, entity_id, CATEGORY_SENSOR, **kwargs)
|
super().__init__(*args, category=CATEGORY_SENSOR)
|
||||||
|
device_class = self.hass.states.get(self.entity_id).attributes \
|
||||||
self.hass = hass
|
|
||||||
self.entity_id = entity_id
|
|
||||||
|
|
||||||
device_class = hass.states.get(entity_id).attributes \
|
|
||||||
.get(ATTR_DEVICE_CLASS)
|
.get(ATTR_DEVICE_CLASS)
|
||||||
service_char = BINARY_SENSOR_SERVICE_MAP[device_class] \
|
service_char = BINARY_SENSOR_SERVICE_MAP[device_class] \
|
||||||
if device_class in BINARY_SENSOR_SERVICE_MAP \
|
if device_class in BINARY_SENSOR_SERVICE_MAP \
|
||||||
else BINARY_SENSOR_SERVICE_MAP[DEVICE_CLASS_OCCUPANCY]
|
else BINARY_SENSOR_SERVICE_MAP[DEVICE_CLASS_OCCUPANCY]
|
||||||
|
|
||||||
service = add_preload_service(self, service_char[0])
|
service = add_preload_service(self, service_char[0])
|
||||||
self.char_detected = service.get_characteristic(service_char[1])
|
self.char_detected = setup_char(service_char[1], service, value=0)
|
||||||
self.char_detected.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."""
|
"""Update accessory after state change."""
|
||||||
if new_state is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
state = new_state.state
|
state = new_state.state
|
||||||
detected = (state == STATE_ON) or (state == STATE_HOME)
|
detected = (state == STATE_ON) or (state == STATE_HOME)
|
||||||
self.char_detected.set_value(detected)
|
self.char_detected.set_value(detected)
|
||||||
|
@ -6,7 +6,7 @@ from homeassistant.const import (
|
|||||||
from homeassistant.core import split_entity_id
|
from homeassistant.core import split_entity_id
|
||||||
|
|
||||||
from . import TYPES
|
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
|
from .const import CATEGORY_SWITCH, SERV_SWITCH, CHAR_ON
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@ -16,20 +16,15 @@ _LOGGER = logging.getLogger(__name__)
|
|||||||
class Switch(HomeAccessory):
|
class Switch(HomeAccessory):
|
||||||
"""Generate a Switch accessory."""
|
"""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."""
|
"""Initialize a Switch accessory object to represent a remote."""
|
||||||
super().__init__(display_name, entity_id, CATEGORY_SWITCH, **kwargs)
|
super().__init__(*args, category=CATEGORY_SWITCH)
|
||||||
|
self._domain = split_entity_id(self.entity_id)[0]
|
||||||
self.hass = hass
|
|
||||||
self.entity_id = entity_id
|
|
||||||
self._domain = split_entity_id(entity_id)[0]
|
|
||||||
|
|
||||||
self.flag_target_state = False
|
self.flag_target_state = False
|
||||||
|
|
||||||
serv_switch = add_preload_service(self, SERV_SWITCH)
|
serv_switch = add_preload_service(self, SERV_SWITCH)
|
||||||
self.char_on = serv_switch.get_characteristic(CHAR_ON)
|
self.char_on = setup_char(
|
||||||
self.char_on.value = False
|
CHAR_ON, serv_switch, value=False, callback=self.set_state)
|
||||||
self.char_on.setter_callback = self.set_state
|
|
||||||
|
|
||||||
def set_state(self, value):
|
def set_state(self, value):
|
||||||
"""Move switch state to value if call came from HomeKit."""
|
"""Move switch state to value if call came from HomeKit."""
|
||||||
@ -40,15 +35,11 @@ class Switch(HomeAccessory):
|
|||||||
self.hass.services.call(self._domain, service,
|
self.hass.services.call(self._domain, service,
|
||||||
{ATTR_ENTITY_ID: self.entity_id})
|
{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."""
|
"""Update switch state after state changed."""
|
||||||
if new_state is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
current_state = (new_state.state == STATE_ON)
|
current_state = (new_state.state == STATE_ON)
|
||||||
if not self.flag_target_state:
|
if not self.flag_target_state:
|
||||||
_LOGGER.debug('%s: Set current state to %s',
|
_LOGGER.debug('%s: Set current state to %s',
|
||||||
self.entity_id, current_state)
|
self.entity_id, current_state)
|
||||||
self.char_on.set_value(current_state)
|
self.char_on.set_value(current_state)
|
||||||
|
|
||||||
self.flag_target_state = False
|
self.flag_target_state = False
|
||||||
|
@ -5,12 +5,15 @@ from homeassistant.components.climate import (
|
|||||||
ATTR_CURRENT_TEMPERATURE, ATTR_TEMPERATURE,
|
ATTR_CURRENT_TEMPERATURE, ATTR_TEMPERATURE,
|
||||||
ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW,
|
ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW,
|
||||||
ATTR_OPERATION_MODE, ATTR_OPERATION_LIST,
|
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 (
|
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 . import TYPES
|
||||||
from .accessories import HomeAccessory, add_preload_service, debounce
|
from .accessories import (
|
||||||
|
HomeAccessory, add_preload_service, debounce, setup_char)
|
||||||
from .const import (
|
from .const import (
|
||||||
CATEGORY_THERMOSTAT, SERV_THERMOSTAT, CHAR_CURRENT_HEATING_COOLING,
|
CATEGORY_THERMOSTAT, SERV_THERMOSTAT, CHAR_CURRENT_HEATING_COOLING,
|
||||||
CHAR_TARGET_HEATING_COOLING, CHAR_CURRENT_TEMPERATURE,
|
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}
|
STATE_COOL: 2, STATE_AUTO: 3}
|
||||||
HC_HOMEKIT_TO_HASS = {c: s for s, c in HC_HASS_TO_HOMEKIT.items()}
|
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')
|
@TYPES.register('Thermostat')
|
||||||
class Thermostat(HomeAccessory):
|
class Thermostat(HomeAccessory):
|
||||||
"""Generate a Thermostat accessory for a climate."""
|
"""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."""
|
"""Initialize a Thermostat accessory object."""
|
||||||
super().__init__(display_name, entity_id,
|
super().__init__(*args, category=CATEGORY_THERMOSTAT)
|
||||||
CATEGORY_THERMOSTAT, **kwargs)
|
|
||||||
|
|
||||||
self.hass = hass
|
|
||||||
self.entity_id = entity_id
|
|
||||||
self._call_timer = None
|
|
||||||
self._unit = TEMP_CELSIUS
|
self._unit = TEMP_CELSIUS
|
||||||
|
|
||||||
self.heat_cool_flag_target_state = False
|
self.heat_cool_flag_target_state = False
|
||||||
self.temperature_flag_target_state = False
|
self.temperature_flag_target_state = False
|
||||||
self.coolingthresh_flag_target_state = False
|
self.coolingthresh_flag_target_state = False
|
||||||
self.heatingthresh_flag_target_state = False
|
self.heatingthresh_flag_target_state = False
|
||||||
|
|
||||||
# Add additional characteristics if auto mode is supported
|
# Add additional characteristics if auto mode is supported
|
||||||
extra_chars = [
|
self.chars = []
|
||||||
CHAR_COOLING_THRESHOLD_TEMPERATURE,
|
features = self.hass.states.get(self.entity_id) \
|
||||||
CHAR_HEATING_THRESHOLD_TEMPERATURE] if support_auto else None
|
.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(
|
||||||
serv_thermostat = add_preload_service(self, SERV_THERMOSTAT,
|
self, SERV_THERMOSTAT, self.chars)
|
||||||
extra_chars)
|
|
||||||
|
|
||||||
# Current and target mode characteristics
|
# Current and target mode characteristics
|
||||||
self.char_current_heat_cool = serv_thermostat. \
|
self.char_current_heat_cool = setup_char(
|
||||||
get_characteristic(CHAR_CURRENT_HEATING_COOLING)
|
CHAR_CURRENT_HEATING_COOLING, serv_thermostat, value=0)
|
||||||
self.char_current_heat_cool.value = 0
|
self.char_target_heat_cool = setup_char(
|
||||||
self.char_target_heat_cool = serv_thermostat. \
|
CHAR_TARGET_HEATING_COOLING, serv_thermostat, value=0,
|
||||||
get_characteristic(CHAR_TARGET_HEATING_COOLING)
|
callback=self.set_heat_cool)
|
||||||
self.char_target_heat_cool.value = 0
|
|
||||||
self.char_target_heat_cool.setter_callback = self.set_heat_cool
|
|
||||||
|
|
||||||
# Current and target temperature characteristics
|
# Current and target temperature characteristics
|
||||||
self.char_current_temp = serv_thermostat. \
|
self.char_current_temp = setup_char(
|
||||||
get_characteristic(CHAR_CURRENT_TEMPERATURE)
|
CHAR_CURRENT_TEMPERATURE, serv_thermostat, value=21.0)
|
||||||
self.char_current_temp.value = 21.0
|
self.char_target_temp = setup_char(
|
||||||
self.char_target_temp = serv_thermostat. \
|
CHAR_TARGET_TEMPERATURE, serv_thermostat, value=21.0,
|
||||||
get_characteristic(CHAR_TARGET_TEMPERATURE)
|
callback=self.set_target_temperature)
|
||||||
self.char_target_temp.value = 21.0
|
|
||||||
self.char_target_temp.setter_callback = self.set_target_temperature
|
|
||||||
|
|
||||||
# Display units characteristic
|
# Display units characteristic
|
||||||
self.char_display_units = serv_thermostat. \
|
self.char_display_units = setup_char(
|
||||||
get_characteristic(CHAR_TEMP_DISPLAY_UNITS)
|
CHAR_TEMP_DISPLAY_UNITS, serv_thermostat, value=0)
|
||||||
self.char_display_units.value = 0
|
|
||||||
|
|
||||||
# If the device supports it: high and low temperature characteristics
|
# 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_cooling_thresh_temp = None
|
||||||
self.char_heating_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):
|
def set_heat_cool(self, value):
|
||||||
"""Move operation mode to value if call came from HomeKit."""
|
"""Move operation mode to value if call came from HomeKit."""
|
||||||
@ -141,11 +133,8 @@ class Thermostat(HomeAccessory):
|
|||||||
self.hass.components.climate.set_temperature(
|
self.hass.components.climate.set_temperature(
|
||||||
temperature=value, entity_id=self.entity_id)
|
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."""
|
"""Update security state after state changed."""
|
||||||
if new_state is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
self._unit = new_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT,
|
self._unit = new_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT,
|
||||||
TEMP_CELSIUS)
|
TEMP_CELSIUS)
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ def validate_entity_config(values):
|
|||||||
return entities
|
return entities
|
||||||
|
|
||||||
|
|
||||||
def show_setup_message(bridge, hass):
|
def show_setup_message(hass, bridge):
|
||||||
"""Display persistent notification with setup information."""
|
"""Display persistent notification with setup information."""
|
||||||
pin = bridge.pincode.decode()
|
pin = bridge.pincode.decode()
|
||||||
_LOGGER.info('Pincode: %s', pin)
|
_LOGGER.info('Pincode: %s', pin)
|
||||||
|
@ -10,9 +10,8 @@ from homeassistant.components.homekit.accessories import (
|
|||||||
add_preload_service, set_accessory_info,
|
add_preload_service, set_accessory_info,
|
||||||
debounce, HomeAccessory, HomeBridge, HomeDriver)
|
debounce, HomeAccessory, HomeBridge, HomeDriver)
|
||||||
from homeassistant.components.homekit.const import (
|
from homeassistant.components.homekit.const import (
|
||||||
ACCESSORY_MODEL, ACCESSORY_NAME, BRIDGE_MODEL, BRIDGE_NAME,
|
BRIDGE_MODEL, BRIDGE_NAME, SERV_ACCESSORY_INFO,
|
||||||
SERV_ACCESSORY_INFO, CHAR_MANUFACTURER, CHAR_MODEL,
|
CHAR_MANUFACTURER, CHAR_MODEL, CHAR_NAME, CHAR_SERIAL_NUMBER)
|
||||||
CHAR_NAME, CHAR_SERIAL_NUMBER)
|
|
||||||
from homeassistant.const import ATTR_NOW, EVENT_TIME_CHANGED
|
from homeassistant.const import ATTR_NOW, EVENT_TIME_CHANGED
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
@ -92,7 +91,7 @@ class TestAccessories(unittest.TestCase):
|
|||||||
def test_set_accessory_info(self):
|
def test_set_accessory_info(self):
|
||||||
"""Test setting the basic accessory information."""
|
"""Test setting the basic accessory information."""
|
||||||
# Test HomeAccessory
|
# Test HomeAccessory
|
||||||
acc = HomeAccessory()
|
acc = HomeAccessory('HA', 'Home Accessory', 'homekit.accessory', 2, '')
|
||||||
set_accessory_info(acc, 'name', 'model', 'manufacturer', '0000')
|
set_accessory_info(acc, 'name', 'model', 'manufacturer', '0000')
|
||||||
|
|
||||||
serv = acc.get_service(SERV_ACCESSORY_INFO)
|
serv = acc.get_service(SERV_ACCESSORY_INFO)
|
||||||
@ -104,7 +103,7 @@ class TestAccessories(unittest.TestCase):
|
|||||||
serv.get_characteristic(CHAR_SERIAL_NUMBER).value, '0000')
|
serv.get_characteristic(CHAR_SERIAL_NUMBER).value, '0000')
|
||||||
|
|
||||||
# Test HomeBridge
|
# Test HomeBridge
|
||||||
acc = HomeBridge(None)
|
acc = HomeBridge('hass')
|
||||||
set_accessory_info(acc, 'name', 'model', 'manufacturer', '0000')
|
set_accessory_info(acc, 'name', 'model', 'manufacturer', '0000')
|
||||||
|
|
||||||
serv = acc.get_service(SERV_ACCESSORY_INFO)
|
serv = acc.get_service(SERV_ACCESSORY_INFO)
|
||||||
@ -116,26 +115,37 @@ class TestAccessories(unittest.TestCase):
|
|||||||
|
|
||||||
def test_home_accessory(self):
|
def test_home_accessory(self):
|
||||||
"""Test HomeAccessory class."""
|
"""Test HomeAccessory class."""
|
||||||
acc = HomeAccessory()
|
hass = get_test_home_assistant()
|
||||||
self.assertEqual(acc.display_name, ACCESSORY_NAME)
|
|
||||||
|
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(acc.category, 1) # Category.OTHER
|
||||||
self.assertEqual(len(acc.services), 1)
|
self.assertEqual(len(acc.services), 1)
|
||||||
serv = acc.services[0] # SERV_ACCESSORY_INFO
|
serv = acc.services[0] # SERV_ACCESSORY_INFO
|
||||||
self.assertEqual(
|
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.display_name, 'test_name')
|
||||||
self.assertEqual(acc.category, 3) # Category.FAN
|
|
||||||
self.assertEqual(acc.aid, 2)
|
self.assertEqual(acc.aid, 2)
|
||||||
self.assertEqual(len(acc.services), 1)
|
self.assertEqual(len(acc.services), 1)
|
||||||
serv = acc.services[0] # SERV_ACCESSORY_INFO
|
serv = acc.services[0] # SERV_ACCESSORY_INFO
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
serv.get_characteristic(CHAR_MODEL).value, 'test_model')
|
serv.get_characteristic(CHAR_MODEL).value, 'test_model')
|
||||||
|
|
||||||
|
hass.stop()
|
||||||
|
|
||||||
def test_home_bridge(self):
|
def test_home_bridge(self):
|
||||||
"""Test HomeBridge class."""
|
"""Test HomeBridge class."""
|
||||||
bridge = HomeBridge(None)
|
bridge = HomeBridge('hass')
|
||||||
|
self.assertEqual(bridge.hass, 'hass')
|
||||||
self.assertEqual(bridge.display_name, BRIDGE_NAME)
|
self.assertEqual(bridge.display_name, BRIDGE_NAME)
|
||||||
self.assertEqual(bridge.category, 2) # Category.BRIDGE
|
self.assertEqual(bridge.category, 2) # Category.BRIDGE
|
||||||
self.assertEqual(len(bridge.services), 1)
|
self.assertEqual(len(bridge.services), 1)
|
||||||
@ -144,12 +154,10 @@ class TestAccessories(unittest.TestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
serv.get_characteristic(CHAR_MODEL).value, BRIDGE_MODEL)
|
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(bridge.display_name, 'test_name')
|
||||||
self.assertEqual(len(bridge.services), 1)
|
self.assertEqual(len(bridge.services), 1)
|
||||||
serv = bridge.services[0] # SERV_ACCESSORY_INFO
|
serv = bridge.services[0] # SERV_ACCESSORY_INFO
|
||||||
self.assertEqual(
|
|
||||||
serv.get_characteristic(CHAR_MODEL).value, 'test_model')
|
|
||||||
|
|
||||||
# setup_message
|
# setup_message
|
||||||
bridge.setup_message()
|
bridge.setup_message()
|
||||||
@ -174,11 +182,11 @@ class TestAccessories(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
mock_remove_paired_client.call_args, call('client_uuid'))
|
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):
|
def test_home_driver(self):
|
||||||
"""Test HomeDriver class."""
|
"""Test HomeDriver class."""
|
||||||
bridge = HomeBridge(None)
|
bridge = HomeBridge('hass')
|
||||||
ip_address = '127.0.0.1'
|
ip_address = '127.0.0.1'
|
||||||
port = 51826
|
port = 51826
|
||||||
path = '.homekit.state'
|
path = '.homekit.state'
|
||||||
|
@ -19,14 +19,14 @@ CONFIG = {}
|
|||||||
def test_get_accessory_invalid_aid(caplog):
|
def test_get_accessory_invalid_aid(caplog):
|
||||||
"""Test with unsupported component."""
|
"""Test with unsupported component."""
|
||||||
assert get_accessory(None, State('light.demo', 'on'),
|
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 caplog.records[0].levelname == 'WARNING'
|
||||||
assert 'invalid aid' in caplog.records[0].msg
|
assert 'invalid aid' in caplog.records[0].msg
|
||||||
|
|
||||||
|
|
||||||
def test_not_supported():
|
def test_not_supported():
|
||||||
"""Test if none is returned if entity isn't 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
|
is None
|
||||||
|
|
||||||
|
|
||||||
@ -48,7 +48,6 @@ class TestGetAccessories(unittest.TestCase):
|
|||||||
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS})
|
{ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS})
|
||||||
get_accessory(None, state, 2, {})
|
get_accessory(None, state, 2, {})
|
||||||
|
|
||||||
# pylint: disable=invalid-name
|
|
||||||
def test_sensor_temperature_fahrenheit(self):
|
def test_sensor_temperature_fahrenheit(self):
|
||||||
"""Test temperature sensor with Fahrenheit as unit."""
|
"""Test temperature sensor with Fahrenheit as unit."""
|
||||||
with patch.dict(TYPES, {'TemperatureSensor': self.mock_type}):
|
with patch.dict(TYPES, {'TemperatureSensor': self.mock_type}):
|
||||||
@ -91,8 +90,9 @@ class TestGetAccessories(unittest.TestCase):
|
|||||||
get_accessory(None, state, 2, config)
|
get_accessory(None, state, 2, config)
|
||||||
|
|
||||||
# pylint: disable=unsubscriptable-object
|
# pylint: disable=unsubscriptable-object
|
||||||
|
print(self.mock_type.call_args[1])
|
||||||
self.assertEqual(
|
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):
|
def test_climate(self):
|
||||||
"""Test climate devices."""
|
"""Test climate devices."""
|
||||||
@ -100,10 +100,6 @@ class TestGetAccessories(unittest.TestCase):
|
|||||||
state = State('climate.test', 'auto')
|
state = State('climate.test', 'auto')
|
||||||
get_accessory(None, state, 2, {})
|
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):
|
def test_light(self):
|
||||||
"""Test light devices."""
|
"""Test light devices."""
|
||||||
with patch.dict(TYPES, {'Light': self.mock_type}):
|
with patch.dict(TYPES, {'Light': self.mock_type}):
|
||||||
@ -119,10 +115,6 @@ class TestGetAccessories(unittest.TestCase):
|
|||||||
SUPPORT_TARGET_TEMPERATURE_HIGH})
|
SUPPORT_TARGET_TEMPERATURE_HIGH})
|
||||||
get_accessory(None, state, 2, {})
|
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):
|
def test_switch(self):
|
||||||
"""Test switch."""
|
"""Test switch."""
|
||||||
with patch.dict(TYPES, {'Switch': self.mock_type}):
|
with patch.dict(TYPES, {'Switch': self.mock_type}):
|
||||||
@ -140,3 +132,9 @@ class TestGetAccessories(unittest.TestCase):
|
|||||||
with patch.dict(TYPES, {'Switch': self.mock_type}):
|
with patch.dict(TYPES, {'Switch': self.mock_type}):
|
||||||
state = State('input_boolean.test', 'on')
|
state = State('input_boolean.test', 'on')
|
||||||
get_accessory(None, state, 2, {})
|
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, {})
|
||||||
|
@ -173,7 +173,7 @@ class TestHomeKit(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertEqual(mock_add_bridge_acc.mock_calls, [call(state)])
|
self.assertEqual(mock_add_bridge_acc.mock_calls, [call(state)])
|
||||||
self.assertEqual(mock_show_setup_msg.mock_calls, [
|
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.assertEqual(homekit.driver.mock_calls, [call.start()])
|
||||||
self.assertTrue(homekit.started)
|
self.assertTrue(homekit.started)
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ class TestHomekitSensors(unittest.TestCase):
|
|||||||
"""Test if accessory and HA are updated accordingly."""
|
"""Test if accessory and HA are updated accordingly."""
|
||||||
window_cover = 'cover.window'
|
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()
|
acc.run()
|
||||||
|
|
||||||
self.assertEqual(acc.aid, 2)
|
self.assertEqual(acc.aid, 2)
|
||||||
|
@ -50,9 +50,11 @@ class TestHomekitLights(unittest.TestCase):
|
|||||||
def test_light_basic(self):
|
def test_light_basic(self):
|
||||||
"""Test light with char state."""
|
"""Test light with char state."""
|
||||||
entity_id = 'light.demo'
|
entity_id = 'light.demo'
|
||||||
|
|
||||||
self.hass.states.set(entity_id, STATE_ON,
|
self.hass.states.set(entity_id, STATE_ON,
|
||||||
{ATTR_SUPPORTED_FEATURES: 0})
|
{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.aid, 2)
|
||||||
self.assertEqual(acc.category, 5) # Lightbulb
|
self.assertEqual(acc.category, 5) # Lightbulb
|
||||||
self.assertEqual(acc.char_on.value, 0)
|
self.assertEqual(acc.char_on.value, 0)
|
||||||
@ -94,9 +96,11 @@ class TestHomekitLights(unittest.TestCase):
|
|||||||
def test_light_brightness(self):
|
def test_light_brightness(self):
|
||||||
"""Test light with brightness."""
|
"""Test light with brightness."""
|
||||||
entity_id = 'light.demo'
|
entity_id = 'light.demo'
|
||||||
|
|
||||||
self.hass.states.set(entity_id, STATE_ON, {
|
self.hass.states.set(entity_id, STATE_ON, {
|
||||||
ATTR_SUPPORTED_FEATURES: SUPPORT_BRIGHTNESS, ATTR_BRIGHTNESS: 255})
|
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)
|
self.assertEqual(acc.char_brightness.value, 0)
|
||||||
|
|
||||||
acc.run()
|
acc.run()
|
||||||
@ -135,10 +139,12 @@ class TestHomekitLights(unittest.TestCase):
|
|||||||
def test_light_color_temperature(self):
|
def test_light_color_temperature(self):
|
||||||
"""Test light with color temperature."""
|
"""Test light with color temperature."""
|
||||||
entity_id = 'light.demo'
|
entity_id = 'light.demo'
|
||||||
|
|
||||||
self.hass.states.set(entity_id, STATE_ON, {
|
self.hass.states.set(entity_id, STATE_ON, {
|
||||||
ATTR_SUPPORTED_FEATURES: SUPPORT_COLOR_TEMP,
|
ATTR_SUPPORTED_FEATURES: SUPPORT_COLOR_TEMP,
|
||||||
ATTR_COLOR_TEMP: 190})
|
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)
|
self.assertEqual(acc.char_color_temperature.value, 153)
|
||||||
|
|
||||||
acc.run()
|
acc.run()
|
||||||
@ -157,10 +163,12 @@ class TestHomekitLights(unittest.TestCase):
|
|||||||
def test_light_rgb_color(self):
|
def test_light_rgb_color(self):
|
||||||
"""Test light with rgb_color."""
|
"""Test light with rgb_color."""
|
||||||
entity_id = 'light.demo'
|
entity_id = 'light.demo'
|
||||||
|
|
||||||
self.hass.states.set(entity_id, STATE_ON, {
|
self.hass.states.set(entity_id, STATE_ON, {
|
||||||
ATTR_SUPPORTED_FEATURES: SUPPORT_COLOR,
|
ATTR_SUPPORTED_FEATURES: SUPPORT_COLOR,
|
||||||
ATTR_HS_COLOR: (260, 90)})
|
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_hue.value, 0)
|
||||||
self.assertEqual(acc.char_saturation.value, 75)
|
self.assertEqual(acc.char_saturation.value, 75)
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ class TestHomekitSensors(unittest.TestCase):
|
|||||||
"""Test if accessory and HA are updated accordingly."""
|
"""Test if accessory and HA are updated accordingly."""
|
||||||
kitchen_lock = 'lock.kitchen_door'
|
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()
|
acc.run()
|
||||||
|
|
||||||
self.assertEqual(acc.aid, 2)
|
self.assertEqual(acc.aid, 2)
|
||||||
|
@ -35,8 +35,8 @@ class TestHomekitSecuritySystems(unittest.TestCase):
|
|||||||
"""Test if accessory and HA are updated accordingly."""
|
"""Test if accessory and HA are updated accordingly."""
|
||||||
acp = 'alarm_control_panel.test'
|
acp = 'alarm_control_panel.test'
|
||||||
|
|
||||||
acc = SecuritySystem(self.hass, acp, 'SecuritySystem',
|
acc = SecuritySystem(self.hass, 'SecuritySystem', acp,
|
||||||
alarm_code='1234', aid=2)
|
2, config={ATTR_CODE: '1234'})
|
||||||
acc.run()
|
acc.run()
|
||||||
|
|
||||||
self.assertEqual(acc.aid, 2)
|
self.assertEqual(acc.aid, 2)
|
||||||
@ -107,8 +107,8 @@ class TestHomekitSecuritySystems(unittest.TestCase):
|
|||||||
"""Test accessory if security_system doesn't require a alarm_code."""
|
"""Test accessory if security_system doesn't require a alarm_code."""
|
||||||
acp = 'alarm_control_panel.test'
|
acp = 'alarm_control_panel.test'
|
||||||
|
|
||||||
acc = SecuritySystem(self.hass, acp, 'SecuritySystem',
|
acc = SecuritySystem(self.hass, 'SecuritySystem', acp,
|
||||||
alarm_code=None, aid=2)
|
2, config={ATTR_CODE: None})
|
||||||
acc.run()
|
acc.run()
|
||||||
|
|
||||||
# Set from HomeKit
|
# Set from HomeKit
|
||||||
|
@ -26,7 +26,8 @@ class TestHomekitSensors(unittest.TestCase):
|
|||||||
"""Test if accessory is updated after state change."""
|
"""Test if accessory is updated after state change."""
|
||||||
entity_id = 'sensor.temperature'
|
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()
|
acc.run()
|
||||||
|
|
||||||
self.assertEqual(acc.aid, 2)
|
self.assertEqual(acc.aid, 2)
|
||||||
@ -54,7 +55,7 @@ class TestHomekitSensors(unittest.TestCase):
|
|||||||
"""Test if accessory is updated after state change."""
|
"""Test if accessory is updated after state change."""
|
||||||
entity_id = 'sensor.humidity'
|
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()
|
acc.run()
|
||||||
|
|
||||||
self.assertEqual(acc.aid, 2)
|
self.assertEqual(acc.aid, 2)
|
||||||
@ -78,7 +79,8 @@ class TestHomekitSensors(unittest.TestCase):
|
|||||||
{ATTR_DEVICE_CLASS: "opening"})
|
{ATTR_DEVICE_CLASS: "opening"})
|
||||||
self.hass.block_till_done()
|
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()
|
acc.run()
|
||||||
|
|
||||||
self.assertEqual(acc.aid, 2)
|
self.assertEqual(acc.aid, 2)
|
||||||
@ -118,6 +120,7 @@ class TestHomekitSensors(unittest.TestCase):
|
|||||||
{ATTR_DEVICE_CLASS: device_class})
|
{ATTR_DEVICE_CLASS: device_class})
|
||||||
self.hass.block_till_done()
|
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.get_service(service).display_name, service)
|
||||||
self.assertEqual(acc.char_detected.display_name, char)
|
self.assertEqual(acc.char_detected.display_name, char)
|
||||||
|
@ -34,7 +34,7 @@ class TestHomekitSwitches(unittest.TestCase):
|
|||||||
entity_id = 'switch.test'
|
entity_id = 'switch.test'
|
||||||
domain = split_entity_id(entity_id)[0]
|
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()
|
acc.run()
|
||||||
|
|
||||||
self.assertEqual(acc.aid, 2)
|
self.assertEqual(acc.aid, 2)
|
||||||
@ -70,7 +70,7 @@ class TestHomekitSwitches(unittest.TestCase):
|
|||||||
entity_id = 'remote.test'
|
entity_id = 'remote.test'
|
||||||
domain = split_entity_id(entity_id)[0]
|
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()
|
acc.run()
|
||||||
|
|
||||||
self.assertEqual(acc.char_on.value, False)
|
self.assertEqual(acc.char_on.value, False)
|
||||||
@ -89,7 +89,7 @@ class TestHomekitSwitches(unittest.TestCase):
|
|||||||
entity_id = 'input_boolean.test'
|
entity_id = 'input_boolean.test'
|
||||||
domain = split_entity_id(entity_id)[0]
|
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()
|
acc.run()
|
||||||
|
|
||||||
self.assertEqual(acc.char_on.value, False)
|
self.assertEqual(acc.char_on.value, False)
|
||||||
|
@ -7,8 +7,9 @@ from homeassistant.components.climate import (
|
|||||||
ATTR_TARGET_TEMP_LOW, ATTR_TARGET_TEMP_HIGH, ATTR_OPERATION_MODE,
|
ATTR_TARGET_TEMP_LOW, ATTR_TARGET_TEMP_HIGH, ATTR_OPERATION_MODE,
|
||||||
ATTR_OPERATION_LIST, STATE_COOL, STATE_HEAT, STATE_AUTO)
|
ATTR_OPERATION_LIST, STATE_COOL, STATE_HEAT, STATE_AUTO)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_SERVICE, EVENT_CALL_SERVICE, ATTR_SERVICE_DATA,
|
ATTR_SERVICE, ATTR_SERVICE_DATA, ATTR_SUPPORTED_FEATURES,
|
||||||
ATTR_UNIT_OF_MEASUREMENT, STATE_OFF, TEMP_CELSIUS, TEMP_FAHRENHEIT)
|
ATTR_UNIT_OF_MEASUREMENT, EVENT_CALL_SERVICE,
|
||||||
|
STATE_OFF, TEMP_CELSIUS, TEMP_FAHRENHEIT)
|
||||||
|
|
||||||
from tests.common import get_test_home_assistant
|
from tests.common import get_test_home_assistant
|
||||||
from tests.components.homekit.test_accessories import patch_debounce
|
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."""
|
"""Test if accessory and HA are updated accordingly."""
|
||||||
climate = 'climate.test'
|
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()
|
acc.run()
|
||||||
|
|
||||||
self.assertEqual(acc.aid, 2)
|
self.assertEqual(acc.aid, 2)
|
||||||
@ -187,7 +191,11 @@ class TestHomekitThermostats(unittest.TestCase):
|
|||||||
"""Test if accessory and HA are updated accordingly."""
|
"""Test if accessory and HA are updated accordingly."""
|
||||||
climate = 'climate.test'
|
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()
|
acc.run()
|
||||||
|
|
||||||
self.assertEqual(acc.char_cooling_thresh_temp.value, 23.0)
|
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."""
|
"""Test if accessory and HA are updated accordingly."""
|
||||||
climate = 'climate.test'
|
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()
|
acc.run()
|
||||||
|
|
||||||
self.hass.states.set(climate, STATE_AUTO,
|
self.hass.states.set(climate, STATE_AUTO,
|
||||||
|
@ -58,7 +58,7 @@ class TestUtil(unittest.TestCase):
|
|||||||
"""Test show setup message as persistence notification."""
|
"""Test show setup message as persistence notification."""
|
||||||
bridge = HomeBridge(self.hass)
|
bridge = HomeBridge(self.hass)
|
||||||
|
|
||||||
show_setup_message(bridge, self.hass)
|
show_setup_message(self.hass, bridge)
|
||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
|
|
||||||
data = self.events[0].data
|
data = self.events[0].data
|
||||||
|
Loading…
x
Reference in New Issue
Block a user