From 6fb8378b459b6e7cb25395440795870f62c1b9fe Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 4 Jan 2019 13:47:02 -0500 Subject: [PATCH 01/24] Bumped version to 0.85.0b0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index a03b5fe52bc..e8347eddc5a 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 85 -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 57c96a5489c0f26129731d264751d97c40c47682 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Sat, 5 Jan 2019 16:00:07 +0100 Subject: [PATCH 02/24] Add ESPHome native API discovery (#19399) * ESPHome discovery * Add note about netdisco * :abcd: * Address comments * Bump netdisco to 2.3.0 * Update requirements_all.txt --- homeassistant/components/discovery.py | 3 +- .../components/esphome/config_flow.py | 18 +++++ requirements_all.txt | 2 +- tests/components/esphome/test_config_flow.py | 65 ++++++++++++++++++- 4 files changed, 84 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/discovery.py b/homeassistant/components/discovery.py index 5d8102e3056..f87395520bb 100644 --- a/homeassistant/components/discovery.py +++ b/homeassistant/components/discovery.py @@ -21,7 +21,7 @@ from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.helpers.discovery import async_load_platform, async_discover import homeassistant.util.dt as dt_util -REQUIREMENTS = ['netdisco==2.2.0'] +REQUIREMENTS = ['netdisco==2.3.0'] DOMAIN = 'discovery' @@ -51,6 +51,7 @@ SERVICE_DLNA_DMR = 'dlna_dmr' CONFIG_ENTRY_HANDLERS = { SERVICE_DAIKIN: 'daikin', SERVICE_DECONZ: 'deconz', + 'esphome': 'esphome', 'google_cast': 'cast', SERVICE_HUE: 'hue', SERVICE_TELLDUSLIVE: 'tellduslive', diff --git a/homeassistant/components/esphome/config_flow.py b/homeassistant/components/esphome/config_flow.py index 017cf8c8ee6..24edaf152e6 100644 --- a/homeassistant/components/esphome/config_flow.py +++ b/homeassistant/components/esphome/config_flow.py @@ -53,6 +53,24 @@ class EsphomeFlowHandler(config_entries.ConfigFlow): errors=errors ) + async def async_step_discovery(self, user_input: ConfigType): + """Handle discovery.""" + # mDNS hostname has additional '.' at end + hostname = user_input['hostname'][:-1] + hosts = (hostname, user_input['host']) + for entry in self._async_current_entries(): + if entry.data['host'] in hosts: + return self.async_abort( + reason='already_configured' + ) + + # Prefer .local addresses (mDNS is available after all, otherwise + # we wouldn't have received the discovery message) + return await self.async_step_user(user_input={ + 'host': hostname, + 'port': user_input['port'], + }) + def _async_get_entry(self): return self.async_create_entry( title=self._name, diff --git a/requirements_all.txt b/requirements_all.txt index 4242e0b38d1..c20a2d8a459 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -705,7 +705,7 @@ nessclient==0.9.9 netdata==0.1.2 # homeassistant.components.discovery -netdisco==2.2.0 +netdisco==2.3.0 # homeassistant.components.sensor.neurio_energy neurio==0.3.1 diff --git a/tests/components/esphome/test_config_flow.py b/tests/components/esphome/test_config_flow.py index d90db501a54..476b3e3c5c1 100644 --- a/tests/components/esphome/test_config_flow.py +++ b/tests/components/esphome/test_config_flow.py @@ -1,11 +1,11 @@ """Test config flow.""" from collections import namedtuple -from unittest.mock import patch, MagicMock +from unittest.mock import MagicMock, patch import pytest from homeassistant.components.esphome import config_flow -from tests.common import mock_coro +from tests.common import mock_coro, MockConfigEntry MockDeviceInfo = namedtuple("DeviceInfo", ["uses_password", "name"]) @@ -218,3 +218,64 @@ async def test_user_login_connection_error(hass, mock_api_connection_error, assert result['errors'] == { 'base': 'connection_error' } + + +async def test_discovery_initiation(hass, mock_client): + """Test discovery importing works.""" + flow = config_flow.EsphomeFlowHandler() + flow.hass = hass + service_info = { + 'host': '192.168.43.183', + 'port': 6053, + 'hostname': 'test8266.local.', + 'properties': {} + } + + mock_client.device_info.return_value = mock_coro( + MockDeviceInfo(False, "test8266")) + + result = await flow.async_step_discovery(user_input=service_info) + assert result['type'] == 'create_entry' + assert result['title'] == 'test8266' + assert result['data']['host'] == 'test8266.local' + assert result['data']['port'] == 6053 + + +async def test_discovery_already_configured_hostname(hass, mock_client): + """Test discovery aborts if already configured via hostname.""" + MockConfigEntry( + domain='esphome', + data={'host': 'test8266.local', 'port': 6053, 'password': ''} + ).add_to_hass(hass) + + flow = config_flow.EsphomeFlowHandler() + flow.hass = hass + service_info = { + 'host': '192.168.43.183', + 'port': 6053, + 'hostname': 'test8266.local.', + 'properties': {} + } + result = await flow.async_step_discovery(user_input=service_info) + assert result['type'] == 'abort' + assert result['reason'] == 'already_configured' + + +async def test_discovery_already_configured_ip(hass, mock_client): + """Test discovery aborts if already configured via static IP.""" + MockConfigEntry( + domain='esphome', + data={'host': '192.168.43.183', 'port': 6053, 'password': ''} + ).add_to_hass(hass) + + flow = config_flow.EsphomeFlowHandler() + flow.hass = hass + service_info = { + 'host': '192.168.43.183', + 'port': 6053, + 'hostname': 'test8266.local.', + 'properties': {} + } + result = await flow.async_step_discovery(user_input=service_info) + assert result['type'] == 'abort' + assert result['reason'] == 'already_configured' From afa0d37ff06e94d97d45621d3cff332209c2a82a Mon Sep 17 00:00:00 2001 From: Eliseo Martelli Date: Sat, 5 Jan 2019 17:42:36 +0100 Subject: [PATCH 03/24] Rename air pollutants to air quality (#19448) * mv component folder * moved in airquality * changed names in files * renamed test init * renamed test air quality * renamed in tests * renamed coverage * fixed naming * corrected attr names * changed attr names --- .coveragerc | 2 +- .../__init__.py | 60 +++++++++---------- .../{air_pollutants => air_quality}/demo.py | 20 +++---- .../opensensemap.py | 20 +++---- homeassistant/components/demo.py | 2 +- requirements_all.txt | 2 +- tests/components/air_pollutants/__init__.py | 1 - .../air_pollutants/test_air_pollutants.py | 42 ------------- tests/components/air_quality/__init__.py | 1 + .../air_quality/test_air_quality.py | 42 +++++++++++++ 10 files changed, 96 insertions(+), 96 deletions(-) rename homeassistant/components/{air_pollutants => air_quality}/__init__.py (66%) rename homeassistant/components/{air_pollutants => air_quality}/demo.py (66%) rename homeassistant/components/{air_pollutants => air_quality}/opensensemap.py (80%) delete mode 100644 tests/components/air_pollutants/__init__.py delete mode 100644 tests/components/air_pollutants/test_air_pollutants.py create mode 100644 tests/components/air_quality/__init__.py create mode 100644 tests/components/air_quality/test_air_quality.py diff --git a/.coveragerc b/.coveragerc index 2be86802a85..3f8d0e6959b 100644 --- a/.coveragerc +++ b/.coveragerc @@ -442,7 +442,7 @@ omit = homeassistant/components/spider.py homeassistant/components/*/spider.py - homeassistant/components/air_pollutants/opensensemap.py + homeassistant/components/air_quality/opensensemap.py homeassistant/components/alarm_control_panel/alarmdotcom.py homeassistant/components/alarm_control_panel/canary.py homeassistant/components/alarm_control_panel/concord232.py diff --git a/homeassistant/components/air_pollutants/__init__.py b/homeassistant/components/air_quality/__init__.py similarity index 66% rename from homeassistant/components/air_pollutants/__init__.py rename to homeassistant/components/air_quality/__init__.py index f810807242c..7aed61ee11c 100644 --- a/homeassistant/components/air_pollutants/__init__.py +++ b/homeassistant/components/air_quality/__init__.py @@ -1,8 +1,8 @@ """ -Component for handling Air Pollutants data for your location. +Component for handling Air Quality data for your location. For more details about this component, please refer to the documentation at -https://home-assistant.io/components/air_pollutants/ +https://home-assistant.io/components/air_quality/ """ from datetime import timedelta import logging @@ -13,43 +13,43 @@ from homeassistant.helpers.entity import Entity _LOGGER = logging.getLogger(__name__) -ATTR_AIR_POLLUTANTS_AQI = 'air_quality_index' -ATTR_AIR_POLLUTANTS_ATTRIBUTION = 'attribution' -ATTR_AIR_POLLUTANTS_C02 = 'carbon_dioxide' -ATTR_AIR_POLLUTANTS_CO = 'carbon_monoxide' -ATTR_AIR_POLLUTANTS_N2O = 'nitrogen_oxide' -ATTR_AIR_POLLUTANTS_NO = 'nitrogen_monoxide' -ATTR_AIR_POLLUTANTS_NO2 = 'nitrogen_dioxide' -ATTR_AIR_POLLUTANTS_OZONE = 'ozone' -ATTR_AIR_POLLUTANTS_PM_0_1 = 'particulate_matter_0_1' -ATTR_AIR_POLLUTANTS_PM_10 = 'particulate_matter_10' -ATTR_AIR_POLLUTANTS_PM_2_5 = 'particulate_matter_2_5' -ATTR_AIR_POLLUTANTS_SO2 = 'sulphur_dioxide' +ATTR_AQI = 'air_quality_index' +ATTR_ATTRIBUTION = 'attribution' +ATTR_C02 = 'carbon_dioxide' +ATTR_CO = 'carbon_monoxide' +ATTR_N2O = 'nitrogen_oxide' +ATTR_NO = 'nitrogen_monoxide' +ATTR_NO2 = 'nitrogen_dioxide' +ATTR_OZONE = 'ozone' +ATTR_PM_0_1 = 'particulate_matter_0_1' +ATTR_PM_10 = 'particulate_matter_10' +ATTR_PM_2_5 = 'particulate_matter_2_5' +ATTR_SO2 = 'sulphur_dioxide' -DOMAIN = 'air_pollutants' +DOMAIN = 'air_quality' ENTITY_ID_FORMAT = DOMAIN + '.{}' SCAN_INTERVAL = timedelta(seconds=30) PROP_TO_ATTR = { - 'air_quality_index': ATTR_AIR_POLLUTANTS_AQI, - 'attribution': ATTR_AIR_POLLUTANTS_ATTRIBUTION, - 'carbon_dioxide': ATTR_AIR_POLLUTANTS_C02, - 'carbon_monoxide': ATTR_AIR_POLLUTANTS_CO, - 'nitrogen_oxide': ATTR_AIR_POLLUTANTS_N2O, - 'nitrogen_monoxide': ATTR_AIR_POLLUTANTS_NO, - 'nitrogen_dioxide': ATTR_AIR_POLLUTANTS_NO2, - 'ozone': ATTR_AIR_POLLUTANTS_OZONE, - 'particulate_matter_0_1': ATTR_AIR_POLLUTANTS_PM_0_1, - 'particulate_matter_10': ATTR_AIR_POLLUTANTS_PM_10, - 'particulate_matter_2_5': ATTR_AIR_POLLUTANTS_PM_2_5, - 'sulphur_dioxide': ATTR_AIR_POLLUTANTS_SO2, + 'air_quality_index': ATTR_AQI, + 'attribution': ATTR_ATTRIBUTION, + 'carbon_dioxide': ATTR_C02, + 'carbon_monoxide': ATTR_CO, + 'nitrogen_oxide': ATTR_N2O, + 'nitrogen_monoxide': ATTR_NO, + 'nitrogen_dioxide': ATTR_NO2, + 'ozone': ATTR_OZONE, + 'particulate_matter_0_1': ATTR_PM_0_1, + 'particulate_matter_10': ATTR_PM_10, + 'particulate_matter_2_5': ATTR_PM_2_5, + 'sulphur_dioxide': ATTR_SO2, } async def async_setup(hass, config): - """Set up the air pollutants component.""" + """Set up the air quality component.""" component = hass.data[DOMAIN] = EntityComponent( _LOGGER, DOMAIN, hass, SCAN_INTERVAL) await component.async_setup(config) @@ -66,8 +66,8 @@ async def async_unload_entry(hass, entry): return await hass.data[DOMAIN].async_unload_entry(entry) -class AirPollutantsEntity(Entity): - """ABC for air pollutants data.""" +class AirQualityEntity(Entity): + """ABC for air quality data.""" @property def particulate_matter_2_5(self): diff --git a/homeassistant/components/air_pollutants/demo.py b/homeassistant/components/air_quality/demo.py similarity index 66% rename from homeassistant/components/air_pollutants/demo.py rename to homeassistant/components/air_quality/demo.py index 06c407d8608..b2b9c10574f 100644 --- a/homeassistant/components/air_pollutants/demo.py +++ b/homeassistant/components/air_quality/demo.py @@ -1,25 +1,25 @@ """ -Demo platform that offers fake air pollutants data. +Demo platform that offers fake air quality data. For more details about this platform, please refer to the documentation https://home-assistant.io/components/demo/ """ -from homeassistant.components.air_pollutants import AirPollutantsEntity +from homeassistant.components.air_quality import AirQualityEntity def setup_platform(hass, config, add_entities, discovery_info=None): - """Set up the Air Pollutants.""" + """Set up the Air Quality.""" add_entities([ - DemoAirPollutants('Home', 14, 23, 100), - DemoAirPollutants('Office', 4, 16, None) + DemoAirQuality('Home', 14, 23, 100), + DemoAirQuality('Office', 4, 16, None) ]) -class DemoAirPollutants(AirPollutantsEntity): - """Representation of Air Pollutants data.""" +class DemoAirQuality(AirQualityEntity): + """Representation of Air Quality data.""" def __init__(self, name, pm_2_5, pm_10, n2o): - """Initialize the Demo Air Pollutants.""" + """Initialize the Demo Air Quality.""" self._name = name self._pm_2_5 = pm_2_5 self._pm_10 = pm_10 @@ -28,11 +28,11 @@ class DemoAirPollutants(AirPollutantsEntity): @property def name(self): """Return the name of the sensor.""" - return '{} {}'.format('Demo Air Pollutants', self._name) + return '{} {}'.format('Demo Air Quality', self._name) @property def should_poll(self): - """No polling needed for Demo Air Pollutants.""" + """No polling needed for Demo Air Quality.""" return False @property diff --git a/homeassistant/components/air_pollutants/opensensemap.py b/homeassistant/components/air_quality/opensensemap.py similarity index 80% rename from homeassistant/components/air_pollutants/opensensemap.py rename to homeassistant/components/air_quality/opensensemap.py index ae4625bbbe9..fe3cca4876e 100644 --- a/homeassistant/components/air_pollutants/opensensemap.py +++ b/homeassistant/components/air_quality/opensensemap.py @@ -1,16 +1,16 @@ """ -Support for openSenseMap Air Pollutants data. +Support for openSenseMap Air Quality data. For more details about this platform, please refer to the documentation at -https://home-assistant.io/components/air_pollutants_opensensemap/ +https://home-assistant.io/components/air_quality/opensensemap/ """ from datetime import timedelta import logging import voluptuous as vol -from homeassistant.components.air_pollutants import ( - PLATFORM_SCHEMA, AirPollutantsEntity) +from homeassistant.components.air_quality import ( + PLATFORM_SCHEMA, AirQualityEntity) from homeassistant.const import CONF_NAME from homeassistant.helpers.aiohttp_client import async_get_clientsession import homeassistant.helpers.config_validation as cv @@ -34,7 +34,7 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ async def async_setup_platform( hass, config, async_add_entities, discovery_info=None): - """Set up the openSenseMap air pollutants platform.""" + """Set up the openSenseMap air quality platform.""" from opensensemap_api import OpenSenseMap name = config.get(CONF_NAME) @@ -51,20 +51,20 @@ async def async_setup_platform( station_name = osm_api.api.data['name'] if name is None else name - async_add_entities([OpenSenseMapPollutants(station_name, osm_api)], True) + async_add_entities([OpenSenseMapQuality(station_name, osm_api)], True) -class OpenSenseMapPollutants(AirPollutantsEntity): - """Implementation of an openSenseMap air pollutants entity.""" +class OpenSenseMapQuality(AirQualityEntity): + """Implementation of an openSenseMap air quality entity.""" def __init__(self, name, osm): - """Initialize the air pollutants entity.""" + """Initialize the air quality entity.""" self._name = name self._osm = osm @property def name(self): - """Return the name of the air pollutants entity.""" + """Return the name of the air quality entity.""" return self._name @property diff --git a/homeassistant/components/demo.py b/homeassistant/components/demo.py index d1bca45400b..2b9854fbcc7 100644 --- a/homeassistant/components/demo.py +++ b/homeassistant/components/demo.py @@ -15,7 +15,7 @@ DEPENDENCIES = ['conversation', 'introduction', 'zone'] DOMAIN = 'demo' COMPONENTS_WITH_DEMO_PLATFORM = [ - 'air_pollutants', + 'air_quality', 'alarm_control_panel', 'binary_sensor', 'calendar', diff --git a/requirements_all.txt b/requirements_all.txt index c20a2d8a459..1117f70f039 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -746,7 +746,7 @@ openevsewifi==0.4 # homeassistant.components.media_player.openhome openhomedevice==0.4.2 -# homeassistant.components.air_pollutants.opensensemap +# homeassistant.components.air_quality.opensensemap opensensemap-api==0.1.3 # homeassistant.components.switch.orvibo diff --git a/tests/components/air_pollutants/__init__.py b/tests/components/air_pollutants/__init__.py deleted file mode 100644 index 98af2395a1f..00000000000 --- a/tests/components/air_pollutants/__init__.py +++ /dev/null @@ -1 +0,0 @@ -"""The tests for Air Pollutants platforms.""" diff --git a/tests/components/air_pollutants/test_air_pollutants.py b/tests/components/air_pollutants/test_air_pollutants.py deleted file mode 100644 index bbbd85b3a0c..00000000000 --- a/tests/components/air_pollutants/test_air_pollutants.py +++ /dev/null @@ -1,42 +0,0 @@ -"""The tests for the Air Pollutants component.""" -from homeassistant.components.air_pollutants import ( - ATTR_AIR_POLLUTANTS_ATTRIBUTION, ATTR_AIR_POLLUTANTS_N2O, - ATTR_AIR_POLLUTANTS_OZONE, ATTR_AIR_POLLUTANTS_PM_10) -from homeassistant.setup import async_setup_component - - -async def test_state(hass): - """Test Air Pollutants state.""" - config = { - 'air_pollutants': { - 'platform': 'demo', - } - } - - assert await async_setup_component(hass, 'air_pollutants', config) - - state = hass.states.get('air_pollutants.demo_air_pollutants_home') - assert state is not None - - assert state.state == '14' - - -async def test_attributes(hass): - """Test Air Pollutants attributes.""" - config = { - 'air_pollutants': { - 'platform': 'demo', - } - } - - assert await async_setup_component(hass, 'air_pollutants', config) - - state = hass.states.get('air_pollutants.demo_air_pollutants_office') - assert state is not None - - data = state.attributes - assert data.get(ATTR_AIR_POLLUTANTS_PM_10) == 16 - assert data.get(ATTR_AIR_POLLUTANTS_N2O) is None - assert data.get(ATTR_AIR_POLLUTANTS_OZONE) is None - assert data.get(ATTR_AIR_POLLUTANTS_ATTRIBUTION) == \ - 'Powered by Home Assistant' diff --git a/tests/components/air_quality/__init__.py b/tests/components/air_quality/__init__.py new file mode 100644 index 00000000000..c53122cb1b9 --- /dev/null +++ b/tests/components/air_quality/__init__.py @@ -0,0 +1 @@ +"""The tests for Air Quality platforms.""" diff --git a/tests/components/air_quality/test_air_quality.py b/tests/components/air_quality/test_air_quality.py new file mode 100644 index 00000000000..7ad1300b945 --- /dev/null +++ b/tests/components/air_quality/test_air_quality.py @@ -0,0 +1,42 @@ +"""The tests for the Air Quality component.""" +from homeassistant.components.air_quality import ( + ATTR_ATTRIBUTION, ATTR_N2O, + ATTR_OZONE, ATTR_PM_10) +from homeassistant.setup import async_setup_component + + +async def test_state(hass): + """Test Air Quality state.""" + config = { + 'air_quality': { + 'platform': 'demo', + } + } + + assert await async_setup_component(hass, 'air_quality', config) + + state = hass.states.get('air_quality.demo_air_quality_home') + assert state is not None + + assert state.state == '14' + + +async def test_attributes(hass): + """Test Air Quality attributes.""" + config = { + 'air_quality': { + 'platform': 'demo', + } + } + + assert await async_setup_component(hass, 'air_quality', config) + + state = hass.states.get('air_quality.demo_air_quality_office') + assert state is not None + + data = state.attributes + assert data.get(ATTR_PM_10) == 16 + assert data.get(ATTR_N2O) is None + assert data.get(ATTR_OZONE) is None + assert data.get(ATTR_ATTRIBUTION) == \ + 'Powered by Home Assistant' From 3453d31f010c12757f72fe690b6bc6c5368a07ba Mon Sep 17 00:00:00 2001 From: Alexei Chetroi Date: Fri, 4 Jan 2019 16:05:37 -0500 Subject: [PATCH 04/24] Use manufacturer id only for configure_reporting only when specified. (#19729) --- homeassistant/components/zha/helpers.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/zha/helpers.py b/homeassistant/components/zha/helpers.py index 426bceeb634..3212849f721 100644 --- a/homeassistant/components/zha/helpers.py +++ b/homeassistant/components/zha/helpers.py @@ -67,10 +67,13 @@ async def configure_reporting(entity_id, cluster, attr, skip_bind=False, attr_name = cluster.attributes.get(attr, [attr])[0] cluster_name = cluster.ep_attribute + kwargs = {} + if manufacturer: + kwargs['manufacturer'] = manufacturer try: res = await cluster.configure_reporting(attr, min_report, max_report, reportable_change, - manufacturer=manufacturer) + **kwargs) _LOGGER.debug( "%s: reporting '%s' attr on '%s' cluster: %d/%d/%d: Result: '%s'", entity_id, attr_name, cluster_name, min_report, max_report, From 3a466195b9e3529745ae7a9b832ddcd41092bafc Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Mon, 7 Jan 2019 13:36:16 +0100 Subject: [PATCH 05/24] Simplify data_key for a stable unique_id because the order of the dict will not be preserved (Closes: #13522) (#19766) --- homeassistant/components/cover/xiaomi_aqara.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/cover/xiaomi_aqara.py b/homeassistant/components/cover/xiaomi_aqara.py index 3ed0a70b1e0..ead2c0e9219 100644 --- a/homeassistant/components/cover/xiaomi_aqara.py +++ b/homeassistant/components/cover/xiaomi_aqara.py @@ -18,9 +18,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): model = device['model'] if model == 'curtain': devices.append(XiaomiGenericCover(device, "Curtain", - {'status': 'status', - 'pos': 'curtain_level'}, - gateway)) + 'status', gateway)) add_entities(devices) @@ -45,20 +43,20 @@ class XiaomiGenericCover(XiaomiDevice, CoverDevice): def close_cover(self, **kwargs): """Close the cover.""" - self._write_to_hub(self._sid, **{self._data_key['status']: 'close'}) + self._write_to_hub(self._sid, **{self._data_key: 'close'}) def open_cover(self, **kwargs): """Open the cover.""" - self._write_to_hub(self._sid, **{self._data_key['status']: 'open'}) + self._write_to_hub(self._sid, **{self._data_key: 'open'}) def stop_cover(self, **kwargs): """Stop the cover.""" - self._write_to_hub(self._sid, **{self._data_key['status']: 'stop'}) + self._write_to_hub(self._sid, **{self._data_key: 'stop'}) def set_cover_position(self, **kwargs): """Move the cover to a specific position.""" position = kwargs.get(ATTR_POSITION) - self._write_to_hub(self._sid, **{self._data_key['pos']: str(position)}) + self._write_to_hub(self._sid, **{ATTR_CURTAIN_LEVEL: str(position)}) def parse_data(self, data, raw_data): """Parse data sent by gateway.""" From ed881f399fabc3f472db677a89bd2df8b9e0d46d Mon Sep 17 00:00:00 2001 From: Sebastian Muszynski Date: Fri, 4 Jan 2019 22:02:42 +0100 Subject: [PATCH 06/24] Don't slugify unique id (#19770) --- homeassistant/components/xiaomi_aqara.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/xiaomi_aqara.py b/homeassistant/components/xiaomi_aqara.py index aa2102ca805..25e7a72db90 100644 --- a/homeassistant/components/xiaomi_aqara.py +++ b/homeassistant/components/xiaomi_aqara.py @@ -20,7 +20,6 @@ import homeassistant.helpers.config_validation as cv from homeassistant.helpers.entity import Entity from homeassistant.helpers.event import async_track_point_in_utc_time from homeassistant.util.dt import utcnow -from homeassistant.util import slugify REQUIREMENTS = ['PyXiaomiGateway==0.11.1'] @@ -222,11 +221,11 @@ class XiaomiDevice(Entity): if hasattr(self, '_data_key') \ and self._data_key: # pylint: disable=no-member - self._unique_id = slugify("{}-{}".format( + self._unique_id = "{}{}".format( self._data_key, # pylint: disable=no-member - self._sid)) + self._sid) else: - self._unique_id = slugify("{}-{}".format(self._type, self._sid)) + self._unique_id = "{}{}".format(self._type, self._sid) def _add_push_data_job(self, *args): self.hass.add_job(self.push_data, *args) From 6d9c37d636bbe76640304f584606964d9f18d503 Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Fri, 4 Jan 2019 22:10:52 +0100 Subject: [PATCH 07/24] Fix some ESPHome race conditions (#19772) * Fix some ESPHome race conditions * Remove debug * Update requirements_all.txt * :ambulance: Fix IDE line length settings --- homeassistant/components/esphome/__init__.py | 51 +++++++++++-------- .../components/esphome/config_flow.py | 15 ++---- requirements_all.txt | 2 +- tests/components/esphome/test_config_flow.py | 42 ++------------- 4 files changed, 38 insertions(+), 72 deletions(-) diff --git a/homeassistant/components/esphome/__init__.py b/homeassistant/components/esphome/__init__.py index 04acba7c691..9034818a934 100644 --- a/homeassistant/components/esphome/__init__.py +++ b/homeassistant/components/esphome/__init__.py @@ -6,6 +6,7 @@ from typing import Any, Dict, List, Optional, TYPE_CHECKING, Callable import attr import voluptuous as vol +from homeassistant import const from homeassistant.config_entries import ConfigEntry from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PORT, \ EVENT_HOMEASSISTANT_STOP @@ -30,7 +31,7 @@ if TYPE_CHECKING: ServiceCall DOMAIN = 'esphome' -REQUIREMENTS = ['aioesphomeapi==1.3.0'] +REQUIREMENTS = ['aioesphomeapi==1.4.0'] DISPATCHER_UPDATE_ENTITY = 'esphome_{entry_id}_update_{component_key}_{key}' @@ -161,8 +162,8 @@ async def async_setup_entry(hass: HomeAssistantType, port = entry.data[CONF_PORT] password = entry.data[CONF_PASSWORD] - cli = APIClient(hass.loop, host, port, password) - await cli.start() + cli = APIClient(hass.loop, host, port, password, + client_info="Home Assistant {}".format(const.__version__)) # Store client in per-config-entry hass.data store = Store(hass, STORAGE_VERSION, STORAGE_KEY.format(entry.entry_id), @@ -181,8 +182,6 @@ async def async_setup_entry(hass: HomeAssistantType, hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, on_stop) ) - try_connect = await _setup_auto_reconnect_logic(hass, cli, entry, host) - @callback def async_on_state(state: 'EntityState') -> None: """Send dispatcher updates when a new state is received.""" @@ -247,7 +246,8 @@ async def async_setup_entry(hass: HomeAssistantType, # Re-connection logic will trigger after this await cli.disconnect() - cli.on_login = on_login + try_connect = await _setup_auto_reconnect_logic(hass, cli, entry, host, + on_login) # This is a bit of a hack: We schedule complete_setup into the # event loop and return immediately (return True) @@ -291,7 +291,7 @@ async def async_setup_entry(hass: HomeAssistantType, async def _setup_auto_reconnect_logic(hass: HomeAssistantType, cli: 'APIClient', - entry: ConfigEntry, host: str): + entry: ConfigEntry, host: str, on_login): """Set up the re-connect logic for the API client.""" from aioesphomeapi import APIConnectionError @@ -308,33 +308,40 @@ async def _setup_auto_reconnect_logic(hass: HomeAssistantType, data.available = False data.async_update_device_state(hass) - if tries != 0: - # If not first re-try, wait and print message - wait_time = min(2**tries, 300) - _LOGGER.info("Trying to reconnect in %s seconds", wait_time) - await asyncio.sleep(wait_time) - - if is_disconnect and tries == 0: + if is_disconnect: # This can happen often depending on WiFi signal strength. # So therefore all these connection warnings are logged # as infos. The "unavailable" logic will still trigger so the # user knows if the device is not connected. - _LOGGER.info("Disconnected from API") + _LOGGER.info("Disconnected from ESPHome API for %s", host) + + if tries != 0: + # If not first re-try, wait and print message + # Cap wait time at 1 minute. This is because while working on the + # device (e.g. soldering stuff), users don't want to have to wait + # a long time for their device to show up in HA again (this was + # mentioned a lot in early feedback) + # + # In the future another API will be set up so that the ESP can + # notify HA of connectivity directly, but for new we'll use a + # really short reconnect interval. + wait_time = int(round(min(1.8**tries, 60.0))) + _LOGGER.info("Trying to reconnect in %s seconds", wait_time) + await asyncio.sleep(wait_time) try: - await cli.connect() - await cli.login() + await cli.connect(on_stop=try_connect, login=True) except APIConnectionError as error: - _LOGGER.info("Can't connect to esphome API for '%s' (%s)", + _LOGGER.info("Can't connect to ESPHome API for %s: %s", host, error) # Schedule re-connect in event loop in order not to delay HA # startup. First connect is scheduled in tracked tasks. - data.reconnect_task = \ - hass.loop.create_task(try_connect(tries + 1, is_disconnect)) + data.reconnect_task = hass.loop.create_task( + try_connect(tries + 1, is_disconnect=False)) else: _LOGGER.info("Successfully connected to %s", host) + hass.async_create_task(on_login()) - cli.on_disconnect = try_connect return try_connect @@ -368,7 +375,7 @@ async def _cleanup_instance(hass: HomeAssistantType, disconnect_cb() for cleanup_callback in data.cleanup_callbacks: cleanup_callback() - await data.client.stop() + await data.client.disconnect() async def async_unload_entry(hass: HomeAssistantType, diff --git a/homeassistant/components/esphome/config_flow.py b/homeassistant/components/esphome/config_flow.py index 24edaf152e6..1f71d8d66b5 100644 --- a/homeassistant/components/esphome/config_flow.py +++ b/homeassistant/components/esphome/config_flow.py @@ -110,7 +110,6 @@ class EsphomeFlowHandler(config_entries.ConfigFlow): cli = APIClient(self.hass.loop, self._host, self._port, '') try: - await cli.start() await cli.connect() device_info = await cli.device_info() except APIConnectionError as err: @@ -118,7 +117,7 @@ class EsphomeFlowHandler(config_entries.ConfigFlow): return 'resolve_error', None return 'connection_error', None finally: - await cli.stop(force=True) + await cli.disconnect(force=True) return None, device_info @@ -129,17 +128,9 @@ class EsphomeFlowHandler(config_entries.ConfigFlow): cli = APIClient(self.hass.loop, self._host, self._port, self._password) try: - await cli.start() - await cli.connect() - except APIConnectionError: - await cli.stop(force=True) - return 'connection_error' - - try: - await cli.login() + await cli.connect(login=True) except APIConnectionError: + await cli.disconnect(force=True) return 'invalid_password' - finally: - await cli.stop(force=True) return None diff --git a/requirements_all.txt b/requirements_all.txt index 1117f70f039..aab6791bfed 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -96,7 +96,7 @@ aioautomatic==0.6.5 aiodns==1.1.1 # homeassistant.components.esphome -aioesphomeapi==1.3.0 +aioesphomeapi==1.4.0 # homeassistant.components.freebox aiofreepybox==0.0.6 diff --git a/tests/components/esphome/test_config_flow.py b/tests/components/esphome/test_config_flow.py index 476b3e3c5c1..1291aa53123 100644 --- a/tests/components/esphome/test_config_flow.py +++ b/tests/components/esphome/test_config_flow.py @@ -31,10 +31,8 @@ def mock_client(): return mock_client mock_client.side_effect = mock_constructor - mock_client.start.return_value = mock_coro() mock_client.connect.return_value = mock_coro() - mock_client.stop.return_value = mock_coro() - mock_client.login.return_value = mock_coro() + mock_client.disconnect.return_value = mock_coro() yield mock_client @@ -69,10 +67,9 @@ async def test_user_connection_works(hass, mock_client): 'password': '' } assert result['title'] == 'test' - assert len(mock_client.start.mock_calls) == 1 assert len(mock_client.connect.mock_calls) == 1 assert len(mock_client.device_info.mock_calls) == 1 - assert len(mock_client.stop.mock_calls) == 1 + assert len(mock_client.disconnect.mock_calls) == 1 assert mock_client.host == '127.0.0.1' assert mock_client.port == 80 assert mock_client.password == '' @@ -106,10 +103,9 @@ async def test_user_resolve_error(hass, mock_api_connection_error, assert result['errors'] == { 'base': 'resolve_error' } - assert len(mock_client.start.mock_calls) == 1 assert len(mock_client.connect.mock_calls) == 1 assert len(mock_client.device_info.mock_calls) == 1 - assert len(mock_client.stop.mock_calls) == 1 + assert len(mock_client.disconnect.mock_calls) == 1 async def test_user_connection_error(hass, mock_api_connection_error, @@ -131,10 +127,9 @@ async def test_user_connection_error(hass, mock_api_connection_error, assert result['errors'] == { 'base': 'connection_error' } - assert len(mock_client.start.mock_calls) == 1 assert len(mock_client.connect.mock_calls) == 1 assert len(mock_client.device_info.mock_calls) == 1 - assert len(mock_client.stop.mock_calls) == 1 + assert len(mock_client.disconnect.mock_calls) == 1 async def test_user_with_password(hass, mock_client): @@ -176,38 +171,11 @@ async def test_user_invalid_password(hass, mock_api_connection_error, mock_client.device_info.return_value = mock_coro( MockDeviceInfo(True, "test")) - mock_client.login.side_effect = mock_api_connection_error await flow.async_step_user(user_input={ 'host': '127.0.0.1', 'port': 6053, }) - result = await flow.async_step_authenticate(user_input={ - 'password': 'invalid' - }) - - assert result['type'] == 'form' - assert result['step_id'] == 'authenticate' - assert result['errors'] == { - 'base': 'invalid_password' - } - - -async def test_user_login_connection_error(hass, mock_api_connection_error, - mock_client): - """Test user step with connection error during login phase.""" - flow = config_flow.EsphomeFlowHandler() - flow.hass = hass - await flow.async_step_user(user_input=None) - - mock_client.device_info.return_value = mock_coro( - MockDeviceInfo(True, "test")) - - await flow.async_step_user(user_input={ - 'host': '127.0.0.1', - 'port': 6053, - }) - mock_client.connect.side_effect = mock_api_connection_error result = await flow.async_step_authenticate(user_input={ 'password': 'invalid' @@ -216,7 +184,7 @@ async def test_user_login_connection_error(hass, mock_api_connection_error, assert result['type'] == 'form' assert result['step_id'] == 'authenticate' assert result['errors'] == { - 'base': 'connection_error' + 'base': 'invalid_password' } From 0d49b1962488beccca7614ce8f632fd5a7250d0b Mon Sep 17 00:00:00 2001 From: cdce8p <30130371+cdce8p@users.noreply.github.com> Date: Fri, 4 Jan 2019 22:37:42 +0100 Subject: [PATCH 08/24] Update HAP-python to 2.4.2 (#19776) * Bugfixes for connection issues --- homeassistant/components/homekit/__init__.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/homekit/__init__.py b/homeassistant/components/homekit/__init__.py index c8aea5f8fb3..c34b527252f 100644 --- a/homeassistant/components/homekit/__init__.py +++ b/homeassistant/components/homekit/__init__.py @@ -30,7 +30,7 @@ from .const import ( from .util import ( show_setup_message, validate_entity_config, validate_media_player_features) -REQUIREMENTS = ['HAP-python==2.4.1'] +REQUIREMENTS = ['HAP-python==2.4.2'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index aab6791bfed..2d2ea082980 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -33,7 +33,7 @@ Adafruit-SHT31==1.0.2 # Adafruit_BBIO==1.0.0 # homeassistant.components.homekit -HAP-python==2.4.1 +HAP-python==2.4.2 # homeassistant.components.notify.mastodon Mastodon.py==1.3.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 1982d1cc136..98e8cd54b7a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -19,7 +19,7 @@ requests_mock==1.5.2 # homeassistant.components.homekit -HAP-python==2.4.1 +HAP-python==2.4.2 # homeassistant.components.sensor.rmvtransport PyRMVtransport==0.1.3 From 312ad7057dde267aadbd6d9a2af61bb783939b4d Mon Sep 17 00:00:00 2001 From: cdheiser <10488026+cdheiser@users.noreply.github.com> Date: Sun, 6 Jan 2019 09:25:09 -0800 Subject: [PATCH 09/24] Fix a bug in Lutron RadioRA2 Scene support (#19819) --- homeassistant/components/lutron.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/lutron.py b/homeassistant/components/lutron.py index 48ad95da415..7f1e1d25ae1 100644 --- a/homeassistant/components/lutron.py +++ b/homeassistant/components/lutron.py @@ -68,7 +68,7 @@ def setup(hass, base_config): button.name != 'Unknown Button' and button.button_type in ('SingleAction', 'Toggle')): hass.data[LUTRON_DEVICES]['scene'].append( - (area.name, button, led)) + (area.name, keypad.name, button, led)) for component in ('light', 'cover', 'switch', 'scene'): discovery.load_platform(hass, component, DOMAIN, None, base_config) From 68e33fdbf50036152d885267654a93f213bee19f Mon Sep 17 00:00:00 2001 From: Fredrik Erlandsson Date: Mon, 7 Jan 2019 13:04:53 +0100 Subject: [PATCH 10/24] fixes #19814, Daikin config setting (#19823) --- homeassistant/components/daikin/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/daikin/__init__.py b/homeassistant/components/daikin/__init__.py index 86ad6c0a160..f16d6a87d55 100644 --- a/homeassistant/components/daikin/__init__.py +++ b/homeassistant/components/daikin/__init__.py @@ -12,7 +12,7 @@ from socket import timeout import async_timeout import voluptuous as vol -from homeassistant.config_entries import ConfigEntry +from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry from homeassistant.const import CONF_HOSTS import homeassistant.helpers.config_validation as cv from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC @@ -51,12 +51,12 @@ async def async_setup(hass, config): if not hosts: hass.async_create_task( hass.config_entries.flow.async_init( - DOMAIN, context={'source': config.SOURCE_IMPORT})) + DOMAIN, context={'source': SOURCE_IMPORT})) for host in hosts: hass.async_create_task( hass.config_entries.flow.async_init( DOMAIN, - context={'source': config.SOURCE_IMPORT}, + context={'source': SOURCE_IMPORT}, data={ KEY_HOST: host, })) From 4ec313cb3b6dcc5194e9c204076807c54c7dbd2d Mon Sep 17 00:00:00 2001 From: Otto Winter Date: Mon, 7 Jan 2019 11:58:10 +0100 Subject: [PATCH 11/24] Bump aioesphomeapi (#19838) --- homeassistant/components/esphome/__init__.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/esphome/__init__.py b/homeassistant/components/esphome/__init__.py index 9034818a934..70d92250564 100644 --- a/homeassistant/components/esphome/__init__.py +++ b/homeassistant/components/esphome/__init__.py @@ -31,7 +31,7 @@ if TYPE_CHECKING: ServiceCall DOMAIN = 'esphome' -REQUIREMENTS = ['aioesphomeapi==1.4.0'] +REQUIREMENTS = ['aioesphomeapi==1.4.1'] DISPATCHER_UPDATE_ENTITY = 'esphome_{entry_id}_update_{component_key}_{key}' diff --git a/requirements_all.txt b/requirements_all.txt index 2d2ea082980..94459516b10 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -96,7 +96,7 @@ aioautomatic==0.6.5 aiodns==1.1.1 # homeassistant.components.esphome -aioesphomeapi==1.4.0 +aioesphomeapi==1.4.1 # homeassistant.components.freebox aiofreepybox==0.0.6 From f0191313525ed89050a22fcbdf56d14377798aa5 Mon Sep 17 00:00:00 2001 From: Alistair Galbraith Date: Tue, 8 Jan 2019 20:13:47 -0800 Subject: [PATCH 12/24] Resolves #17196, Resolves #18739 - Hue Beyond light fixture errors (#19874) * Resolves #17196, Resolves #18739 - Hue Beyond light fixtures being incorrectly recognized * Removed long code lines that were failing code review * Removed trailing whitespace --- homeassistant/components/light/hue.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/light/hue.py b/homeassistant/components/light/hue.py index 686fc01caf9..28a2d79de13 100644 --- a/homeassistant/components/light/hue.py +++ b/homeassistant/components/light/hue.py @@ -298,7 +298,8 @@ class HueLight(Light): @property def device_info(self): """Return the device info.""" - if self.light.type in ('LightGroup', 'Room'): + if self.light.type in ('LightGroup', 'Room', + 'Luminaire', 'LightSource'): return None return { From ed41421a3de66eb540cb8ba30ab8c06ad481dfd3 Mon Sep 17 00:00:00 2001 From: Steven Looman Date: Tue, 8 Jan 2019 22:05:36 +0100 Subject: [PATCH 13/24] Fix error when trying to log used UPnP device, if multiple found (#19875) --- homeassistant/components/upnp/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/upnp/__init__.py b/homeassistant/components/upnp/__init__.py index e360d4b18d3..d44cf2a8683 100644 --- a/homeassistant/components/upnp/__init__.py +++ b/homeassistant/components/upnp/__init__.py @@ -102,8 +102,10 @@ async def async_discover_and_construct(hass, udn=None) -> Device: # get the first/any discovery_info = discovery_infos[0] if len(discovery_infos) > 1: + device_name = discovery_info.get( + 'usn', discovery_info.get('ssdp_description', '')) _LOGGER.info('Detected multiple UPnP/IGD devices, using: %s', - discovery_info['igd_name']) + device_name) ssdp_description = discovery_info['ssdp_description'] return await Device.async_create_device(hass, ssdp_description) From 6b56985e01ac89435d3be100a54b1121a8f0ec96 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Wed, 9 Jan 2019 05:14:27 +0100 Subject: [PATCH 14/24] Update OZW to 0.1.2 (#19878) * Update ozw 0.1.2 * Update requirements_all.txt --- homeassistant/components/zwave/__init__.py | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/zwave/__init__.py b/homeassistant/components/zwave/__init__.py index 6d96192f075..7860b545be2 100644 --- a/homeassistant/components/zwave/__init__.py +++ b/homeassistant/components/zwave/__init__.py @@ -42,7 +42,7 @@ from .discovery_schemas import DISCOVERY_SCHEMAS from .util import (check_node_schema, check_value_schema, node_name, check_has_unique_id, is_node_parsed) -REQUIREMENTS = ['pydispatcher==2.0.5', 'homeassistant-pyozw==0.1.1'] +REQUIREMENTS = ['pydispatcher==2.0.5', 'homeassistant-pyozw==0.1.2'] _LOGGER = logging.getLogger(__name__) diff --git a/requirements_all.txt b/requirements_all.txt index 94459516b10..566042a28a5 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -514,7 +514,7 @@ holidays==0.9.8 home-assistant-frontend==20181219.0 # homeassistant.components.zwave -homeassistant-pyozw==0.1.1 +homeassistant-pyozw==0.1.2 # homeassistant.components.homekit_controller # homekit==0.12.0 From 8a3d43745db03e0144a13891ffd3c1e86fae2672 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 8 Jan 2019 20:23:59 -0800 Subject: [PATCH 15/24] Bumped version to 0.85.0b1 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index e8347eddc5a..2d2a7ff633e 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 85 -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 f17d6c0593f13251d8fe893a4b7bc906b73ffe72 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 9 Jan 2019 15:12:29 -0800 Subject: [PATCH 16/24] Updated frontend to 20190109.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 475ce26bc43..478ff5549d9 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -24,7 +24,7 @@ from homeassistant.core import callback from homeassistant.helpers.translation import async_get_translations from homeassistant.loader import bind_hass -REQUIREMENTS = ['home-assistant-frontend==20181219.0'] +REQUIREMENTS = ['home-assistant-frontend==20190109.0'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log', diff --git a/requirements_all.txt b/requirements_all.txt index 566042a28a5..15725711619 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -511,7 +511,7 @@ hole==0.3.0 holidays==0.9.8 # homeassistant.components.frontend -home-assistant-frontend==20181219.0 +home-assistant-frontend==20190109.0 # homeassistant.components.zwave homeassistant-pyozw==0.1.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 98e8cd54b7a..ebee97e43c2 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -104,7 +104,7 @@ hdate==0.7.5 holidays==0.9.8 # homeassistant.components.frontend -home-assistant-frontend==20181219.0 +home-assistant-frontend==20190109.0 # homeassistant.components.homematicip_cloud homematicip==0.9.8 From 8cf595dd3e2cfd3fd16964590a92bee7b9fa2862 Mon Sep 17 00:00:00 2001 From: Florian Ludwig Date: Wed, 9 Jan 2019 05:45:24 +0100 Subject: [PATCH 17/24] assign user to websocket connection when using legacy_api_password (#19797) --- homeassistant/components/websocket_api/auth.py | 4 +++- tests/components/websocket_api/test_auth.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/websocket_api/auth.py b/homeassistant/components/websocket_api/auth.py index 434775c9b9b..f175327bf28 100644 --- a/homeassistant/components/websocket_api/auth.py +++ b/homeassistant/components/websocket_api/auth.py @@ -6,6 +6,7 @@ from homeassistant.const import __version__ from homeassistant.components.http.auth import validate_password from homeassistant.components.http.ban import process_wrong_login, \ process_success_login +from homeassistant.auth.providers import legacy_api_password from .connection import ActiveConnection from .error import Disconnect @@ -81,7 +82,8 @@ class AuthPhase: elif self._hass.auth.support_legacy and 'api_password' in msg: self._logger.debug("Received api_password") if validate_password(self._request, msg['api_password']): - return await self._async_finish_auth(None, None) + user = await legacy_api_password.async_get_user(self._hass) + return await self._async_finish_auth(user, None) self._send_message(auth_invalid_message( 'Invalid access token or password')) diff --git a/tests/components/websocket_api/test_auth.py b/tests/components/websocket_api/test_auth.py index 4c0014e4783..9d2d2ce251e 100644 --- a/tests/components/websocket_api/test_auth.py +++ b/tests/components/websocket_api/test_auth.py @@ -132,7 +132,8 @@ async def test_auth_active_with_password_not_allow(hass, aiohttp_client): assert auth_msg['type'] == TYPE_AUTH_INVALID -async def test_auth_legacy_support_with_password(hass, aiohttp_client): +async def test_auth_legacy_support_with_password(hass, aiohttp_client, + legacy_auth): """Test authenticating with a token.""" assert await async_setup_component(hass, 'websocket_api', { 'http': { From 7641658e38eebe36ebe47487ccd23a96633af8d5 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Wed, 9 Jan 2019 15:13:29 -0800 Subject: [PATCH 18/24] Bumped version to 0.85.0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 2d2a7ff633e..eccbb262ec5 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 85 -PATCH_VERSION = '0b1' +PATCH_VERSION = '0' __short_version__ = '{}.{}'.format(MAJOR_VERSION, MINOR_VERSION) __version__ = '{}.{}'.format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 5, 3) From fe92cf1e72baab9952a1a65b38550b3fdd7647bc Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 11 Jan 2019 11:48:32 -0800 Subject: [PATCH 19/24] Updated frontend to 20190109.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 478ff5549d9..026311f1397 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -24,7 +24,7 @@ from homeassistant.core import callback from homeassistant.helpers.translation import async_get_translations from homeassistant.loader import bind_hass -REQUIREMENTS = ['home-assistant-frontend==20190109.0'] +REQUIREMENTS = ['home-assistant-frontend==20190109.1'] DOMAIN = 'frontend' DEPENDENCIES = ['api', 'websocket_api', 'http', 'system_log', diff --git a/requirements_all.txt b/requirements_all.txt index 15725711619..58fbb1bd5be 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -511,7 +511,7 @@ hole==0.3.0 holidays==0.9.8 # homeassistant.components.frontend -home-assistant-frontend==20190109.0 +home-assistant-frontend==20190109.1 # homeassistant.components.zwave homeassistant-pyozw==0.1.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index ebee97e43c2..7595cf2f8c7 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -104,7 +104,7 @@ hdate==0.7.5 holidays==0.9.8 # homeassistant.components.frontend -home-assistant-frontend==20190109.0 +home-assistant-frontend==20190109.1 # homeassistant.components.homematicip_cloud homematicip==0.9.8 From 7a83b86ebd5fc0d110319d1ea613718387083aac Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Fri, 4 Jan 2019 14:00:26 -0500 Subject: [PATCH 20/24] check config instead of config_entry for quirks flag (#19730) --- homeassistant/components/zha/__init__.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/zha/__init__.py b/homeassistant/components/zha/__init__.py index 5ad06565b00..3fe8980c451 100644 --- a/homeassistant/components/zha/__init__.py +++ b/homeassistant/components/zha/__init__.py @@ -95,8 +95,7 @@ async def async_setup(hass, config): context={'source': config_entries.SOURCE_IMPORT}, data={ CONF_USB_PATH: conf[CONF_USB_PATH], - CONF_RADIO_TYPE: conf.get(CONF_RADIO_TYPE).value, - ENABLE_QUIRKS: conf[ENABLE_QUIRKS] + CONF_RADIO_TYPE: conf.get(CONF_RADIO_TYPE).value } )) return True @@ -107,17 +106,17 @@ async def async_setup_entry(hass, config_entry): Will automatically load components to support devices found on the network. """ - if config_entry.data.get(ENABLE_QUIRKS): - # needs to be done here so that the ZHA module is finished loading - # before zhaquirks is imported - # pylint: disable=W0611, W0612 - import zhaquirks # noqa - hass.data[DATA_ZHA] = hass.data.get(DATA_ZHA, {}) hass.data[DATA_ZHA][DATA_ZHA_DISPATCHERS] = [] config = hass.data[DATA_ZHA].get(DATA_ZHA_CONFIG, {}) + if config.get(ENABLE_QUIRKS, True): + # needs to be done here so that the ZHA module is finished loading + # before zhaquirks is imported + # pylint: disable=W0611, W0612 + import zhaquirks # noqa + usb_path = config_entry.data.get(CONF_USB_PATH) baudrate = config.get(CONF_BAUDRATE, DEFAULT_BAUDRATE) radio_type = config_entry.data.get(CONF_RADIO_TYPE) From ded37d971d032ef384c2baef0ad86795b490873a Mon Sep 17 00:00:00 2001 From: Alexei Chetroi Date: Thu, 10 Jan 2019 14:43:24 -0500 Subject: [PATCH 21/24] Don't map LevelControl to light for single cluster devices. (#19929) --- homeassistant/components/zha/const.py | 1 - 1 file changed, 1 deletion(-) diff --git a/homeassistant/components/zha/const.py b/homeassistant/components/zha/const.py index 3e7f9f89f91..5b650c95cc4 100644 --- a/homeassistant/components/zha/const.py +++ b/homeassistant/components/zha/const.py @@ -129,7 +129,6 @@ def populate_data(): SINGLE_INPUT_CLUSTER_DEVICE_CLASS.update({ zcl.clusters.general.OnOff: 'switch', - zcl.clusters.general.LevelControl: 'light', zcl.clusters.measurement.RelativeHumidity: 'sensor', zcl.clusters.measurement.TemperatureMeasurement: 'sensor', zcl.clusters.measurement.PressureMeasurement: 'sensor', From 0979ce476ab039cb1cc6b68e8bc313c94ed3a39a Mon Sep 17 00:00:00 2001 From: Daniel Shokouhi Date: Thu, 10 Jan 2019 13:56:10 -0800 Subject: [PATCH 22/24] Fix botvac connected alert retrieval --- homeassistant/components/vacuum/neato.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/vacuum/neato.py b/homeassistant/components/vacuum/neato.py index 0c97f99df99..37d4783cdbd 100644 --- a/homeassistant/components/vacuum/neato.py +++ b/homeassistant/components/vacuum/neato.py @@ -82,7 +82,10 @@ class NeatoConnectedVacuum(StateVacuumDevice): self._available = False return _LOGGER.debug('self._state=%s', self._state) - robot_alert = ALERTS.get(self._state['alert']) + if 'alert' in self._state: + robot_alert = ALERTS.get(self._state['alert']) + else: + robot_alert = None if self._state['state'] == 1: if self._state['details']['isCharging']: self._clean_state = STATE_DOCKED From 990e7c57f28e19a391759b00f2820acbece667ad Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 11 Jan 2019 11:52:07 -0800 Subject: [PATCH 23/24] Fix warning (#19946) * Fix warning * Update service.py --- homeassistant/helpers/service.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/homeassistant/helpers/service.py b/homeassistant/helpers/service.py index 66488fbec3d..2b7638b55ee 100644 --- a/homeassistant/helpers/service.py +++ b/homeassistant/helpers/service.py @@ -204,8 +204,9 @@ async def entity_service_call(hass, platforms, func, call): if ATTR_ENTITY_ID in call.data: target_all_entities = call.data[ATTR_ENTITY_ID] == ENTITY_MATCH_ALL else: - _LOGGER.warning('Not passing an entity ID to a service to target all ' - 'entities is deprecated. Use instead: entity_id: "*"') + _LOGGER.warning( + 'Not passing an entity ID to a service to target all entities is ' + 'deprecated. Use instead: entity_id: "%s"', ENTITY_MATCH_ALL) target_all_entities = True if not target_all_entities: From 963ffa1ccc5ad453d0c1ebb066da36495b46f173 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 11 Jan 2019 12:06:12 -0800 Subject: [PATCH 24/24] Bumped version to 0.85.1 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index eccbb262ec5..a9ba2211d07 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 85 -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)