From f2dfc84d52c5308a597cb98efb861e63a194a060 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 18 May 2018 19:31:16 -0400 Subject: [PATCH 01/33] Version bump to 0.70.0b0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index acc30bcd57c..73c5ee00bc6 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 70 -PATCH_VERSION = '0.dev0' +PATCH_VERSION = '0b0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From b0e850ba5d55de5d646d286057aeba0d502d1307 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 19 May 2018 10:44:54 -0400 Subject: [PATCH 02/33] Bump frontend to 20180519.0 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 8cc3c8ea473..d4700e5edd3 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -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==20180519.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log'] diff --git a/requirements_all.txt b/requirements_all.txt index 5d71464c08a..924f2297311 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -389,7 +389,7 @@ hipnotify==1.0.8 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180518.1 +home-assistant-frontend==20180519.0 # homeassistant.components.homekit_controller # homekit==0.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 4a0db70f7d7..75a50d09a3d 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -81,7 +81,7 @@ hbmqtt==0.9.2 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180518.1 +home-assistant-frontend==20180519.0 # homeassistant.components.influxdb # homeassistant.components.sensor.influxdb From 8854efd685950e22afc0030cefa5218554750434 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 19 May 2018 10:45:18 -0400 Subject: [PATCH 03/33] Version bump to 0.70.0b1 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 73c5ee00bc6..68f4443d12e 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 70 -PATCH_VERSION = '0b0' +PATCH_VERSION = '0b1' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From ba9bb90cf73d7c609510ddfd98dcfbab55170567 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 21 May 2018 11:01:35 -0400 Subject: [PATCH 04/33] Update frontend to 20180521.0 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index d4700e5edd3..04e4e0dae48 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -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==20180519.0'] +REQUIREMENTS = ['home-assistant-frontend==20180521.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log'] diff --git a/requirements_all.txt b/requirements_all.txt index 924f2297311..b86398bb3e8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -389,7 +389,7 @@ hipnotify==1.0.8 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180519.0 +home-assistant-frontend==20180521.0 # homeassistant.components.homekit_controller # homekit==0.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 75a50d09a3d..a4fe31b0639 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -81,7 +81,7 @@ hbmqtt==0.9.2 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180519.0 +home-assistant-frontend==20180521.0 # homeassistant.components.influxdb # homeassistant.components.sensor.influxdb From cfdea8d20f30b6494637ee65fa965f494b2b0022 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Sun, 20 May 2018 00:33:52 +0200 Subject: [PATCH 05/33] 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 --- homeassistant/components/mysensors.py | 46 +++++++++++++++++++++++---- 1 file changed, 40 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/mysensors.py b/homeassistant/components/mysensors.py index 6721669a026..1e7e252bd9d 100644 --- a/homeassistant/components/mysensors.py +++ b/homeassistant/components/mysensors.py @@ -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: From 2f8865d6cb64b252254874589a722cb886c405b8 Mon Sep 17 00:00:00 2001 From: cdce8p <30130371+cdce8p@users.noreply.github.com> Date: Mon, 21 May 2018 04:25:53 +0200 Subject: [PATCH 06/33] Homekit style cleanup (#14556) * Style cleanup * Sorted imports * Harmonized service calls * Test improvements * Small update --- homeassistant/components/homekit/__init__.py | 11 ++-- .../components/homekit/accessories.py | 5 +- homeassistant/components/homekit/const.py | 35 +++++------ .../components/homekit/type_covers.py | 25 ++++---- homeassistant/components/homekit/type_fans.py | 13 ++-- .../components/homekit/type_lights.py | 42 ++++++------- .../components/homekit/type_locks.py | 7 +-- .../homekit/type_security_systems.py | 12 ++-- .../components/homekit/type_sensors.py | 38 ++++++------ .../components/homekit/type_switches.py | 4 +- .../components/homekit/type_thermostats.py | 60 ++++++++++--------- tests/components/homekit/common.py | 8 +++ tests/components/homekit/test_accessories.py | 39 ++++++------ .../homekit/test_get_accessories.py | 15 ++--- tests/components/homekit/test_homekit.py | 49 +++++++-------- tests/components/homekit/test_type_covers.py | 4 +- tests/components/homekit/test_type_fans.py | 12 ++-- tests/components/homekit/test_type_lights.py | 6 +- tests/components/homekit/test_type_locks.py | 2 +- .../homekit/test_type_security_systems.py | 10 ++-- tests/components/homekit/test_type_sensors.py | 8 +-- .../components/homekit/test_type_switches.py | 2 +- .../homekit/test_type_thermostats.py | 8 +-- tests/components/homekit/test_util.py | 8 +-- 24 files changed, 209 insertions(+), 214 deletions(-) create mode 100644 tests/components/homekit/common.py diff --git a/homeassistant/components/homekit/__init__.py b/homeassistant/components/homekit/__init__.py index ce5f30d7bf2..202f9694689 100644 --- a/homeassistant/components/homekit/__init__.py +++ b/homeassistant/components/homekit/__init__.py @@ -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() diff --git a/homeassistant/components/homekit/accessories.py b/homeassistant/components/homekit/accessories.py index ff835659221..ded4526b008 100644 --- a/homeassistant/components/homekit/accessories.py +++ b/homeassistant/components/homekit/accessories.py @@ -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): diff --git a/homeassistant/components/homekit/const.py b/homeassistant/components/homekit/const.py index adde13cc030..21cad2d9cf7 100644 --- a/homeassistant/components/homekit/const.py +++ b/homeassistant/components/homekit/const.py @@ -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' diff --git a/homeassistant/components/homekit/type_covers.py b/homeassistant/components/homekit/type_covers.py index a32ba0370ec..cf0620a4e30 100644 --- a/homeassistant/components/homekit/type_covers.py +++ b/homeassistant/components/homekit/type_covers.py @@ -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) diff --git a/homeassistant/components/homekit/type_fans.py b/homeassistant/components/homekit/type_fans.py index a3ea027c07e..bf0d4da6a59 100644 --- a/homeassistant/components/homekit/type_fans.py +++ b/homeassistant/components/homekit/type_fans.py @@ -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): diff --git a/homeassistant/components/homekit/type_lights.py b/homeassistant/components/homekit/type_lights.py index dae3579a97a..da012799602 100644 --- a/homeassistant/components/homekit/type_lights.py +++ b/homeassistant/components/homekit/type_lights.py @@ -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.""" diff --git a/homeassistant/components/homekit/type_locks.py b/homeassistant/components/homekit/type_locks.py index 309f3072768..05ab6c6f822 100644 --- a/homeassistant/components/homekit/type_locks.py +++ b/homeassistant/components/homekit/type_locks.py @@ -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.""" diff --git a/homeassistant/components/homekit/type_security_systems.py b/homeassistant/components/homekit/type_security_systems.py index bd29453e10a..bbf8b3f17cb 100644 --- a/homeassistant/components/homekit/type_security_systems.py +++ b/homeassistant/components/homekit/type_security_systems.py @@ -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.""" diff --git a/homeassistant/components/homekit/type_sensors.py b/homeassistant/components/homekit/type_sensors.py index 0005c6184ee..373c1188f2d 100644 --- a/homeassistant/components/homekit/type_sensors.py +++ b/homeassistant/components/homekit/type_sensors.py @@ -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) diff --git a/homeassistant/components/homekit/type_switches.py b/homeassistant/components/homekit/type_switches.py index ff4bf1611b8..5754266587c 100644 --- a/homeassistant/components/homekit/type_switches.py +++ b/homeassistant/components/homekit/type_switches.py @@ -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.""" diff --git a/homeassistant/components/homekit/type_thermostats.py b/homeassistant/components/homekit/type_thermostats.py index ab4d7faf875..d6555d5056d 100644 --- a/homeassistant/components/homekit/type_thermostats.py +++ b/homeassistant/components/homekit/type_thermostats.py @@ -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.""" diff --git a/tests/components/homekit/common.py b/tests/components/homekit/common.py new file mode 100644 index 00000000000..915759f22d6 --- /dev/null +++ b/tests/components/homekit/common.py @@ -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)) diff --git a/tests/components/homekit/test_accessories.py b/tests/components/homekit/test_accessories.py index 1b06e245734..3d1c335f8ae 100644 --- a/tests/components/homekit/test_accessories.py +++ b/tests/components/homekit/test_accessories.py @@ -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' diff --git a/tests/components/homekit/test_get_accessories.py b/tests/components/homekit/test_get_accessories.py index 0ffc1ae4767..25a0dd3f1cb 100644 --- a/tests/components/homekit/test_get_accessories.py +++ b/tests/components/homekit/test_get_accessories.py @@ -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', diff --git a/tests/components/homekit/test_homekit.py b/tests/components/homekit/test_homekit.py index b22a7f63cda..31337088b33 100644 --- a/tests/components/homekit/test_homekit.py +++ b/tests/components/homekit/test_homekit.py @@ -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): diff --git a/tests/components/homekit/test_type_covers.py b/tests/components/homekit/test_type_covers.py index 7260ae40c1a..8138d1c506b 100644 --- a/tests/components/homekit/test_type_covers.py +++ b/tests/components/homekit/test_type_covers.py @@ -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') diff --git a/tests/components/homekit/test_type_fans.py b/tests/components/homekit/test_type_fans.py index fc504cc6cbd..f96fe19d603 100644 --- a/tests/components/homekit/test_type_fans.py +++ b/tests/components/homekit/test_type_fans.py @@ -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') diff --git a/tests/components/homekit/test_type_lights.py b/tests/components/homekit/test_type_lights.py index 65a526edcc3..7a1db7b3f71 100644 --- a/tests/components/homekit/test_type_lights.py +++ b/tests/components/homekit/test_type_lights.py @@ -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') diff --git a/tests/components/homekit/test_type_locks.py b/tests/components/homekit/test_type_locks.py index 3b8cde47fcb..f4698b1380b 100644 --- a/tests/components/homekit/test_type_locks.py +++ b/tests/components/homekit/test_type_locks.py @@ -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 diff --git a/tests/components/homekit/test_type_security_systems.py b/tests/components/homekit/test_type_security_systems.py index 577d2f2175d..7b72404cdaa 100644 --- a/tests/components/homekit/test_type_security_systems.py +++ b/tests/components/homekit/test_type_security_systems.py @@ -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 diff --git a/tests/components/homekit/test_type_sensors.py b/tests/components/homekit/test_type_sensors.py index 56742bada92..e36ae67da12 100644 --- a/tests/components/homekit/test_type_sensors.py +++ b/tests/components/homekit/test_type_sensors.py @@ -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): diff --git a/tests/components/homekit/test_type_switches.py b/tests/components/homekit/test_type_switches.py index 399a8bd84c8..5fc0b6ce1b9 100644 --- a/tests/components/homekit/test_type_switches.py +++ b/tests/components/homekit/test_type_switches.py @@ -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 diff --git a/tests/components/homekit/test_type_thermostats.py b/tests/components/homekit/test_type_thermostats.py index bc5b3219cdf..337ad23ad05 100644 --- a/tests/components/homekit/test_type_thermostats.py +++ b/tests/components/homekit/test_type_thermostats.py @@ -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') diff --git a/tests/components/homekit/test_util.py b/tests/components/homekit/test_util.py index 42f81387960..0755e8f54d4 100644 --- a/tests/components/homekit/test_util.py +++ b/tests/components/homekit/test_util.py @@ -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 From 1bc916927ca7138ac136e722a41a6ac2f65a9c25 Mon Sep 17 00:00:00 2001 From: Marco Orovecchia Date: Mon, 21 May 2018 17:02:50 +0200 Subject: [PATCH 07/33] fix nanoleaf aurora lights min and max temperature (#14571) * fixed nanoleaf aurora lights min and max temperature * review changes --- homeassistant/components/light/nanoleaf_aurora.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/homeassistant/components/light/nanoleaf_aurora.py b/homeassistant/components/light/nanoleaf_aurora.py index 99c07166037..c26766d8deb 100644 --- a/homeassistant/components/light/nanoleaf_aurora.py +++ b/homeassistant/components/light/nanoleaf_aurora.py @@ -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.""" From 4671bd95c612cc55c05ef3284f697b8fbeb76f27 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Mon, 21 May 2018 11:10:53 -0400 Subject: [PATCH 08/33] Version bump to 0.70.0b2 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 68f4443d12e..73dc0db7aac 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 70 -PATCH_VERSION = '0b1' +PATCH_VERSION = '0b2' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From 45d1d30a8b698a5c8b7495845512c1a345432216 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 24 May 2018 13:08:12 -0400 Subject: [PATCH 09/33] Update frontend to 20180524.0 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 04e4e0dae48..8ee6ce549a4 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -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==20180521.0'] +REQUIREMENTS = ['home-assistant-frontend==20180524.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log'] diff --git a/requirements_all.txt b/requirements_all.txt index b86398bb3e8..94f49fb2454 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -389,7 +389,7 @@ hipnotify==1.0.8 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180521.0 +home-assistant-frontend==20180524.0 # homeassistant.components.homekit_controller # homekit==0.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index a4fe31b0639..57224aa4233 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -81,7 +81,7 @@ hbmqtt==0.9.2 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180521.0 +home-assistant-frontend==20180524.0 # homeassistant.components.influxdb # homeassistant.components.sensor.influxdb From a4d45c46e8859268b185a311c64282fe824e5348 Mon Sep 17 00:00:00 2001 From: Greg Laabs Date: Mon, 21 May 2018 12:00:01 -0700 Subject: [PATCH 10/33] 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. --- .../components/binary_sensor/isy994.py | 29 ++++++++++++++----- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/binary_sensor/isy994.py b/homeassistant/components/binary_sensor/isy994.py index fb86244acf3..09f1739cba7 100644 --- a/homeassistant/components/binary_sensor/isy994.py +++ b/homeassistant/components/binary_sensor/isy994.py @@ -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: From 69e86c29a6ede65f7baa61846435bf18bca24682 Mon Sep 17 00:00:00 2001 From: Tom Harris Date: Mon, 21 May 2018 19:46:20 -0400 Subject: [PATCH 11/33] Bump insteonplm version to fix device hanging (#14582) * Update inteonplm to 0.9.2 * Change to force Travis CI * Change to force Travis CI --- homeassistant/components/insteon_plm/__init__.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/insteon_plm/__init__.py b/homeassistant/components/insteon_plm/__init__.py index 246e84ec71f..b86f80cbee7 100644 --- a/homeassistant/components/insteon_plm/__init__.py +++ b/homeassistant/components/insteon_plm/__init__.py @@ -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__) diff --git a/requirements_all.txt b/requirements_all.txt index 94f49fb2454..0bd40c03fae 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -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 From ef35b8d42879d8209f7e56abc660353a0df1a810 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 24 May 2018 14:24:14 -0400 Subject: [PATCH 12/33] Fix hue discovery popping up (#14614) * Fix hue discovery popping up * Fix result * Fix tests --- homeassistant/auth.py | 3 +++ homeassistant/config_entries.py | 15 +++++++++------ homeassistant/data_entry_flow.py | 8 ++++---- tests/test_config_entries.py | 20 ++++++++++++++++++++ tests/test_data_entry_flow.py | 3 ++- 5 files changed, 38 insertions(+), 11 deletions(-) diff --git a/homeassistant/auth.py b/homeassistant/auth.py index 7c01776b7b1..5e434b74ca8 100644 --- a/homeassistant/auth.py +++ b/homeassistant/auth.py @@ -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']) diff --git a/homeassistant/config_entries.py b/homeassistant/config_entries.py index 1350cd7d76a..8a73e424fb5 100644 --- a/homeassistant/config_entries.py +++ b/homeassistant/config_entries.py @@ -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): diff --git a/homeassistant/data_entry_flow.py b/homeassistant/data_entry_flow.py index e9580aba273..5095297e795 100644 --- a/homeassistant/data_entry_flow.py +++ b/homeassistant/data_entry_flow.py @@ -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 diff --git a/tests/test_config_entries.py b/tests/test_config_entries.py index 1518706db55..84bd0771542 100644 --- a/tests/test_config_entries.py +++ b/tests/test_config_entries.py @@ -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 diff --git a/tests/test_data_entry_flow.py b/tests/test_data_entry_flow.py index 6d3e41436c5..894fd4d7194 100644 --- a/tests/test_data_entry_flow.py +++ b/tests/test_data_entry_flow.py @@ -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) From 43d2e436b9750fcaf5392062b252d686a6ca30a3 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 24 May 2018 14:25:15 -0400 Subject: [PATCH 13/33] Version bump to 0.70.0b3 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 73dc0db7aac..dafe7e90db5 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 70 -PATCH_VERSION = '0b2' +PATCH_VERSION = '0b3' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From bfc16428dad23ea72c836955a43cf5f289b5b836 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 26 May 2018 08:33:22 -0400 Subject: [PATCH 14/33] Bump frontend to 20180526.1 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 8ee6ce549a4..f6b8bc9cb7a 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -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==20180524.0'] +REQUIREMENTS = ['home-assistant-frontend==20180526.1'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log'] diff --git a/requirements_all.txt b/requirements_all.txt index 0bd40c03fae..1386c490695 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -389,7 +389,7 @@ hipnotify==1.0.8 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180524.0 +home-assistant-frontend==20180526.1 # homeassistant.components.homekit_controller # homekit==0.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 57224aa4233..9e2ea04fb8c 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -81,7 +81,7 @@ hbmqtt==0.9.2 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180524.0 +home-assistant-frontend==20180526.1 # homeassistant.components.influxdb # homeassistant.components.sensor.influxdb From 19351fc429389a948297e4eb31e24c0ceb825058 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 25 May 2018 11:32:45 -0400 Subject: [PATCH 15/33] Use libsodium18 (#14624) --- virtualization/Docker/setup_docker_prereqs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virtualization/Docker/setup_docker_prereqs b/virtualization/Docker/setup_docker_prereqs index 302dfba2e1d..23f55eea13f 100755 --- a/virtualization/Docker/setup_docker_prereqs +++ b/virtualization/Docker/setup_docker_prereqs @@ -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 From 2f0435ebd81bc7b3a9a0b474b831b33720218c9d Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 25 May 2018 13:49:45 -0400 Subject: [PATCH 16/33] No longer use backports for ffmpeg (#14626) --- virtualization/Docker/scripts/ffmpeg | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/virtualization/Docker/scripts/ffmpeg b/virtualization/Docker/scripts/ffmpeg index 81b9ce694f9..914c2648e56 100755 --- a/virtualization/Docker/scripts/ffmpeg +++ b/virtualization/Docker/scripts/ffmpeg @@ -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[@]} \ No newline at end of file +apt-get install -y --no-install-recommends ${PACKAGES[@]} From c9498d9f0941575bbf15e19b602f5dda9352b55c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 26 May 2018 08:35:18 -0400 Subject: [PATCH 17/33] Version bump to 0.70.0b4 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index dafe7e90db5..86653d4c909 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 70 -PATCH_VERSION = '0b3' +PATCH_VERSION = '0b4' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From 52c21a53b37bdfa37f2466ecfd301a1ccae4511c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 26 May 2018 11:53:24 -0400 Subject: [PATCH 18/33] Bump frontend to 20180526.2 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index f6b8bc9cb7a..7d888a2b082 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -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==20180526.1'] +REQUIREMENTS = ['home-assistant-frontend==20180526.2'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log'] diff --git a/requirements_all.txt b/requirements_all.txt index 1386c490695..0dbd5f74d3d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -389,7 +389,7 @@ hipnotify==1.0.8 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180526.1 +home-assistant-frontend==20180526.2 # homeassistant.components.homekit_controller # homekit==0.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 9e2ea04fb8c..405511c6d50 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -81,7 +81,7 @@ hbmqtt==0.9.2 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180526.1 +home-assistant-frontend==20180526.2 # homeassistant.components.influxdb # homeassistant.components.sensor.influxdb From 6c62f7231b07db9f058908799955418642829fa6 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 26 May 2018 11:53:57 -0400 Subject: [PATCH 19/33] Version bump to 0.70.0b5 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 86653d4c909..f2d95bc2ac4 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 70 -PATCH_VERSION = '0b4' +PATCH_VERSION = '0b5' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From 6b9addfeeab05a8de0d2a2cb0df99b1c6e73c085 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 26 May 2018 11:54:50 -0400 Subject: [PATCH 20/33] Update release script --- script/release | 1 + 1 file changed, 1 insertion(+) diff --git a/script/release b/script/release index dc3e208bc1a..cf4f808377e 100755 --- a/script/release +++ b/script/release @@ -27,5 +27,6 @@ then exit 1 fi +rm -rf dist python3 setup.py sdist bdist_wheel python3 -m twine upload dist/* --skip-existing From fb447cab82dae8a2332f82d4f9db4fc11d7e804c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 26 May 2018 14:29:26 -0400 Subject: [PATCH 21/33] Bump frontend to 20180526.3 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 7d888a2b082..654afd67f42 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -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==20180526.2'] +REQUIREMENTS = ['home-assistant-frontend==20180526.3'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log'] diff --git a/requirements_all.txt b/requirements_all.txt index 0dbd5f74d3d..d58c58e38b2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -389,7 +389,7 @@ hipnotify==1.0.8 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180526.2 +home-assistant-frontend==20180526.3 # homeassistant.components.homekit_controller # homekit==0.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 405511c6d50..9622fe9674a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -81,7 +81,7 @@ hbmqtt==0.9.2 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180526.2 +home-assistant-frontend==20180526.3 # homeassistant.components.influxdb # homeassistant.components.sensor.influxdb From a5b9e59ceeee8cdf3d4629b44abd9485927b382b Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 26 May 2018 14:30:03 -0400 Subject: [PATCH 22/33] Version bump to 0.70.0b6 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index f2d95bc2ac4..37c583e3b7e 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 70 -PATCH_VERSION = '0b5' +PATCH_VERSION = '0b6' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From 07b27283805dea27ae9163c49db1ac4d23147e52 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 26 May 2018 20:02:16 -0400 Subject: [PATCH 23/33] Bump frontend to 20180526.4 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 654afd67f42..2bd7283e38e 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -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==20180526.3'] +REQUIREMENTS = ['home-assistant-frontend==20180526.4'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log'] diff --git a/requirements_all.txt b/requirements_all.txt index d58c58e38b2..ae16651d8e9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -389,7 +389,7 @@ hipnotify==1.0.8 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180526.3 +home-assistant-frontend==20180526.4 # homeassistant.components.homekit_controller # homekit==0.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 9622fe9674a..ce458995d2a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -81,7 +81,7 @@ hbmqtt==0.9.2 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180526.3 +home-assistant-frontend==20180526.4 # homeassistant.components.influxdb # homeassistant.components.sensor.influxdb From a9b0f92afefb6a5bef1abd865808ac0845e691ed Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 26 May 2018 20:02:54 -0400 Subject: [PATCH 24/33] Version bump to 0.70.0b7 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 37c583e3b7e..0ff3f0738a1 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 70 -PATCH_VERSION = '0b6' +PATCH_VERSION = '0b7' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From 94a82ab7dc1b504ee89bd93f75fc40503b023bf1 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 27 May 2018 17:17:19 -0400 Subject: [PATCH 25/33] Allow Hass.io panel dir (#14655) --- homeassistant/components/hassio/http.py | 2 +- tests/components/hassio/test_http.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/hassio/http.py b/homeassistant/components/hassio/http.py index 9dd6427ec38..bb4f8219a33 100644 --- a/homeassistant/components/hassio/http.py +++ b/homeassistant/components/hassio/http.py @@ -36,7 +36,7 @@ NO_TIMEOUT = { } NO_AUTH = { - re.compile(r'^app-(es5|latest)/(index|hassio-app).html$'), + re.compile(r'^app-(es5|latest)/.+$'), re.compile(r'^addons/[^/]*/logo$') } diff --git a/tests/components/hassio/test_http.py b/tests/components/hassio/test_http.py index ed425ad8cca..ac90deb9f73 100644 --- a/tests/components/hassio/test_http.py +++ b/tests/components/hassio/test_http.py @@ -48,7 +48,7 @@ def test_auth_required_forward_request(hassio_client): @pytest.mark.parametrize( 'build_type', [ 'es5/index.html', 'es5/hassio-app.html', 'latest/index.html', - 'latest/hassio-app.html' + 'latest/hassio-app.html', 'es5/some-chunk.js', 'es5/app.js', ]) def test_forward_request_no_auth_for_panel(hassio_client, build_type): """Test no auth needed for .""" From cd0e321668706c767d4be49dd66002743dac9d7a Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 27 May 2018 17:18:53 -0400 Subject: [PATCH 26/33] Version bump to 0.70.0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 0ff3f0738a1..84088c4511c 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 70 -PATCH_VERSION = '0b7' +PATCH_VERSION = '0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From 0eddd287c5e68cc3ed2d27245a0d54f76b3a1544 Mon Sep 17 00:00:00 2001 From: MizterB <5458030+MizterB@users.noreply.github.com> Date: Mon, 28 May 2018 10:21:00 -0400 Subject: [PATCH 27/33] Update Hue platform to aiohue 1.5.0, and re-implement logic for duplicate scene names. (#14653) --- homeassistant/components/hue/__init__.py | 2 +- homeassistant/components/hue/bridge.py | 18 +++++++++++++++--- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/hue/__init__.py b/homeassistant/components/hue/__init__.py index 0aed854d4e4..251d8cba095 100644 --- a/homeassistant/components/hue/__init__.py +++ b/homeassistant/components/hue/__init__.py @@ -17,7 +17,7 @@ from .bridge import HueBridge # Loading the config flow file will register the flow from .config_flow import configured_hosts -REQUIREMENTS = ['aiohue==1.3.0'] +REQUIREMENTS = ['aiohue==1.5.0'] _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/hue/bridge.py b/homeassistant/components/hue/bridge.py index 5ff5e2dbf6f..d7a8dc7f730 100644 --- a/homeassistant/components/hue/bridge.py +++ b/homeassistant/components/hue/bridge.py @@ -124,9 +124,21 @@ class HueBridge(object): (group for group in self.api.groups.values() if group.name == group_name), None) - scene_id = next( - (scene.id for scene in self.api.scenes.values() - if scene.name == scene_name), None) + # The same scene name can exist in multiple groups. + # In this case, activate first scene that contains the + # the exact same light IDs as the group + scenes = [] + for scene in self.api.scenes.values(): + if scene.name == scene_name: + scenes.append(scene) + if len(scenes) == 1: + scene_id = scenes[0].id + else: + group_lights = sorted(group.lights) + for scene in scenes: + if group_lights == scene.lights: + scene_id = scene.id + break # If we can't find it, fetch latest info. if not updated and (group is None or scene_id is None): diff --git a/requirements_all.txt b/requirements_all.txt index ae16651d8e9..d6dc1725ba2 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -86,7 +86,7 @@ aiodns==1.1.1 aiohttp_cors==0.7.0 # homeassistant.components.hue -aiohue==1.3.0 +aiohue==1.5.0 # homeassistant.components.sensor.imap aioimaplib==0.7.13 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index ce458995d2a..cb0dbc0689f 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -35,7 +35,7 @@ aioautomatic==0.6.5 aiohttp_cors==0.7.0 # homeassistant.components.hue -aiohue==1.3.0 +aiohue==1.5.0 # homeassistant.components.notify.apns apns2==0.3.0 From 64f157a036dae9c7cfdb14113480f73df206e1d1 Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Tue, 29 May 2018 10:15:30 +0200 Subject: [PATCH 28/33] Ignore unsupported Sonos favorite lists (#14665) --- .../components/media_player/sonos.py | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/media_player/sonos.py b/homeassistant/components/media_player/sonos.py index 06e5f3befe4..0f536e1edfb 100644 --- a/homeassistant/components/media_player/sonos.py +++ b/homeassistant/components/media_player/sonos.py @@ -427,15 +427,18 @@ class SonosDevice(MediaPlayerDevice): self.update_volume() self._favorites = [] - for fav in self.soco.music_library.get_sonos_favorites(): - # SoCo 0.14 raises a generic Exception on invalid xml in favorites. - # Filter those out now so our list is safe to use. - try: - if fav.reference.get_uri(): - self._favorites.append(fav) - # pylint: disable=broad-except - except Exception: - _LOGGER.debug("Ignoring invalid favorite '%s'", fav.title) + # SoCo 0.14 raises a generic Exception on invalid xml in favorites. + # Filter those out now so our list is safe to use. + # pylint: disable=broad-except + try: + for fav in self.soco.music_library.get_sonos_favorites(): + try: + if fav.reference.get_uri(): + self._favorites.append(fav) + except Exception: + _LOGGER.debug("Ignoring invalid favorite '%s'", fav.title) + except Exception: + _LOGGER.debug("Ignoring invalid favorite list") def _radio_artwork(self, url): """Return the private URL with artwork for a radio stream.""" From 40aba3d7850855f75ecc8db12d47c1aa63183d93 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Tue, 29 May 2018 15:03:45 +0200 Subject: [PATCH 29/33] MQTT Cover Fix Assumed State (#14672) --- homeassistant/components/cover/mqtt.py | 5 +++++ tests/components/cover/test_mqtt.py | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/cover/mqtt.py b/homeassistant/components/cover/mqtt.py index 0f31d3a9fe0..235ff5799cc 100644 --- a/homeassistant/components/cover/mqtt.py +++ b/homeassistant/components/cover/mqtt.py @@ -235,6 +235,11 @@ class MqttCover(MqttAvailability, CoverDevice): """No polling needed.""" return False + @property + def assumed_state(self): + """Return true if we do optimistic updates.""" + return self._optimistic + @property def name(self): """Return the name of the cover.""" diff --git a/tests/components/cover/test_mqtt.py b/tests/components/cover/test_mqtt.py index 23a7b32fc28..aea6398e3ae 100644 --- a/tests/components/cover/test_mqtt.py +++ b/tests/components/cover/test_mqtt.py @@ -2,8 +2,8 @@ import unittest from homeassistant.setup import setup_component -from homeassistant.const import STATE_OPEN, STATE_CLOSED, STATE_UNKNOWN,\ - STATE_UNAVAILABLE +from homeassistant.const import STATE_OPEN, STATE_CLOSED, STATE_UNKNOWN, \ + STATE_UNAVAILABLE, ATTR_ASSUMED_STATE import homeassistant.components.cover as cover from homeassistant.components.cover.mqtt import MqttCover @@ -40,6 +40,7 @@ class TestCoverMQTT(unittest.TestCase): state = self.hass.states.get('cover.test') self.assertEqual(STATE_UNKNOWN, state.state) + self.assertFalse(state.attributes.get(ATTR_ASSUMED_STATE)) fire_mqtt_message(self.hass, 'state-topic', '0') self.hass.block_till_done() @@ -112,6 +113,7 @@ class TestCoverMQTT(unittest.TestCase): state = self.hass.states.get('cover.test') self.assertEqual(STATE_UNKNOWN, state.state) + self.assertTrue(state.attributes.get(ATTR_ASSUMED_STATE)) cover.open_cover(self.hass, 'cover.test') self.hass.block_till_done() From 753ffdaffdbe1bf18048484dc8e14955b8a1db9a Mon Sep 17 00:00:00 2001 From: Marius Date: Fri, 1 Jun 2018 00:26:59 +0300 Subject: [PATCH 30/33] Fix Eco mode display on Nest (#14706) * Fix Eco mode display on Nest * Fix Hound problems --- homeassistant/components/climate/nest.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/climate/nest.py b/homeassistant/components/climate/nest.py index 0a5344fdf98..28e8020ab90 100644 --- a/homeassistant/components/climate/nest.py +++ b/homeassistant/components/climate/nest.py @@ -134,7 +134,9 @@ class NestThermostat(ClimateDevice): @property def target_temperature(self): """Return the temperature we try to reach.""" - if self._mode != NEST_MODE_HEAT_COOL and not self.is_away_mode_on: + if self._mode != NEST_MODE_HEAT_COOL and \ + self._mode != STATE_ECO and \ + not self.is_away_mode_on: return self._target_temperature return None From f7f0138cff6eea549000e8d5bd9852d01fceea74 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 31 May 2018 17:25:35 -0400 Subject: [PATCH 31/33] Bump frontend to 20180531.0 --- homeassistant/components/frontend/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index 2bd7283e38e..5ebf6e8762f 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -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==20180526.4'] +REQUIREMENTS = ['home-assistant-frontend==20180531.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log'] diff --git a/requirements_all.txt b/requirements_all.txt index d6dc1725ba2..9749557873d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -389,7 +389,7 @@ hipnotify==1.0.8 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180526.4 +home-assistant-frontend==20180531.0 # homeassistant.components.homekit_controller # homekit==0.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index cb0dbc0689f..1e04d3fdb03 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -81,7 +81,7 @@ hbmqtt==0.9.2 holidays==0.9.5 # homeassistant.components.frontend -home-assistant-frontend==20180526.4 +home-assistant-frontend==20180531.0 # homeassistant.components.influxdb # homeassistant.components.sensor.influxdb From d4a4938fce1caf08bb651f07a0955163ffc23fbb Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 31 May 2018 17:27:55 -0400 Subject: [PATCH 32/33] Version bump to 0.70.1 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 84088c4511c..bb60a42fff9 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 70 -PATCH_VERSION = '0' +PATCH_VERSION = '1' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From d31e01b8778780a79ce254fd091fb098f4ac8923 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 31 May 2018 17:58:03 -0400 Subject: [PATCH 33/33] Revert "Remove simplepush.io (#14358)" This reverts commit 612a37b2dd37f4856ac7103bb7bc6f7dc6d8b970. --- .coveragerc | 1 + homeassistant/components/notify/simplepush.py | 59 +++++++++++++++++++ requirements_all.txt | 3 + 3 files changed, 63 insertions(+) create mode 100644 homeassistant/components/notify/simplepush.py diff --git a/.coveragerc b/.coveragerc index d361cf2ddad..80ca261f32d 100644 --- a/.coveragerc +++ b/.coveragerc @@ -542,6 +542,7 @@ omit = homeassistant/components/notify/rest.py homeassistant/components/notify/rocketchat.py homeassistant/components/notify/sendgrid.py + homeassistant/components/notify/simplepush.py homeassistant/components/notify/slack.py homeassistant/components/notify/smtp.py homeassistant/components/notify/stride.py diff --git a/homeassistant/components/notify/simplepush.py b/homeassistant/components/notify/simplepush.py new file mode 100644 index 00000000000..9d5c58fc5b1 --- /dev/null +++ b/homeassistant/components/notify/simplepush.py @@ -0,0 +1,59 @@ +""" +Simplepush notification service. + +For more details about this platform, please refer to the documentation at +https://home-assistant.io/components/notify.simplepush/ +""" +import logging + +import voluptuous as vol + +import homeassistant.helpers.config_validation as cv +from homeassistant.components.notify import ( + ATTR_TITLE, ATTR_TITLE_DEFAULT, PLATFORM_SCHEMA, BaseNotificationService) +from homeassistant.const import CONF_PASSWORD + +REQUIREMENTS = ['simplepush==1.1.4'] + +_LOGGER = logging.getLogger(__name__) + +ATTR_ENCRYPTED = 'encrypted' + +CONF_DEVICE_KEY = 'device_key' +CONF_EVENT = 'event' +CONF_SALT = 'salt' + +PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ + vol.Required(CONF_DEVICE_KEY): cv.string, + vol.Optional(CONF_EVENT): cv.string, + vol.Inclusive(CONF_PASSWORD, ATTR_ENCRYPTED): cv.string, + vol.Inclusive(CONF_SALT, ATTR_ENCRYPTED): cv.string, +}) + + +def get_service(hass, config, discovery_info=None): + """Get the Simplepush notification service.""" + return SimplePushNotificationService(config) + + +class SimplePushNotificationService(BaseNotificationService): + """Implementation of the notification service for Simplepush.""" + + def __init__(self, config): + """Initialize the Simplepush notification service.""" + self._device_key = config.get(CONF_DEVICE_KEY) + self._event = config.get(CONF_EVENT) + self._password = config.get(CONF_PASSWORD) + self._salt = config.get(CONF_SALT) + + def send_message(self, message='', **kwargs): + """Send a message to a Simplepush user.""" + from simplepush import send, send_encrypted + + title = kwargs.get(ATTR_TITLE, ATTR_TITLE_DEFAULT) + + if self._password: + send_encrypted(self._device_key, self._password, self._salt, title, + message, event=self._event) + else: + send(self._device_key, title, message, event=self._event) diff --git a/requirements_all.txt b/requirements_all.txt index 9749557873d..3bed3fa9fdf 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1186,6 +1186,9 @@ sharp_aquos_rc==0.3.2 # homeassistant.components.sensor.shodan shodan==1.7.7 +# homeassistant.components.notify.simplepush +simplepush==1.1.4 + # homeassistant.components.alarm_control_panel.simplisafe simplisafe-python==1.0.5