Compare commits

..

23 Commits

Author SHA1 Message Date
Paulus Schoutsen
a9b0f92afe Version bump to 0.70.0b7 2018-05-26 20:02:54 -04:00
Paulus Schoutsen
07b2728380 Bump frontend to 20180526.4 2018-05-26 20:02:36 -04:00
Paulus Schoutsen
a5b9e59cee Version bump to 0.70.0b6 2018-05-26 14:30:03 -04:00
Paulus Schoutsen
fb447cab82 Bump frontend to 20180526.3 2018-05-26 14:29:53 -04:00
Paulus Schoutsen
6b9addfeea Update release script 2018-05-26 11:54:50 -04:00
Paulus Schoutsen
6c62f7231b Version bump to 0.70.0b5 2018-05-26 11:53:57 -04:00
Paulus Schoutsen
52c21a53b3 Bump frontend to 20180526.2 2018-05-26 11:53:44 -04:00
Paulus Schoutsen
c9498d9f09 Version bump to 0.70.0b4 2018-05-26 08:35:18 -04:00
Paulus Schoutsen
2f0435ebd8 No longer use backports for ffmpeg (#14626) 2018-05-26 08:34:56 -04:00
Paulus Schoutsen
19351fc429 Use libsodium18 (#14624) 2018-05-26 08:34:55 -04:00
Paulus Schoutsen
bfc16428da Bump frontend to 20180526.1 2018-05-26 08:34:40 -04:00
Paulus Schoutsen
43d2e436b9 Version bump to 0.70.0b3 2018-05-24 14:25:15 -04:00
Paulus Schoutsen
ef35b8d428 Fix hue discovery popping up (#14614)
* Fix hue discovery popping up

* Fix result

* Fix tests
2018-05-24 14:24:58 -04:00
Tom Harris
69e86c29a6 Bump insteonplm version to fix device hanging (#14582)
* Update inteonplm to 0.9.2

* Change to force Travis CI

* Change to force Travis CI
2018-05-24 14:24:58 -04:00
Greg Laabs
a4d45c46e8 Fix ISY moisure sensors showing unknown until a leak is detected (#14496)
* Fix ISY leak sensors always showing UNKNOWN until a leak is detected

Added some logic that handles both moisture sensors and door/window sensors

* Handle edge case of leak sensor status update after ISY reboot

If a leak sensor is unknown, due to a recent reboot of the ISY, the status will get updated to dry upon the first heartbeat. This status update is the only way that a leak sensor's status changes without an accompanying Control event, so we need to watch for it.

* Fixes from overnight testing

State was checking the incorrect parameter, and wasn't calling schedule update

* Remove leftover debug log line

* Remove unnecessary pylint instruction

* Remove access of protected property

We can't cast _.status directly to a bool for some unknown reason (possibly with the VarEvents library), but casting to an int then bool does work.
2018-05-24 14:24:57 -04:00
Paulus Schoutsen
45d1d30a8b Update frontend to 20180524.0 2018-05-24 14:24:37 -04:00
Paulus Schoutsen
4671bd95c6 Version bump to 0.70.0b2 2018-05-21 11:10:53 -04:00
Marco Orovecchia
1bc916927c fix nanoleaf aurora lights min and max temperature (#14571)
* fixed nanoleaf aurora lights min and max temperature

* review changes
2018-05-21 11:10:36 -04:00
cdce8p
2f8865d6cb Homekit style cleanup (#14556)
* Style cleanup

* Sorted imports
* Harmonized service calls

* Test improvements

* Small update
2018-05-21 11:10:35 -04:00
Martin Hjelmare
cfdea8d20f Wait for future mysensors gateway ready (#14398)
* Wait for future mysensors gateway ready

* Add an asyncio future that is done when the gateway reports the
  gateway ready message, I_GATEWAY_READY.
* This will make sure that the gateway is ready before home assistant
  fires the home assistant start event. Automations can now send
  messages to the gateway when home assistant is started.
* Use async timeout to wait max 15 seconds for ready gateway.

* Address comments
2018-05-21 11:10:35 -04:00
Paulus Schoutsen
ba9bb90cf7 Update frontend to 20180521.0 2018-05-21 11:01:47 -04:00
Paulus Schoutsen
8854efd685 Version bump to 0.70.0b1 2018-05-19 10:45:18 -04:00
Paulus Schoutsen
b0e850ba5d Bump frontend to 20180519.0 2018-05-19 10:45:03 -04:00
40 changed files with 327 additions and 252 deletions

View File

@@ -347,6 +347,9 @@ class AuthManager:
async def _async_finish_login_flow(self, result):
"""Result of a credential login flow."""
if result['type'] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY:
return None
auth_provider = self._providers[result['handler']]
return await auth_provider.async_get_or_create_credentials(
result['data'])

View File

@@ -117,8 +117,10 @@ class ISYBinarySensorDevice(ISYDevice, BinarySensorDevice):
# pylint: disable=protected-access
if _is_val_unknown(self._node.status._val):
self._computed_state = None
self._status_was_unknown = True
else:
self._computed_state = bool(self._node.status._val)
self._status_was_unknown = False
@asyncio.coroutine
def async_added_to_hass(self) -> None:
@@ -156,9 +158,13 @@ class ISYBinarySensorDevice(ISYDevice, BinarySensorDevice):
# pylint: disable=protected-access
if not _is_val_unknown(self._negative_node.status._val):
# If the negative node has a value, it means the negative node is
# in use for this device. Therefore, we cannot determine the state
# of the sensor until we receive our first ON event.
self._computed_state = None
# in use for this device. Next we need to check to see if the
# negative and positive nodes disagree on the state (both ON or
# both OFF).
if self._negative_node.status._val == self._node.status._val:
# The states disagree, therefore we cannot determine the state
# of the sensor until we receive our first ON event.
self._computed_state = None
def _negative_node_control_handler(self, event: object) -> None:
"""Handle an "On" control event from the "negative" node."""
@@ -189,14 +195,21 @@ class ISYBinarySensorDevice(ISYDevice, BinarySensorDevice):
self.schedule_update_ha_state()
self._heartbeat()
# pylint: disable=unused-argument
def on_update(self, event: object) -> None:
"""Ignore primary node status updates.
"""Primary node status updates.
We listen directly to the Control events on all nodes for this
device.
We MOSTLY ignore these updates, as we listen directly to the Control
events on all nodes for this device. However, there is one edge case:
If a leak sensor is unknown, due to a recent reboot of the ISY, the
status will get updated to dry upon the first heartbeat. This status
update is the only way that a leak sensor's status changes without
an accompanying Control event, so we need to watch for it.
"""
pass
if self._status_was_unknown and self._computed_state is None:
self._computed_state = bool(int(self._node.status))
self._status_was_unknown = False
self.schedule_update_ha_state()
self._heartbeat()
@property
def value(self) -> object:

View File

@@ -25,7 +25,7 @@ from homeassistant.core import callback
from homeassistant.helpers.translation import async_get_translations
from homeassistant.loader import bind_hass
REQUIREMENTS = ['home-assistant-frontend==20180518.1']
REQUIREMENTS = ['home-assistant-frontend==20180526.4']
DOMAIN = 'frontend'
DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log']

View File

@@ -13,17 +13,18 @@ from homeassistant.components.cover import (
SUPPORT_CLOSE, SUPPORT_OPEN, SUPPORT_SET_POSITION)
from homeassistant.const import (
ATTR_DEVICE_CLASS, ATTR_SUPPORTED_FEATURES, ATTR_UNIT_OF_MEASUREMENT,
CONF_IP_ADDRESS, CONF_NAME, CONF_PORT, TEMP_CELSIUS, TEMP_FAHRENHEIT,
CONF_IP_ADDRESS, CONF_NAME, CONF_PORT,
DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_TEMPERATURE,
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP,
DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_ILLUMINANCE, DEVICE_CLASS_TEMPERATURE)
TEMP_CELSIUS, TEMP_FAHRENHEIT)
import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entityfilter import FILTER_SCHEMA
from homeassistant.util import get_local_ip
from homeassistant.util.decorator import Registry
from .const import (
CONF_AUTO_START, CONF_ENTITY_CONFIG, CONF_FILTER, DEFAULT_PORT,
DEFAULT_AUTO_START, DOMAIN, HOMEKIT_FILE, SERVICE_HOMEKIT_START,
DEVICE_CLASS_CO2, DEVICE_CLASS_PM25)
CONF_AUTO_START, CONF_ENTITY_CONFIG, CONF_FILTER, DEFAULT_AUTO_START,
DEFAULT_PORT, DEVICE_CLASS_CO2, DEVICE_CLASS_PM25, DOMAIN, HOMEKIT_FILE,
SERVICE_HOMEKIT_START)
from .util import show_setup_message, validate_entity_config
TYPES = Registry()

View File

@@ -84,20 +84,21 @@ class HomeAccessory(Accessory):
async_track_state_change(
self.hass, self.entity_id, self.update_state_callback)
@ha_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)
self.hass.async_add_job(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
raise NotImplementedError()
class HomeBridge(Bridge):

View File

@@ -1,23 +1,23 @@
"""Constants used be the HomeKit component."""
# #### MISC ####
# #### Misc ####
DEBOUNCE_TIMEOUT = 0.5
DOMAIN = 'homekit'
HOMEKIT_FILE = '.homekit.state'
HOMEKIT_NOTIFY_ID = 4663548
# #### CONFIG ####
# #### Config ####
CONF_AUTO_START = 'auto_start'
CONF_ENTITY_CONFIG = 'entity_config'
CONF_FILTER = 'filter'
# #### CONFIG DEFAULTS ####
# #### Config Defaults ####
DEFAULT_AUTO_START = True
DEFAULT_PORT = 51827
# #### HOMEKIT COMPONENT SERVICES ####
# #### HomeKit Component Services ####
SERVICE_HOMEKIT_START = 'start'
# #### STRING CONSTANTS ####
# #### String Constants ####
BRIDGE_MODEL = 'Bridge'
BRIDGE_NAME = 'Home Assistant Bridge'
BRIDGE_SERIAL_NUMBER = 'homekit.bridge'
@@ -31,10 +31,10 @@ SERV_CARBON_MONOXIDE_SENSOR = 'CarbonMonoxideSensor'
SERV_CONTACT_SENSOR = 'ContactSensor'
SERV_FANV2 = 'Fanv2'
SERV_GARAGE_DOOR_OPENER = 'GarageDoorOpener'
SERV_HUMIDITY_SENSOR = 'HumiditySensor' # CurrentRelativeHumidity
SERV_HUMIDITY_SENSOR = 'HumiditySensor'
SERV_LEAK_SENSOR = 'LeakSensor'
SERV_LIGHT_SENSOR = 'LightSensor'
SERV_LIGHTBULB = 'Lightbulb' # On | Brightness, Hue, Saturation, Name
SERV_LIGHTBULB = 'Lightbulb'
SERV_LOCK = 'LockMechanism'
SERV_MOTION_SENSOR = 'MotionSensor'
SERV_OCCUPANCY_SENSOR = 'OccupancySensor'
@@ -44,13 +44,12 @@ SERV_SWITCH = 'Switch'
SERV_TEMPERATURE_SENSOR = 'TemperatureSensor'
SERV_THERMOSTAT = 'Thermostat'
SERV_WINDOW_COVERING = 'WindowCovering'
# CurrentPosition, TargetPosition, PositionState
# #### Characteristics ####
CHAR_ACTIVE = 'Active'
CHAR_AIR_PARTICULATE_DENSITY = 'AirParticulateDensity'
CHAR_AIR_QUALITY = 'AirQuality'
CHAR_BRIGHTNESS = 'Brightness' # Int | [0, 100]
CHAR_BRIGHTNESS = 'Brightness'
CHAR_CARBON_DIOXIDE_DETECTED = 'CarbonDioxideDetected'
CHAR_CARBON_DIOXIDE_LEVEL = 'CarbonDioxideLevel'
CHAR_CARBON_DIOXIDE_PEAK_LEVEL = 'CarbonDioxidePeakLevel'
@@ -61,13 +60,13 @@ CHAR_COOLING_THRESHOLD_TEMPERATURE = 'CoolingThresholdTemperature'
CHAR_CURRENT_AMBIENT_LIGHT_LEVEL = 'CurrentAmbientLightLevel'
CHAR_CURRENT_DOOR_STATE = 'CurrentDoorState'
CHAR_CURRENT_HEATING_COOLING = 'CurrentHeatingCoolingState'
CHAR_CURRENT_POSITION = 'CurrentPosition' # Int | [0, 100]
CHAR_CURRENT_HUMIDITY = 'CurrentRelativeHumidity' # percent
CHAR_CURRENT_POSITION = 'CurrentPosition'
CHAR_CURRENT_HUMIDITY = 'CurrentRelativeHumidity'
CHAR_CURRENT_SECURITY_STATE = 'SecuritySystemCurrentState'
CHAR_CURRENT_TEMPERATURE = 'CurrentTemperature'
CHAR_FIRMWARE_REVISION = 'FirmwareRevision'
CHAR_HEATING_THRESHOLD_TEMPERATURE = 'HeatingThresholdTemperature'
CHAR_HUE = 'Hue' # arcdegress | [0, 360]
CHAR_HUE = 'Hue'
CHAR_LEAK_DETECTED = 'LeakDetected'
CHAR_LOCK_CURRENT_STATE = 'LockCurrentState'
CHAR_LOCK_TARGET_STATE = 'LockTargetState'
@@ -77,16 +76,16 @@ CHAR_MODEL = 'Model'
CHAR_MOTION_DETECTED = 'MotionDetected'
CHAR_NAME = 'Name'
CHAR_OCCUPANCY_DETECTED = 'OccupancyDetected'
CHAR_ON = 'On' # boolean
CHAR_ON = 'On'
CHAR_POSITION_STATE = 'PositionState'
CHAR_ROTATION_DIRECTION = 'RotationDirection'
CHAR_SATURATION = 'Saturation' # percent
CHAR_SATURATION = 'Saturation'
CHAR_SERIAL_NUMBER = 'SerialNumber'
CHAR_SMOKE_DETECTED = 'SmokeDetected'
CHAR_SWING_MODE = 'SwingMode'
CHAR_TARGET_DOOR_STATE = 'TargetDoorState'
CHAR_TARGET_HEATING_COOLING = 'TargetHeatingCoolingState'
CHAR_TARGET_POSITION = 'TargetPosition' # Int | [0, 100]
CHAR_TARGET_POSITION = 'TargetPosition'
CHAR_TARGET_SECURITY_STATE = 'SecuritySystemTargetState'
CHAR_TARGET_TEMPERATURE = 'TargetTemperature'
CHAR_TEMP_DISPLAY_UNITS = 'TemperatureDisplayUnits'
@@ -94,21 +93,17 @@ CHAR_TEMP_DISPLAY_UNITS = 'TemperatureDisplayUnits'
# #### Properties ####
PROP_MAX_VALUE = 'maxValue'
PROP_MIN_VALUE = 'minValue'
PROP_CELSIUS = {'minValue': -273, 'maxValue': 999}
# #### Device Class ####
# #### Device Classes ####
DEVICE_CLASS_CO2 = 'co2'
DEVICE_CLASS_DOOR = 'door'
DEVICE_CLASS_GARAGE_DOOR = 'garage_door'
DEVICE_CLASS_GAS = 'gas'
DEVICE_CLASS_HUMIDITY = 'humidity'
DEVICE_CLASS_LIGHT = 'light'
DEVICE_CLASS_MOISTURE = 'moisture'
DEVICE_CLASS_MOTION = 'motion'
DEVICE_CLASS_OCCUPANCY = 'occupancy'
DEVICE_CLASS_OPENING = 'opening'
DEVICE_CLASS_PM25 = 'pm25'
DEVICE_CLASS_SMOKE = 'smoke'
DEVICE_CLASS_TEMPERATURE = 'temperature'
DEVICE_CLASS_WINDOW = 'window'

View File

@@ -1,21 +1,21 @@
"""Class to hold all cover accessories."""
import logging
from pyhap.const import CATEGORY_WINDOW_COVERING, CATEGORY_GARAGE_DOOR_OPENER
from pyhap.const import CATEGORY_GARAGE_DOOR_OPENER, CATEGORY_WINDOW_COVERING
from homeassistant.components.cover import (
ATTR_CURRENT_POSITION, ATTR_POSITION, DOMAIN, SUPPORT_STOP)
from homeassistant.const import (
ATTR_ENTITY_ID, SERVICE_SET_COVER_POSITION, STATE_OPEN, STATE_CLOSED,
SERVICE_OPEN_COVER, SERVICE_CLOSE_COVER, SERVICE_STOP_COVER,
ATTR_SUPPORTED_FEATURES)
ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, SERVICE_CLOSE_COVER,
SERVICE_OPEN_COVER, SERVICE_SET_COVER_POSITION, SERVICE_STOP_COVER,
STATE_CLOSED, STATE_OPEN)
from . import TYPES
from .accessories import HomeAccessory, debounce
from .accessories import debounce, HomeAccessory
from .const import (
SERV_WINDOW_COVERING, CHAR_CURRENT_POSITION,
CHAR_TARGET_POSITION, CHAR_POSITION_STATE,
SERV_GARAGE_DOOR_OPENER, CHAR_CURRENT_DOOR_STATE, CHAR_TARGET_DOOR_STATE)
CHAR_CURRENT_DOOR_STATE, CHAR_CURRENT_POSITION, CHAR_POSITION_STATE,
CHAR_TARGET_DOOR_STATE, CHAR_TARGET_POSITION,
SERV_GARAGE_DOOR_OPENER, SERV_WINDOW_COVERING)
_LOGGER = logging.getLogger(__name__)
@@ -44,12 +44,13 @@ class GarageDoorOpener(HomeAccessory):
_LOGGER.debug('%s: Set state to %d', self.entity_id, value)
self.flag_target_state = True
params = {ATTR_ENTITY_ID: self.entity_id}
if value == 0:
self.char_current_state.set_value(3)
self.hass.components.cover.open_cover(self.entity_id)
self.hass.services.call(DOMAIN, SERVICE_OPEN_COVER, params)
elif value == 1:
self.char_current_state.set_value(2)
self.hass.components.cover.close_cover(self.entity_id)
self.hass.services.call(DOMAIN, SERVICE_CLOSE_COVER, params)
def update_state(self, new_state):
"""Update cover state after state changed."""
@@ -141,8 +142,8 @@ class WindowCoveringBasic(HomeAccessory):
else:
service, position = (SERVICE_CLOSE_COVER, 0)
self.hass.services.call(DOMAIN, service,
{ATTR_ENTITY_ID: self.entity_id})
params = {ATTR_ENTITY_ID: self.entity_id}
self.hass.services.call(DOMAIN, service, params)
# Snap the current/target position to the expected final position.
self.char_current_position.set_value(position)

View File

@@ -4,12 +4,12 @@ import logging
from pyhap.const import CATEGORY_FAN
from homeassistant.components.fan import (
ATTR_DIRECTION, ATTR_OSCILLATING,
DIRECTION_FORWARD, DIRECTION_REVERSE, DOMAIN, SERVICE_OSCILLATE,
SERVICE_SET_DIRECTION, SUPPORT_DIRECTION, SUPPORT_OSCILLATE)
ATTR_DIRECTION, ATTR_OSCILLATING, DIRECTION_FORWARD, DIRECTION_REVERSE,
DOMAIN, SERVICE_OSCILLATE, SERVICE_SET_DIRECTION, SUPPORT_DIRECTION,
SUPPORT_OSCILLATE)
from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, STATE_OFF, STATE_ON,
SERVICE_TURN_OFF, SERVICE_TURN_ON)
ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, SERVICE_TURN_OFF,
SERVICE_TURN_ON, STATE_OFF, STATE_ON)
from . import TYPES
from .accessories import HomeAccessory
@@ -71,8 +71,7 @@ class Fan(HomeAccessory):
_LOGGER.debug('%s: Set direction to %d', self.entity_id, value)
self._flag[CHAR_ROTATION_DIRECTION] = True
direction = DIRECTION_REVERSE if value == 1 else DIRECTION_FORWARD
params = {ATTR_ENTITY_ID: self.entity_id,
ATTR_DIRECTION: direction}
params = {ATTR_ENTITY_ID: self.entity_id, ATTR_DIRECTION: direction}
self.hass.services.call(DOMAIN, SERVICE_SET_DIRECTION, params)
def set_oscillating(self, value):

View File

@@ -4,16 +4,18 @@ import logging
from pyhap.const import CATEGORY_LIGHTBULB
from homeassistant.components.light import (
ATTR_HS_COLOR, ATTR_COLOR_TEMP, ATTR_BRIGHTNESS, ATTR_MIN_MIREDS,
ATTR_MAX_MIREDS, SUPPORT_COLOR, SUPPORT_COLOR_TEMP, SUPPORT_BRIGHTNESS)
from homeassistant.const import ATTR_SUPPORTED_FEATURES, STATE_ON, STATE_OFF
ATTR_BRIGHTNESS, ATTR_BRIGHTNESS_PCT, ATTR_COLOR_TEMP, ATTR_HS_COLOR,
ATTR_MAX_MIREDS, ATTR_MIN_MIREDS, DOMAIN,
SUPPORT_BRIGHTNESS, SUPPORT_COLOR, SUPPORT_COLOR_TEMP)
from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, SERVICE_TURN_ON,
SERVICE_TURN_OFF, STATE_OFF, STATE_ON)
from . import TYPES
from .accessories import HomeAccessory, debounce
from .accessories import debounce, HomeAccessory
from .const import (
SERV_LIGHTBULB, CHAR_COLOR_TEMPERATURE,
CHAR_BRIGHTNESS, CHAR_HUE, CHAR_ON, CHAR_SATURATION,
PROP_MAX_VALUE, PROP_MIN_VALUE)
CHAR_BRIGHTNESS, CHAR_COLOR_TEMPERATURE, CHAR_HUE, CHAR_ON,
CHAR_SATURATION, SERV_LIGHTBULB, PROP_MAX_VALUE, PROP_MIN_VALUE)
_LOGGER = logging.getLogger(__name__)
@@ -79,28 +81,27 @@ class Light(HomeAccessory):
_LOGGER.debug('%s: Set state to %d', self.entity_id, value)
self._flag[CHAR_ON] = True
if value == 1:
self.hass.components.light.turn_on(self.entity_id)
elif value == 0:
self.hass.components.light.turn_off(self.entity_id)
params = {ATTR_ENTITY_ID: self.entity_id}
service = SERVICE_TURN_ON if value == 1 else SERVICE_TURN_OFF
self.hass.services.call(DOMAIN, service, params)
@debounce
def set_brightness(self, value):
"""Set brightness if call came from HomeKit."""
_LOGGER.debug('%s: Set brightness to %d', self.entity_id, value)
self._flag[CHAR_BRIGHTNESS] = True
if value != 0:
self.hass.components.light.turn_on(
self.entity_id, brightness_pct=value)
else:
self.hass.components.light.turn_off(self.entity_id)
if value == 0:
self.set_state(0) # Turn off light
return
params = {ATTR_ENTITY_ID: self.entity_id, ATTR_BRIGHTNESS_PCT: value}
self.hass.services.call(DOMAIN, SERVICE_TURN_ON, params)
def set_color_temperature(self, value):
"""Set color temperature if call came from HomeKit."""
_LOGGER.debug('%s: Set color temp to %s', self.entity_id, value)
self._flag[CHAR_COLOR_TEMPERATURE] = True
self.hass.components.light.turn_on(self.entity_id, color_temp=value)
params = {ATTR_ENTITY_ID: self.entity_id, ATTR_COLOR_TEMP: value}
self.hass.services.call(DOMAIN, SERVICE_TURN_ON, params)
def set_saturation(self, value):
"""Set saturation if call came from HomeKit."""
@@ -118,15 +119,14 @@ class Light(HomeAccessory):
def set_color(self):
"""Set color if call came from HomeKit."""
# Handle Color
if self._features & SUPPORT_COLOR and self._flag[CHAR_HUE] and \
self._flag[CHAR_SATURATION]:
color = (self._hue, self._saturation)
_LOGGER.debug('%s: Set hs_color to %s', self.entity_id, color)
self._flag.update({
CHAR_HUE: False, CHAR_SATURATION: False, RGB_COLOR: True})
self.hass.components.light.turn_on(
self.entity_id, hs_color=color)
params = {ATTR_ENTITY_ID: self.entity_id, ATTR_HS_COLOR: color}
self.hass.services.call(DOMAIN, SERVICE_TURN_ON, params)
def update_state(self, new_state):
"""Update light after state change."""

View File

@@ -4,13 +4,12 @@ import logging
from pyhap.const import CATEGORY_DOOR_LOCK
from homeassistant.components.lock import (
ATTR_ENTITY_ID, STATE_LOCKED, STATE_UNLOCKED, STATE_UNKNOWN)
ATTR_ENTITY_ID, DOMAIN, STATE_LOCKED, STATE_UNLOCKED, STATE_UNKNOWN)
from homeassistant.const import ATTR_CODE
from . import TYPES
from .accessories import HomeAccessory
from .const import (
SERV_LOCK, CHAR_LOCK_CURRENT_STATE, CHAR_LOCK_TARGET_STATE)
from .const import CHAR_LOCK_CURRENT_STATE, CHAR_LOCK_TARGET_STATE, SERV_LOCK
_LOGGER = logging.getLogger(__name__)
@@ -55,7 +54,7 @@ class Lock(HomeAccessory):
params = {ATTR_ENTITY_ID: self.entity_id}
if self._code:
params[ATTR_CODE] = self._code
self.hass.services.call('lock', service, params)
self.hass.services.call(DOMAIN, service, params)
def update_state(self, new_state):
"""Update lock after state changed."""

View File

@@ -3,16 +3,16 @@ import logging
from pyhap.const import CATEGORY_ALARM_SYSTEM
from homeassistant.components.alarm_control_panel import DOMAIN
from homeassistant.const import (
STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT, STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED, ATTR_ENTITY_ID, ATTR_CODE)
ATTR_ENTITY_ID, ATTR_CODE, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT, STATE_ALARM_TRIGGERED, STATE_ALARM_DISARMED)
from . import TYPES
from .accessories import HomeAccessory
from .const import (
SERV_SECURITY_SYSTEM, CHAR_CURRENT_SECURITY_STATE,
CHAR_TARGET_SECURITY_STATE)
CHAR_CURRENT_SECURITY_STATE, CHAR_TARGET_SECURITY_STATE,
SERV_SECURITY_SYSTEM)
_LOGGER = logging.getLogger(__name__)
@@ -56,7 +56,7 @@ class SecuritySystem(HomeAccessory):
params = {ATTR_ENTITY_ID: self.entity_id}
if self._alarm_code:
params[ATTR_CODE] = self._alarm_code
self.hass.services.call('alarm_control_panel', service, params)
self.hass.services.call(DOMAIN, service, params)
def update_state(self, new_state):
"""Update security state after state changed."""

View File

@@ -4,26 +4,26 @@ import logging
from pyhap.const import CATEGORY_SENSOR
from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT, TEMP_CELSIUS,
ATTR_DEVICE_CLASS, STATE_ON, STATE_HOME)
ATTR_DEVICE_CLASS, ATTR_UNIT_OF_MEASUREMENT, STATE_ON, STATE_HOME,
TEMP_CELSIUS)
from . import TYPES
from .accessories import HomeAccessory
from .const import (
SERV_HUMIDITY_SENSOR, SERV_TEMPERATURE_SENSOR,
CHAR_CURRENT_HUMIDITY, CHAR_CURRENT_TEMPERATURE, PROP_CELSIUS,
SERV_AIR_QUALITY_SENSOR, CHAR_AIR_QUALITY, CHAR_AIR_PARTICULATE_DENSITY,
CHAR_CARBON_DIOXIDE_LEVEL, CHAR_CARBON_DIOXIDE_PEAK_LEVEL,
SERV_LIGHT_SENSOR, CHAR_CURRENT_AMBIENT_LIGHT_LEVEL,
DEVICE_CLASS_CO2, SERV_CARBON_DIOXIDE_SENSOR, CHAR_CARBON_DIOXIDE_DETECTED,
DEVICE_CLASS_GAS, SERV_CARBON_MONOXIDE_SENSOR,
CHAR_CARBON_MONOXIDE_DETECTED,
DEVICE_CLASS_MOISTURE, SERV_LEAK_SENSOR, CHAR_LEAK_DETECTED,
DEVICE_CLASS_MOTION, SERV_MOTION_SENSOR, CHAR_MOTION_DETECTED,
DEVICE_CLASS_OCCUPANCY, SERV_OCCUPANCY_SENSOR, CHAR_OCCUPANCY_DETECTED,
DEVICE_CLASS_OPENING, SERV_CONTACT_SENSOR, CHAR_CONTACT_SENSOR_STATE,
DEVICE_CLASS_DOOR, DEVICE_CLASS_GARAGE_DOOR, DEVICE_CLASS_WINDOW,
DEVICE_CLASS_SMOKE, SERV_SMOKE_SENSOR, CHAR_SMOKE_DETECTED)
CHAR_AIR_PARTICULATE_DENSITY, CHAR_AIR_QUALITY,
CHAR_CARBON_DIOXIDE_DETECTED, CHAR_CARBON_DIOXIDE_LEVEL,
CHAR_CARBON_DIOXIDE_PEAK_LEVEL, CHAR_CARBON_MONOXIDE_DETECTED,
CHAR_CONTACT_SENSOR_STATE, CHAR_CURRENT_AMBIENT_LIGHT_LEVEL,
CHAR_CURRENT_HUMIDITY, CHAR_CURRENT_TEMPERATURE, CHAR_LEAK_DETECTED,
CHAR_MOTION_DETECTED, CHAR_OCCUPANCY_DETECTED, CHAR_SMOKE_DETECTED,
DEVICE_CLASS_CO2, DEVICE_CLASS_DOOR, DEVICE_CLASS_GARAGE_DOOR,
DEVICE_CLASS_GAS, DEVICE_CLASS_MOISTURE, DEVICE_CLASS_MOTION,
DEVICE_CLASS_OCCUPANCY, DEVICE_CLASS_OPENING, DEVICE_CLASS_SMOKE,
DEVICE_CLASS_WINDOW, PROP_CELSIUS, SERV_AIR_QUALITY_SENSOR,
SERV_CARBON_DIOXIDE_SENSOR, SERV_CARBON_MONOXIDE_SENSOR,
SERV_CONTACT_SENSOR, SERV_HUMIDITY_SENSOR, SERV_LEAK_SENSOR,
SERV_LIGHT_SENSOR, SERV_MOTION_SENSOR, SERV_OCCUPANCY_SENSOR,
SERV_SMOKE_SENSOR, SERV_TEMPERATURE_SENSOR)
from .util import (
convert_to_float, temperature_to_homekit, density_to_air_quality)
@@ -108,7 +108,7 @@ class AirQualitySensor(HomeAccessory):
def update_state(self, new_state):
"""Update accessory after state change."""
density = convert_to_float(new_state.state)
if density is not None:
if density:
self.char_density.set_value(density)
self.char_quality.set_value(density_to_air_quality(density))
_LOGGER.debug('%s: Set to %d', self.entity_id, density)
@@ -134,7 +134,7 @@ class CarbonDioxideSensor(HomeAccessory):
def update_state(self, new_state):
"""Update accessory after state change."""
co2 = convert_to_float(new_state.state)
if co2 is not None:
if co2:
self.char_co2.set_value(co2)
if co2 > self.char_peak.value:
self.char_peak.set_value(co2)
@@ -157,7 +157,7 @@ class LightSensor(HomeAccessory):
def update_state(self, new_state):
"""Update accessory after state change."""
luminance = convert_to_float(new_state.state)
if luminance is not None:
if luminance:
self.char_light.set_value(luminance)
_LOGGER.debug('%s: Set to %d', self.entity_id, luminance)

View File

@@ -33,9 +33,9 @@ class Switch(HomeAccessory):
_LOGGER.debug('%s: Set switch state to %s',
self.entity_id, value)
self.flag_target_state = True
params = {ATTR_ENTITY_ID: self.entity_id}
service = SERVICE_TURN_ON if value else SERVICE_TURN_OFF
self.hass.services.call(self._domain, service,
{ATTR_ENTITY_ID: self.entity_id})
self.hass.services.call(self._domain, service, params)
def update_state(self, new_state):
"""Update switch state after state changed."""

View File

@@ -4,22 +4,23 @@ import logging
from pyhap.const import CATEGORY_THERMOSTAT
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, SUPPORT_ON_OFF,
SUPPORT_TARGET_TEMPERATURE_HIGH, SUPPORT_TARGET_TEMPERATURE_LOW)
ATTR_CURRENT_TEMPERATURE, ATTR_OPERATION_LIST, ATTR_OPERATION_MODE,
ATTR_TEMPERATURE, ATTR_TARGET_TEMP_HIGH, ATTR_TARGET_TEMP_LOW,
DOMAIN, SERVICE_SET_TEMPERATURE, SERVICE_SET_OPERATION_MODE, STATE_AUTO,
STATE_COOL, STATE_HEAT, SUPPORT_ON_OFF, SUPPORT_TARGET_TEMPERATURE_HIGH,
SUPPORT_TARGET_TEMPERATURE_LOW)
from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, ATTR_UNIT_OF_MEASUREMENT,
STATE_OFF, TEMP_CELSIUS, TEMP_FAHRENHEIT)
SERVICE_TURN_OFF, SERVICE_TURN_ON, STATE_OFF,
TEMP_CELSIUS, TEMP_FAHRENHEIT)
from . import TYPES
from .accessories import HomeAccessory, debounce
from .accessories import debounce, HomeAccessory
from .const import (
SERV_THERMOSTAT, CHAR_CURRENT_HEATING_COOLING,
CHAR_TARGET_HEATING_COOLING, CHAR_CURRENT_TEMPERATURE,
CHAR_TARGET_TEMPERATURE, CHAR_TEMP_DISPLAY_UNITS,
CHAR_COOLING_THRESHOLD_TEMPERATURE, CHAR_HEATING_THRESHOLD_TEMPERATURE)
CHAR_COOLING_THRESHOLD_TEMPERATURE, CHAR_CURRENT_HEATING_COOLING,
CHAR_CURRENT_TEMPERATURE, CHAR_TARGET_HEATING_COOLING,
CHAR_HEATING_THRESHOLD_TEMPERATURE, CHAR_TARGET_TEMPERATURE,
CHAR_TEMP_DISPLAY_UNITS, SERV_THERMOSTAT)
from .util import temperature_to_homekit, temperature_to_states
_LOGGER = logging.getLogger(__name__)
@@ -99,12 +100,13 @@ class Thermostat(HomeAccessory):
if self.support_power_state is True:
params = {ATTR_ENTITY_ID: self.entity_id}
if hass_value == STATE_OFF:
self.hass.services.call('climate', 'turn_off', params)
self.hass.services.call(DOMAIN, SERVICE_TURN_OFF, params)
return
else:
self.hass.services.call('climate', 'turn_on', params)
self.hass.components.climate.set_operation_mode(
operation_mode=hass_value, entity_id=self.entity_id)
self.hass.services.call(DOMAIN, SERVICE_TURN_ON, params)
params = {ATTR_ENTITY_ID: self.entity_id,
ATTR_OPERATION_MODE: hass_value}
self.hass.services.call(DOMAIN, SERVICE_SET_OPERATION_MODE, params)
@debounce
def set_cooling_threshold(self, value):
@@ -113,11 +115,11 @@ class Thermostat(HomeAccessory):
self.entity_id, value)
self.coolingthresh_flag_target_state = True
low = self.char_heating_thresh_temp.value
low = temperature_to_states(low, self._unit)
value = temperature_to_states(value, self._unit)
self.hass.components.climate.set_temperature(
entity_id=self.entity_id, target_temp_high=value,
target_temp_low=low)
params = {
ATTR_ENTITY_ID: self.entity_id,
ATTR_TARGET_TEMP_HIGH: temperature_to_states(value, self._unit),
ATTR_TARGET_TEMP_LOW: temperature_to_states(low, self._unit)}
self.hass.services.call(DOMAIN, SERVICE_SET_TEMPERATURE, params)
@debounce
def set_heating_threshold(self, value):
@@ -125,13 +127,12 @@ class Thermostat(HomeAccessory):
_LOGGER.debug('%s: Set heating threshold temperature to %.2f°C',
self.entity_id, value)
self.heatingthresh_flag_target_state = True
# Home assistant always wants to set low and high at the same time
high = self.char_cooling_thresh_temp.value
high = temperature_to_states(high, self._unit)
value = temperature_to_states(value, self._unit)
self.hass.components.climate.set_temperature(
entity_id=self.entity_id, target_temp_high=high,
target_temp_low=value)
params = {
ATTR_ENTITY_ID: self.entity_id,
ATTR_TARGET_TEMP_HIGH: temperature_to_states(high, self._unit),
ATTR_TARGET_TEMP_LOW: temperature_to_states(value, self._unit)}
self.hass.services.call(DOMAIN, SERVICE_SET_TEMPERATURE, params)
@debounce
def set_target_temperature(self, value):
@@ -139,9 +140,10 @@ class Thermostat(HomeAccessory):
_LOGGER.debug('%s: Set target temperature to %.2f°C',
self.entity_id, value)
self.temperature_flag_target_state = True
value = temperature_to_states(value, self._unit)
self.hass.components.climate.set_temperature(
temperature=value, entity_id=self.entity_id)
params = {
ATTR_ENTITY_ID: self.entity_id,
ATTR_TEMPERATURE: temperature_to_states(value, self._unit)}
self.hass.services.call(DOMAIN, SERVICE_SET_TEMPERATURE, params)
def update_state(self, new_state):
"""Update security state after state changed."""

View File

@@ -17,7 +17,7 @@ import homeassistant.helpers.config_validation as cv
from homeassistant.helpers import discovery
from homeassistant.helpers.entity import Entity
REQUIREMENTS = ['insteonplm==0.9.1']
REQUIREMENTS = ['insteonplm==0.9.2']
_LOGGER = logging.getLogger(__name__)

View File

@@ -92,6 +92,16 @@ class AuroraLight(Light):
"""Return the list of supported effects."""
return self._effects_list
@property
def min_mireds(self):
"""Return the coldest color_temp that this light supports."""
return 154
@property
def max_mireds(self):
"""Return the warmest color_temp that this light supports."""
return 833
@property
def name(self):
"""Return the display name of this light."""

View File

@@ -12,13 +12,14 @@ import socket
import sys
from timeit import default_timer as timer
import async_timeout
import voluptuous as vol
from homeassistant.components.mqtt import (
valid_publish_topic, valid_subscribe_topic)
from homeassistant.const import (
ATTR_BATTERY_LEVEL, CONF_NAME, CONF_OPTIMISTIC,
EVENT_HOMEASSISTANT_STOP, STATE_OFF, STATE_ON)
ATTR_BATTERY_LEVEL, CONF_NAME, CONF_OPTIMISTIC, EVENT_HOMEASSISTANT_STOP,
STATE_OFF, STATE_ON)
from homeassistant.core import callback
from homeassistant.helpers import discovery
import homeassistant.helpers.config_validation as cv
@@ -57,9 +58,11 @@ DEFAULT_TCP_PORT = 5003
DEFAULT_VERSION = '1.4'
DOMAIN = 'mysensors'
GATEWAY_READY_TIMEOUT = 15.0
MQTT_COMPONENT = 'mqtt'
MYSENSORS_GATEWAYS = 'mysensors_gateways'
MYSENSORS_PLATFORM_DEVICES = 'mysensors_devices_{}'
MYSENSORS_GATEWAY_READY = 'mysensors_gateway_ready_{}'
PLATFORM = 'platform'
SCHEMA = 'schema'
SIGNAL_CALLBACK = 'mysensors_callback_{}_{}_{}_{}'
@@ -353,12 +356,12 @@ async def async_setup(hass, config):
tcp_port = gway.get(CONF_TCP_PORT)
in_prefix = gway.get(CONF_TOPIC_IN_PREFIX, '')
out_prefix = gway.get(CONF_TOPIC_OUT_PREFIX, '')
ready_gateway = await setup_gateway(
gateway = await setup_gateway(
device, persistence_file, baud_rate, tcp_port, in_prefix,
out_prefix)
if ready_gateway is not None:
ready_gateway.nodes_config = gway.get(CONF_NODES)
gateways[id(ready_gateway)] = ready_gateway
if gateway is not None:
gateway.nodes_config = gway.get(CONF_NODES)
gateways[id(gateway)] = gateway
if not gateways:
_LOGGER.error(
@@ -395,6 +398,35 @@ async def gw_start(hass, gateway):
await gateway.start()
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, gw_stop)
if gateway.device == 'mqtt':
# Gatways connected via mqtt doesn't send gateway ready message.
return
gateway_ready = asyncio.Future()
gateway_ready_key = MYSENSORS_GATEWAY_READY.format(id(gateway))
hass.data[gateway_ready_key] = gateway_ready
try:
with async_timeout.timeout(GATEWAY_READY_TIMEOUT, loop=hass.loop):
await gateway_ready
except asyncio.TimeoutError:
_LOGGER.warning(
"Gateway %s not ready after %s secs so continuing with setup",
gateway.device, GATEWAY_READY_TIMEOUT)
finally:
hass.data.pop(gateway_ready_key, None)
@callback
def set_gateway_ready(hass, msg):
"""Set asyncio future result if gateway is ready."""
if (msg.type != msg.gateway.const.MessageType.internal or
msg.sub_type != msg.gateway.const.Internal.I_GATEWAY_READY):
return
gateway_ready = hass.data.get(MYSENSORS_GATEWAY_READY.format(
id(msg.gateway)))
if gateway_ready is None or gateway_ready.cancelled():
return
gateway_ready.set_result(True)
def validate_child(gateway, node_id, child):
@@ -495,6 +527,8 @@ def gw_callback_factory(hass):
_LOGGER.debug(
"Node update: node %s child %s", msg.node_id, msg.child_id)
set_gateway_ready(hass, msg)
try:
child = msg.gateway.sensors[msg.node_id].children[msg.child_id]
except KeyError:

View File

@@ -347,6 +347,15 @@ class ConfigEntries:
async def _async_finish_flow(self, result):
"""Finish a config flow and add an entry."""
# If no discovery config entries in progress, remove notification.
if not any(ent['source'] in DISCOVERY_SOURCES for ent
in self.hass.config_entries.flow.async_progress()):
self.hass.components.persistent_notification.async_dismiss(
DISCOVERY_NOTIFICATION_ID)
if result['type'] != data_entry_flow.RESULT_TYPE_CREATE_ENTRY:
return None
entry = ConfigEntry(
version=result['version'],
domain=result['handler'],
@@ -370,12 +379,6 @@ class ConfigEntries:
if result['source'] not in DISCOVERY_SOURCES:
return entry
# If no discovery config entries in progress, remove notification.
if not any(ent['source'] in DISCOVERY_SOURCES for ent
in self.hass.config_entries.flow.async_progress()):
self.hass.components.persistent_notification.async_dismiss(
DISCOVERY_NOTIFICATION_ID)
return entry
async def _async_create_flow(self, handler, *, source, data):

View File

@@ -2,7 +2,7 @@
"""Constants used by Home Assistant components."""
MAJOR_VERSION = 0
MINOR_VERSION = 70
PATCH_VERSION = '0b0'
PATCH_VERSION = '0b7'
__short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION)
__version__ = '{}.{}'.format(__short_version__, PATCH_VERSION)
REQUIRED_PYTHON_VER = (3, 5, 3)

View File

@@ -110,11 +110,11 @@ class FlowManager:
# Abort and Success results both finish the flow
self._progress.pop(flow.flow_id)
if result['type'] == RESULT_TYPE_ABORT:
return result
# We pass a copy of the result because we're mutating our version
result['result'] = await self._async_finish_flow(dict(result))
entry = await self._async_finish_flow(dict(result))
if result['type'] == RESULT_TYPE_CREATE_ENTRY:
result['result'] = entry
return result

View File

@@ -389,7 +389,7 @@ hipnotify==1.0.8
holidays==0.9.5
# homeassistant.components.frontend
home-assistant-frontend==20180518.1
home-assistant-frontend==20180526.4
# homeassistant.components.homekit_controller
# homekit==0.6
@@ -449,7 +449,7 @@ influxdb==5.0.0
insteonlocal==0.53
# homeassistant.components.insteon_plm
insteonplm==0.9.1
insteonplm==0.9.2
# homeassistant.components.verisure
jsonpath==0.75

View File

@@ -81,7 +81,7 @@ hbmqtt==0.9.2
holidays==0.9.5
# homeassistant.components.frontend
home-assistant-frontend==20180518.1
home-assistant-frontend==20180526.4
# homeassistant.components.influxdb
# homeassistant.components.sensor.influxdb

View File

@@ -27,5 +27,6 @@ then
exit 1
fi
rm -rf dist
python3 setup.py sdist bdist_wheel
python3 -m twine upload dist/* --skip-existing

View File

@@ -0,0 +1,8 @@
"""Collection of fixtures and functions for the HomeKit tests."""
from unittest.mock import patch
def patch_debounce():
"""Return patch for debounce method."""
return patch('homeassistant.components.homekit.accessories.debounce',
lambda f: lambda *args, **kwargs: f(*args, **kwargs))

View File

@@ -5,22 +5,18 @@ This includes tests for all mock object types.
from datetime import datetime, timedelta
from unittest.mock import patch, Mock
import pytest
from homeassistant.components.homekit.accessories import (
debounce, HomeAccessory, HomeBridge, HomeDriver)
from homeassistant.components.homekit.const import (
BRIDGE_MODEL, BRIDGE_NAME, BRIDGE_SERIAL_NUMBER, SERV_ACCESSORY_INFO,
CHAR_FIRMWARE_REVISION, CHAR_MANUFACTURER, CHAR_MODEL, CHAR_NAME,
CHAR_SERIAL_NUMBER, MANUFACTURER)
BRIDGE_MODEL, BRIDGE_NAME, BRIDGE_SERIAL_NUMBER, CHAR_FIRMWARE_REVISION,
CHAR_MANUFACTURER, CHAR_MODEL, CHAR_NAME, CHAR_SERIAL_NUMBER,
MANUFACTURER, SERV_ACCESSORY_INFO)
from homeassistant.const import __version__, ATTR_NOW, EVENT_TIME_CHANGED
import homeassistant.util.dt as dt_util
def patch_debounce():
"""Return patch for debounce method."""
return patch('homeassistant.components.homekit.accessories.debounce',
lambda f: lambda *args, **kwargs: f(*args, **kwargs))
async def test_debounce(hass):
"""Test add_timeout decorator function."""
def demo_func(*args):
@@ -74,20 +70,23 @@ async def test_home_accessory(hass):
assert serv.get_characteristic(CHAR_SERIAL_NUMBER).value == \
'homekit.accessory'
hass.states.async_set('homekit.accessory', 'on')
await hass.async_block_till_done()
await hass.async_add_job(acc.run)
hass.states.async_set('homekit.accessory', 'off')
hass.states.async_set(entity_id, 'on')
await hass.async_block_till_done()
with patch('homeassistant.components.homekit.accessories.'
'HomeAccessory.update_state') as mock_update_state:
await hass.async_add_job(acc.run)
state = hass.states.get(entity_id)
mock_update_state.assert_called_with(state)
entity_id = 'test_model.demo'
hass.states.async_set(entity_id, None)
await hass.async_block_till_done()
hass.states.async_remove(entity_id)
await hass.async_block_till_done()
assert mock_update_state.call_count == 1
acc = HomeAccessory('hass', 'test_name', entity_id, 2, None)
assert acc.display_name == 'test_name'
assert acc.aid == 2
assert len(acc.services) == 1
with pytest.raises(NotImplementedError):
acc.update_state('new_state')
# Test model name from domain
acc = HomeAccessory('hass', 'test_name', 'test_model.demo', 2, None)
serv = acc.services[0] # SERV_ACCESSORY_INFO
assert serv.get_characteristic(CHAR_MODEL).value == 'Test Model'

View File

@@ -4,13 +4,13 @@ from unittest.mock import patch, Mock
import pytest
from homeassistant.core import State
from homeassistant.components.cover import SUPPORT_OPEN, SUPPORT_CLOSE
from homeassistant.components.cover import SUPPORT_CLOSE, SUPPORT_OPEN
from homeassistant.components.climate import (
SUPPORT_TARGET_TEMPERATURE_HIGH, SUPPORT_TARGET_TEMPERATURE_LOW)
from homeassistant.components.homekit import get_accessory, TYPES
from homeassistant.const import (
ATTR_CODE, ATTR_DEVICE_CLASS, ATTR_SUPPORTED_FEATURES,
ATTR_UNIT_OF_MEASUREMENT, TEMP_CELSIUS, TEMP_FAHRENHEIT, CONF_NAME)
ATTR_UNIT_OF_MEASUREMENT, CONF_NAME, TEMP_CELSIUS, TEMP_FAHRENHEIT)
def test_not_supported(caplog):
@@ -40,14 +40,12 @@ def test_customize_options(config, name):
('Fan', 'fan.test', 'on', {}, {}),
('Light', 'light.test', 'on', {}, {}),
('Lock', 'lock.test', 'locked', {}, {ATTR_CODE: '1234'}),
('SecuritySystem', 'alarm_control_panel.test', 'armed', {},
{ATTR_CODE: '1234'}),
('Thermostat', 'climate.test', 'auto', {}, {}),
('Thermostat', 'climate.test', 'auto',
{ATTR_SUPPORTED_FEATURES: SUPPORT_TARGET_TEMPERATURE_LOW |
SUPPORT_TARGET_TEMPERATURE_HIGH}, {}),
('SecuritySystem', 'alarm_control_panel.test', 'armed', {},
{ATTR_CODE: '1234'}),
])
def test_types(type_name, entity_id, state, attrs, config):
"""Test if types are associated correctly."""
@@ -83,22 +81,17 @@ def test_type_covers(type_name, entity_id, state, attrs):
('BinarySensor', 'binary_sensor.opening', 'on',
{ATTR_DEVICE_CLASS: 'opening'}),
('BinarySensor', 'device_tracker.someone', 'not_home', {}),
('AirQualitySensor', 'sensor.air_quality_pm25', '40', {}),
('AirQualitySensor', 'sensor.air_quality', '40',
{ATTR_DEVICE_CLASS: 'pm25'}),
('CarbonDioxideSensor', 'sensor.airmeter_co2', '500', {}),
('CarbonDioxideSensor', 'sensor.airmeter', '500',
{ATTR_DEVICE_CLASS: 'co2'}),
('HumiditySensor', 'sensor.humidity', '20',
{ATTR_DEVICE_CLASS: 'humidity', ATTR_UNIT_OF_MEASUREMENT: '%'}),
('LightSensor', 'sensor.light', '900', {ATTR_DEVICE_CLASS: 'illuminance'}),
('LightSensor', 'sensor.light', '900', {ATTR_UNIT_OF_MEASUREMENT: 'lm'}),
('LightSensor', 'sensor.light', '900', {ATTR_UNIT_OF_MEASUREMENT: 'lx'}),
('TemperatureSensor', 'sensor.temperature', '23',
{ATTR_DEVICE_CLASS: 'temperature'}),
('TemperatureSensor', 'sensor.temperature', '23',

View File

@@ -6,29 +6,28 @@ import pytest
from homeassistant import setup
from homeassistant.core import State
from homeassistant.components.homekit import (
HomeKit, generate_aid,
STATUS_READY, STATUS_RUNNING, STATUS_STOPPED, STATUS_WAIT)
generate_aid, HomeKit, STATUS_READY, STATUS_RUNNING,
STATUS_STOPPED, STATUS_WAIT)
from homeassistant.components.homekit.accessories import HomeBridge
from homeassistant.components.homekit.const import (
DOMAIN, HOMEKIT_FILE, CONF_AUTO_START,
DEFAULT_PORT, SERVICE_HOMEKIT_START)
CONF_AUTO_START, DEFAULT_PORT, DOMAIN, HOMEKIT_FILE, SERVICE_HOMEKIT_START)
from homeassistant.helpers.entityfilter import generate_filter
from homeassistant.const import (
CONF_IP_ADDRESS, CONF_PORT,
EVENT_HOMEASSISTANT_START, EVENT_HOMEASSISTANT_STOP)
from tests.components.homekit.test_accessories import patch_debounce
from tests.components.homekit.common import patch_debounce
IP_ADDRESS = '127.0.0.1'
PATH_HOMEKIT = 'homeassistant.components.homekit'
@pytest.fixture('module')
def debounce_patcher(request):
@pytest.fixture(scope='module')
def debounce_patcher():
"""Patch debounce method."""
patcher = patch_debounce()
patcher.start()
request.addfinalizer(patcher.stop)
yield patcher.start()
patcher.stop()
def test_generate_aid():
@@ -124,27 +123,25 @@ async def test_homekit_setup_ip_address(hass):
hass, ANY, port=DEFAULT_PORT, address='172.0.0.0', persist_file=ANY)
async def test_homekit_add_accessory(hass):
async def test_homekit_add_accessory():
"""Add accessory if config exists and get_acc returns an accessory."""
homekit = HomeKit(hass, None, None, lambda entity_id: True, {})
homekit.bridge = HomeBridge(hass)
homekit = HomeKit('hass', None, None, lambda entity_id: True, {})
homekit.bridge = mock_bridge = Mock()
with patch(PATH_HOMEKIT + '.accessories.HomeBridge.add_accessory') \
as mock_add_acc, \
patch(PATH_HOMEKIT + '.get_accessory') as mock_get_acc:
with patch(PATH_HOMEKIT + '.get_accessory') as mock_get_acc:
mock_get_acc.side_effect = [None, 'acc', None]
homekit.add_bridge_accessory(State('light.demo', 'on'))
mock_get_acc.assert_called_with(hass, ANY, 363398124, {})
assert mock_add_acc.called is False
mock_get_acc.assert_called_with('hass', ANY, 363398124, {})
assert not mock_bridge.add_accessory.called
homekit.add_bridge_accessory(State('demo.test', 'on'))
mock_get_acc.assert_called_with(hass, ANY, 294192020, {})
assert mock_add_acc.called is True
mock_get_acc.assert_called_with('hass', ANY, 294192020, {})
assert mock_bridge.add_accessory.called
homekit.add_bridge_accessory(State('demo.test_2', 'on'))
mock_get_acc.assert_called_with(hass, ANY, 429982757, {})
mock_add_acc.assert_called_with('acc')
mock_get_acc.assert_called_with('hass', ANY, 429982757, {})
mock_bridge.add_accessory.assert_called_with('acc')
async def test_homekit_entity_filter(hass):
@@ -171,8 +168,8 @@ async def test_homekit_start(hass, debounce_patcher):
"""Test HomeKit start method."""
pin = b'123-45-678'
homekit = HomeKit(hass, None, None, {}, {'cover.demo': {}})
homekit.bridge = HomeBridge(hass)
homekit.driver = Mock(state=Mock(paired=False, pincode=pin))
homekit.bridge = Mock()
homekit.driver = mock_driver = Mock(state=Mock(paired=False, pincode=pin))
hass.states.async_set('light.demo', 'on')
state = hass.states.async_all()[0]
@@ -184,13 +181,13 @@ async def test_homekit_start(hass, debounce_patcher):
mock_add_acc.assert_called_with(state)
mock_setup_msg.assert_called_with(hass, pin)
assert homekit.driver.start.called is True
assert mock_driver.start.called is True
assert homekit.status == STATUS_RUNNING
# Test start() if already started
homekit.driver.reset_mock()
mock_driver.reset_mock()
await hass.async_add_job(homekit.start)
assert homekit.driver.start.called is False
assert mock_driver.start.called is False
async def test_homekit_stop(hass):

View File

@@ -4,13 +4,13 @@ from collections import namedtuple
import pytest
from homeassistant.components.cover import (
DOMAIN, ATTR_CURRENT_POSITION, ATTR_POSITION, SUPPORT_STOP)
ATTR_CURRENT_POSITION, ATTR_POSITION, DOMAIN, SUPPORT_STOP)
from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES,
STATE_CLOSED, STATE_OPEN, STATE_UNAVAILABLE, STATE_UNKNOWN)
from tests.common import async_mock_service
from tests.components.homekit.test_accessories import patch_debounce
from tests.components.homekit.common import patch_debounce
@pytest.fixture(scope='module')

View File

@@ -4,15 +4,15 @@ from collections import namedtuple
import pytest
from homeassistant.components.fan import (
ATTR_DIRECTION, ATTR_OSCILLATING,
DIRECTION_FORWARD, DIRECTION_REVERSE, DOMAIN, SERVICE_OSCILLATE,
SERVICE_SET_DIRECTION, SUPPORT_DIRECTION, SUPPORT_OSCILLATE)
ATTR_DIRECTION, ATTR_OSCILLATING, DIRECTION_FORWARD, DIRECTION_REVERSE,
DOMAIN, SERVICE_OSCILLATE, SERVICE_SET_DIRECTION,
SUPPORT_DIRECTION, SUPPORT_OSCILLATE)
from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES,
STATE_ON, STATE_OFF, STATE_UNKNOWN, SERVICE_TURN_ON, SERVICE_TURN_OFF)
ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, STATE_ON, STATE_OFF,
STATE_UNKNOWN, SERVICE_TURN_ON, SERVICE_TURN_OFF)
from tests.common import async_mock_service
from tests.components.homekit.test_accessories import patch_debounce
from tests.components.homekit.common import patch_debounce
@pytest.fixture(scope='module')

View File

@@ -4,14 +4,14 @@ from collections import namedtuple
import pytest
from homeassistant.components.light import (
DOMAIN, ATTR_BRIGHTNESS, ATTR_BRIGHTNESS_PCT, ATTR_COLOR_TEMP,
ATTR_HS_COLOR, SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP, SUPPORT_COLOR)
ATTR_BRIGHTNESS, ATTR_BRIGHTNESS_PCT, ATTR_COLOR_TEMP, ATTR_HS_COLOR,
DOMAIN, SUPPORT_BRIGHTNESS, SUPPORT_COLOR_TEMP, SUPPORT_COLOR)
from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES,
STATE_ON, STATE_OFF, STATE_UNKNOWN)
from tests.common import async_mock_service
from tests.components.homekit.test_accessories import patch_debounce
from tests.components.homekit.common import patch_debounce
@pytest.fixture(scope='module')

View File

@@ -4,7 +4,7 @@ import pytest
from homeassistant.components.homekit.type_locks import Lock
from homeassistant.components.lock import DOMAIN
from homeassistant.const import (
ATTR_CODE, ATTR_ENTITY_ID, STATE_UNKNOWN, STATE_UNLOCKED, STATE_LOCKED)
ATTR_CODE, ATTR_ENTITY_ID, STATE_LOCKED, STATE_UNKNOWN, STATE_UNLOCKED)
from tests.common import async_mock_service

View File

@@ -2,12 +2,12 @@
import pytest
from homeassistant.components.alarm_control_panel import DOMAIN
from homeassistant.components.homekit.type_security_systems import (
SecuritySystem)
from homeassistant.components.homekit.type_security_systems import \
SecuritySystem
from homeassistant.const import (
ATTR_CODE, ATTR_ENTITY_ID, STATE_UNKNOWN, STATE_ALARM_ARMED_AWAY,
STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_NIGHT, STATE_ALARM_DISARMED,
STATE_ALARM_TRIGGERED)
ATTR_CODE, ATTR_ENTITY_ID, STATE_ALARM_ARMED_AWAY, STATE_ALARM_ARMED_HOME,
STATE_ALARM_ARMED_NIGHT, STATE_ALARM_DISARMED, STATE_ALARM_TRIGGERED,
STATE_UNKNOWN)
from tests.common import async_mock_service

View File

@@ -1,11 +1,11 @@
"""Test different accessory types: Sensors."""
from homeassistant.components.homekit.const import PROP_CELSIUS
from homeassistant.components.homekit.type_sensors import (
TemperatureSensor, HumiditySensor, AirQualitySensor, CarbonDioxideSensor,
LightSensor, BinarySensor, BINARY_SENSOR_SERVICE_MAP)
AirQualitySensor, BinarySensor, CarbonDioxideSensor, HumiditySensor,
LightSensor, TemperatureSensor, BINARY_SENSOR_SERVICE_MAP)
from homeassistant.const import (
ATTR_UNIT_OF_MEASUREMENT, ATTR_DEVICE_CLASS, STATE_UNKNOWN, STATE_ON,
STATE_OFF, STATE_HOME, STATE_NOT_HOME, TEMP_CELSIUS, TEMP_FAHRENHEIT)
ATTR_DEVICE_CLASS, ATTR_UNIT_OF_MEASUREMENT, STATE_HOME, STATE_NOT_HOME,
STATE_OFF, STATE_ON, STATE_UNKNOWN, TEMP_CELSIUS, TEMP_FAHRENHEIT)
async def test_temperature(hass):

View File

@@ -3,7 +3,7 @@ import pytest
from homeassistant.core import split_entity_id
from homeassistant.components.homekit.type_switches import Switch
from homeassistant.const import ATTR_ENTITY_ID, STATE_ON, STATE_OFF
from homeassistant.const import ATTR_ENTITY_ID, STATE_OFF, STATE_ON
from tests.common import async_mock_service

View File

@@ -4,15 +4,15 @@ from collections import namedtuple
import pytest
from homeassistant.components.climate import (
DOMAIN, ATTR_CURRENT_TEMPERATURE, ATTR_TEMPERATURE,
ATTR_TARGET_TEMP_LOW, ATTR_TARGET_TEMP_HIGH, ATTR_OPERATION_MODE,
ATTR_OPERATION_LIST, STATE_COOL, STATE_HEAT, STATE_AUTO)
ATTR_CURRENT_TEMPERATURE, ATTR_TEMPERATURE, ATTR_TARGET_TEMP_LOW,
ATTR_TARGET_TEMP_HIGH, ATTR_OPERATION_MODE, ATTR_OPERATION_LIST,
DOMAIN, STATE_AUTO, STATE_COOL, STATE_HEAT)
from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_SUPPORTED_FEATURES, ATTR_UNIT_OF_MEASUREMENT,
STATE_OFF, TEMP_CELSIUS, TEMP_FAHRENHEIT)
from tests.common import async_mock_service
from tests.components.homekit.test_accessories import patch_debounce
from tests.components.homekit.common import patch_debounce
@pytest.fixture(scope='module')

View File

@@ -4,14 +4,14 @@ import voluptuous as vol
from homeassistant.components.homekit.const import HOMEKIT_NOTIFY_ID
from homeassistant.components.homekit.util import (
show_setup_message, dismiss_setup_message, convert_to_float,
temperature_to_homekit, temperature_to_states, density_to_air_quality)
convert_to_float, density_to_air_quality, dismiss_setup_message,
show_setup_message, temperature_to_homekit, temperature_to_states)
from homeassistant.components.homekit.util import validate_entity_config \
as vec
from homeassistant.components.persistent_notification import (
DOMAIN, ATTR_MESSAGE, ATTR_NOTIFICATION_ID)
ATTR_MESSAGE, ATTR_NOTIFICATION_ID, DOMAIN)
from homeassistant.const import (
ATTR_CODE, STATE_UNKNOWN, TEMP_CELSIUS, TEMP_FAHRENHEIT, CONF_NAME)
ATTR_CODE, CONF_NAME, STATE_UNKNOWN, TEMP_CELSIUS, TEMP_FAHRENHEIT)
from tests.common import async_mock_service

View File

@@ -284,3 +284,23 @@ async def test_discovery_notification(hass):
await hass.async_block_till_done()
state = hass.states.get('persistent_notification.config_entry_discovery')
assert state is None
async def test_discovery_notification_not_created(hass):
"""Test that we not create a notification when discovery is aborted."""
loader.set_component(hass, 'test', MockModule('test'))
await async_setup_component(hass, 'persistent_notification', {})
class TestFlow(data_entry_flow.FlowHandler):
VERSION = 5
async def async_step_discovery(self, user_input=None):
return self.async_abort(reason='test')
with patch.dict(config_entries.HANDLERS, {'test': TestFlow}):
await hass.config_entries.flow.async_init(
'test', source=data_entry_flow.SOURCE_DISCOVERY)
await hass.async_block_till_done()
state = hass.states.get('persistent_notification.config_entry_discovery')
assert state is None

View File

@@ -21,7 +21,8 @@ def manager():
return handler()
async def async_add_entry(result):
entries.append(result)
if (result['type'] == data_entry_flow.RESULT_TYPE_CREATE_ENTRY):
entries.append(result)
manager = data_entry_flow.FlowManager(
None, async_create_flow, async_add_entry)

View File

@@ -8,9 +8,4 @@ PACKAGES=(
ffmpeg
)
# Add jessie-backports
echo "Adding jessie-backports"
echo "deb http://deb.debian.org/debian jessie-backports main" >> /etc/apt/sources.list
apt-get update
apt-get install -y --no-install-recommends -t jessie-backports ${PACKAGES[@]}
apt-get install -y --no-install-recommends ${PACKAGES[@]}

View File

@@ -22,7 +22,7 @@ PACKAGES=(
# homeassistant.components.device_tracker.bluetooth_tracker
bluetooth libglib2.0-dev libbluetooth-dev
# homeassistant.components.device_tracker.owntracks
libsodium13
libsodium18
# homeassistant.components.zwave
libudev-dev
# homeassistant.components.homekit_controller