From 47e76fcd5e9fe2651f7346b4d39f8f0044aa8574 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 1 Sep 2019 21:42:57 -0700 Subject: [PATCH 01/16] Expose current direction properly on state machine (#26298) * Expose current direction properly on state machine * Fix template fan --- homeassistant/components/demo/fan.py | 8 ++++---- homeassistant/components/fan/__init__.py | 2 +- homeassistant/components/template/fan.py | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/demo/fan.py b/homeassistant/components/demo/fan.py index cdeed5dbfec..ab8a6f3fae9 100644 --- a/homeassistant/components/demo/fan.py +++ b/homeassistant/components/demo/fan.py @@ -34,13 +34,13 @@ class DemoFan(FanEntity): self._supported_features = supported_features self._speed = STATE_OFF self.oscillating = None - self.direction = None + self._direction = None self._name = name if supported_features & SUPPORT_OSCILLATE: self.oscillating = False if supported_features & SUPPORT_DIRECTION: - self.direction = "forward" + self._direction = "forward" @property def name(self) -> str: @@ -80,7 +80,7 @@ class DemoFan(FanEntity): def set_direction(self, direction: str) -> None: """Set the direction of the fan.""" - self.direction = direction + self._direction = direction self.schedule_update_ha_state() def oscillate(self, oscillating: bool) -> None: @@ -91,7 +91,7 @@ class DemoFan(FanEntity): @property def current_direction(self) -> str: """Fan direction.""" - return self.direction + return self._direction @property def supported_features(self) -> int: diff --git a/homeassistant/components/fan/__init__.py b/homeassistant/components/fan/__init__.py index f5edfe5bb59..50d698f7336 100644 --- a/homeassistant/components/fan/__init__.py +++ b/homeassistant/components/fan/__init__.py @@ -54,7 +54,7 @@ PROP_TO_ATTR = { "speed": ATTR_SPEED, "speed_list": ATTR_SPEED_LIST, "oscillating": ATTR_OSCILLATING, - "direction": ATTR_DIRECTION, + "current_direction": ATTR_DIRECTION, } # type: dict FAN_SET_SPEED_SCHEMA = ENTITY_SERVICE_SCHEMA.extend( diff --git a/homeassistant/components/template/fan.py b/homeassistant/components/template/fan.py index c3d5a4d878f..7fd8c4d9b3c 100644 --- a/homeassistant/components/template/fan.py +++ b/homeassistant/components/template/fan.py @@ -243,7 +243,7 @@ class TemplateFan(FanEntity): return self._oscillating @property - def direction(self): + def current_direction(self): """Return the oscillation state.""" return self._direction From 732855e86c88c105151bd88b570c2bf8cd896530 Mon Sep 17 00:00:00 2001 From: Paul Annekov Date: Sat, 31 Aug 2019 03:30:18 +0300 Subject: [PATCH 02/16] bump tuyaha 0.0.4 (#26303) --- homeassistant/components/tuya/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/tuya/manifest.json b/homeassistant/components/tuya/manifest.json index 8d47d8a0173..9c83056f6ac 100644 --- a/homeassistant/components/tuya/manifest.json +++ b/homeassistant/components/tuya/manifest.json @@ -3,7 +3,7 @@ "name": "Tuya", "documentation": "https://www.home-assistant.io/components/tuya", "requirements": [ - "tuyaha==0.0.3" + "tuyaha==0.0.4" ], "dependencies": [], "codeowners": [] diff --git a/requirements_all.txt b/requirements_all.txt index e749340a8cb..2bf7e6a841c 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1857,7 +1857,7 @@ tplink==0.2.1 transmissionrpc==0.11 # homeassistant.components.tuya -tuyaha==0.0.3 +tuyaha==0.0.4 # homeassistant.components.twentemilieu twentemilieu==0.1.0 From 795d5405db4bfa50a47f3d9b72dc83683831d3be Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 30 Aug 2019 18:34:40 -0700 Subject: [PATCH 03/16] Fix Alexa Report State (#26305) * Fix Alexa Report State * Forgot to save a file --- homeassistant/components/alexa/auth.py | 5 +++ homeassistant/components/alexa/config.py | 8 ++++ .../components/alexa/smart_home_http.py | 5 +++ .../components/alexa/state_report.py | 27 +++++++++---- .../components/cloud/alexa_config.py | 8 +++- tests/components/cloud/test_alexa_config.py | 38 ++++++++++++++++++- 6 files changed, 81 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/alexa/auth.py b/homeassistant/components/alexa/auth.py index d4633d938ed..9f87a6d954e 100644 --- a/homeassistant/components/alexa/auth.py +++ b/homeassistant/components/alexa/auth.py @@ -56,6 +56,11 @@ class Auth: return await self._async_request_new_token(lwa_params) + @callback + def async_invalidate_access_token(self): + """Invalidate access token.""" + self._prefs[STORAGE_ACCESS_TOKEN] = None + async def async_get_access_token(self): """Perform access token or token refresh request.""" async with self._get_token_lock: diff --git a/homeassistant/components/alexa/config.py b/homeassistant/components/alexa/config.py index a22ebbcd30d..f98337d71c5 100644 --- a/homeassistant/components/alexa/config.py +++ b/homeassistant/components/alexa/config.py @@ -1,4 +1,6 @@ """Config helpers for Alexa.""" +from homeassistant.core import callback + from .state_report import async_enable_proactive_mode @@ -55,11 +57,17 @@ class AbstractConfig: unsub_func() self._unsub_proactive_report = None + @callback def should_expose(self, entity_id): """If an entity should be exposed.""" # pylint: disable=no-self-use return False + @callback + def async_invalidate_access_token(self): + """Invalidate access token.""" + raise NotImplementedError + async def async_get_access_token(self): """Get an access token.""" raise NotImplementedError diff --git a/homeassistant/components/alexa/smart_home_http.py b/homeassistant/components/alexa/smart_home_http.py index 7fdd4e3000a..ada00e8a326 100644 --- a/homeassistant/components/alexa/smart_home_http.py +++ b/homeassistant/components/alexa/smart_home_http.py @@ -57,6 +57,11 @@ class AlexaConfig(AbstractConfig): """If an entity should be exposed.""" return self._config[CONF_FILTER](entity_id) + @core.callback + def async_invalidate_access_token(self): + """Invalidate access token.""" + self._auth.async_invalidate_access_token() + async def async_get_access_token(self): """Get an access token.""" return await self._auth.async_get_access_token() diff --git a/homeassistant/components/alexa/state_report.py b/homeassistant/components/alexa/state_report.py index 7e842889977..1e22d5fc09f 100644 --- a/homeassistant/components/alexa/state_report.py +++ b/homeassistant/components/alexa/state_report.py @@ -51,7 +51,9 @@ async def async_enable_proactive_mode(hass, smart_home_config): ) -async def async_send_changereport_message(hass, config, alexa_entity): +async def async_send_changereport_message( + hass, config, alexa_entity, *, invalidate_access_token=True +): """Send a ChangeReport message for an Alexa entity. https://developer.amazon.com/docs/smarthome/state-reporting-for-a-smart-home-skill.html#report-state-with-changereport-events @@ -88,21 +90,30 @@ async def async_send_changereport_message(hass, config, alexa_entity): except (asyncio.TimeoutError, aiohttp.ClientError): _LOGGER.error("Timeout sending report to Alexa.") - return None + return response_text = await response.text() _LOGGER.debug("Sent: %s", json.dumps(message_serialized)) _LOGGER.debug("Received (%s): %s", response.status, response_text) - if response.status != 202: - response_json = json.loads(response_text) - _LOGGER.error( - "Error when sending ChangeReport to Alexa: %s: %s", - response_json["payload"]["code"], - response_json["payload"]["description"], + if response.status == 202 and not invalidate_access_token: + return + + response_json = json.loads(response_text) + + if response_json["payload"]["code"] == "INVALID_ACCESS_TOKEN_EXCEPTION": + config.async_invalidate_access_token() + return await async_send_changereport_message( + hass, config, alexa_entity, invalidate_access_token=False ) + _LOGGER.error( + "Error when sending ChangeReport to Alexa: %s: %s", + response_json["payload"]["code"], + response_json["payload"]["description"], + ) + async def async_send_add_or_update_message(hass, config, entity_ids): """Send an AddOrUpdateReport message for entities. diff --git a/homeassistant/components/cloud/alexa_config.py b/homeassistant/components/cloud/alexa_config.py index d31bcfdfc40..a1432f196bf 100644 --- a/homeassistant/components/cloud/alexa_config.py +++ b/homeassistant/components/cloud/alexa_config.py @@ -7,6 +7,7 @@ import aiohttp import async_timeout from hass_nabucasa import cloud_api +from homeassistant.core import callback from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES from homeassistant.helpers import entity_registry from homeassistant.helpers.event import async_call_later @@ -95,9 +96,14 @@ class AlexaConfig(alexa_config.AbstractConfig): entity_config = entity_configs.get(entity_id, {}) return entity_config.get(PREF_SHOULD_EXPOSE, DEFAULT_SHOULD_EXPOSE) + @callback + def async_invalidate_access_token(self): + """Invalidate access token.""" + self._token_valid = None + async def async_get_access_token(self): """Get an access token.""" - if self._token_valid is not None and self._token_valid < utcnow(): + if self._token_valid is not None and self._token_valid > utcnow(): return self._token resp = await cloud_api.async_alexa_access_token(self._cloud) diff --git a/tests/components/cloud/test_alexa_config.py b/tests/components/cloud/test_alexa_config.py index 22d8c64c3b0..c8e84016a28 100644 --- a/tests/components/cloud/test_alexa_config.py +++ b/tests/components/cloud/test_alexa_config.py @@ -1,6 +1,6 @@ """Test Alexa config.""" import contextlib -from unittest.mock import patch +from unittest.mock import patch, Mock from homeassistant.components.cloud import ALEXA_SCHEMA, alexa_config from homeassistant.util.dt import utcnow @@ -43,6 +43,42 @@ async def test_alexa_config_report_state(hass, cloud_prefs): assert conf.is_reporting_states is False +async def test_alexa_config_invalidate_token(hass, cloud_prefs, aioclient_mock): + """Test Alexa config should expose using prefs.""" + aioclient_mock.post( + "http://example/alexa_token", + json={ + "access_token": "mock-token", + "event_endpoint": "http://example.com/alexa_endpoint", + "expires_in": 30, + }, + ) + conf = alexa_config.AlexaConfig( + hass, + ALEXA_SCHEMA({}), + cloud_prefs, + Mock( + alexa_access_token_url="http://example/alexa_token", + run_executor=Mock(side_effect=mock_coro), + websession=hass.helpers.aiohttp_client.async_get_clientsession(), + ), + ) + + token = await conf.async_get_access_token() + assert token == "mock-token" + assert len(aioclient_mock.mock_calls) == 1 + + token = await conf.async_get_access_token() + assert token == "mock-token" + assert len(aioclient_mock.mock_calls) == 1 + assert conf._token_valid is not None + conf.async_invalidate_access_token() + assert conf._token_valid is None + token = await conf.async_get_access_token() + assert token == "mock-token" + assert len(aioclient_mock.mock_calls) == 2 + + @contextlib.contextmanager def patch_sync_helper(): """Patch sync helper. From 309d401e476fe0171085cb9561e24b498d02cbe9 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 31 Aug 2019 07:46:26 -0700 Subject: [PATCH 04/16] Fix alexa bad temp sensors (#26307) --- .../components/alexa/capabilities.py | 23 +++++++- tests/components/alexa/__init__.py | 6 +++ tests/components/alexa/test_capabilities.py | 54 ++++++++++++++++++- 3 files changed, 80 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/alexa/capabilities.py b/homeassistant/components/alexa/capabilities.py index dfb97cd9db2..d769f797da1 100644 --- a/homeassistant/components/alexa/capabilities.py +++ b/homeassistant/components/alexa/capabilities.py @@ -11,6 +11,7 @@ from homeassistant.const import ( STATE_ON, STATE_UNAVAILABLE, STATE_UNLOCKED, + STATE_UNKNOWN, ) import homeassistant.components.climate.const as climate from homeassistant.components import light, fan, cover @@ -443,7 +444,17 @@ class AlexaTemperatureSensor(AlexaCapibility): if self.entity.domain == climate.DOMAIN: unit = self.hass.config.units.temperature_unit temp = self.entity.attributes.get(climate.ATTR_CURRENT_TEMPERATURE) - return {"value": float(temp), "scale": API_TEMP_UNITS[unit]} + + if temp in (STATE_UNAVAILABLE, STATE_UNKNOWN): + return None + + try: + temp = float(temp) + except ValueError: + _LOGGER.warning("Invalid temp value %s for %s", temp, self.entity.entity_id) + return None + + return {"value": temp, "scale": API_TEMP_UNITS[unit]} class AlexaContactSensor(AlexaCapibility): @@ -591,4 +602,12 @@ class AlexaThermostatController(AlexaCapibility): if temp is None: return None - return {"value": float(temp), "scale": API_TEMP_UNITS[unit]} + try: + temp = float(temp) + except ValueError: + _LOGGER.warning( + "Invalid temp value %s for %s in %s", temp, name, self.entity.entity_id + ) + return None + + return {"value": temp, "scale": API_TEMP_UNITS[unit]} diff --git a/tests/components/alexa/__init__.py b/tests/components/alexa/__init__.py index f853c4ef848..48406a11aef 100644 --- a/tests/components/alexa/__init__.py +++ b/tests/components/alexa/__init__.py @@ -171,6 +171,12 @@ class ReportedProperties: """Initialize class.""" self.properties = properties + def assert_not_has_property(self, namespace, name): + """Assert a property does not exist.""" + for prop in self.properties: + if prop["namespace"] == namespace and prop["name"] == name: + assert False, "Property %s:%s exists" + def assert_equal(self, namespace, name, value): """Assert a property is equal to a given value.""" for prop in self.properties: diff --git a/tests/components/alexa/test_capabilities.py b/tests/components/alexa/test_capabilities.py index f8ad3f57c42..357e0e3026d 100644 --- a/tests/components/alexa/test_capabilities.py +++ b/tests/components/alexa/test_capabilities.py @@ -1,7 +1,15 @@ """Test Alexa capabilities.""" import pytest -from homeassistant.const import STATE_LOCKED, STATE_UNLOCKED, STATE_UNKNOWN +from homeassistant.const import ( + ATTR_UNIT_OF_MEASUREMENT, + TEMP_CELSIUS, + STATE_LOCKED, + STATE_UNLOCKED, + STATE_UNKNOWN, + STATE_UNAVAILABLE, +) +from homeassistant.components import climate from homeassistant.components.alexa import smart_home from tests.common import async_mock_service @@ -368,3 +376,47 @@ async def test_report_cover_percentage_state(hass): properties = await reported_properties(hass, "cover.closed") properties.assert_equal("Alexa.PercentageController", "percentage", 0) + + +async def test_temperature_sensor_sensor(hass): + """Test TemperatureSensor reports sensor temperature correctly.""" + for bad_value in (STATE_UNKNOWN, STATE_UNAVAILABLE, "not-number"): + hass.states.async_set( + "sensor.temp_living_room", + bad_value, + {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS}, + ) + + properties = await reported_properties(hass, "sensor.temp_living_room") + properties.assert_not_has_property("Alexa.TemperatureSensor", "temperature") + + hass.states.async_set( + "sensor.temp_living_room", "34", {ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS} + ) + properties = await reported_properties(hass, "sensor.temp_living_room") + properties.assert_equal( + "Alexa.TemperatureSensor", "temperature", {"value": 34.0, "scale": "CELSIUS"} + ) + + +async def test_temperature_sensor_climate(hass): + """Test TemperatureSensor reports climate temperature correctly.""" + for bad_value in (STATE_UNKNOWN, STATE_UNAVAILABLE, "not-number"): + hass.states.async_set( + "climate.downstairs", + climate.HVAC_MODE_HEAT, + {climate.ATTR_CURRENT_TEMPERATURE: bad_value}, + ) + + properties = await reported_properties(hass, "climate.downstairs") + properties.assert_not_has_property("Alexa.TemperatureSensor", "temperature") + + hass.states.async_set( + "climate.downstairs", + climate.HVAC_MODE_HEAT, + {climate.ATTR_CURRENT_TEMPERATURE: 34}, + ) + properties = await reported_properties(hass, "climate.downstairs") + properties.assert_equal( + "Alexa.TemperatureSensor", "temperature", {"value": 34.0, "scale": "CELSIUS"} + ) From d1e3fbd622ccc0fd94b1e5d5834d166db189d891 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Sat, 31 Aug 2019 15:56:43 +0200 Subject: [PATCH 05/16] deCONZ - Dont update entry if data is equal --- homeassistant/components/deconz/config_flow.py | 10 ++++++---- tests/components/deconz/test_config_flow.py | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/deconz/config_flow.py b/homeassistant/components/deconz/config_flow.py index 650c0285750..306a4fbf839 100644 --- a/homeassistant/components/deconz/config_flow.py +++ b/homeassistant/components/deconz/config_flow.py @@ -157,8 +157,12 @@ class DeconzFlowHandler(config_entries.ConfigFlow): async def _update_entry(self, entry, host): """Update existing entry.""" + if entry.data[CONF_HOST] == host: + return self.async_abort(reason="already_configured") + entry.data[CONF_HOST] = host self.hass.config_entries.async_update_entry(entry) + return self.async_abort(reason="updated_instance") async def async_step_ssdp(self, discovery_info): """Handle a discovered deCONZ bridge.""" @@ -175,8 +179,7 @@ class DeconzFlowHandler(config_entries.ConfigFlow): if uuid in gateways: entry = gateways[uuid].config_entry - await self._update_entry(entry, discovery_info[CONF_HOST]) - return self.async_abort(reason="updated_instance") + return await self._update_entry(entry, discovery_info[CONF_HOST]) bridgeid = discovery_info[ATTR_SERIAL] if any( @@ -224,8 +227,7 @@ class DeconzFlowHandler(config_entries.ConfigFlow): if bridgeid in gateway_entries: entry = gateway_entries[bridgeid] - await self._update_entry(entry, user_input[CONF_HOST]) - return self.async_abort(reason="updated_instance") + return await self._update_entry(entry, user_input[CONF_HOST]) self._hassio_discovery = user_input diff --git a/tests/components/deconz/test_config_flow.py b/tests/components/deconz/test_config_flow.py index 8165c9df080..ea3abead028 100644 --- a/tests/components/deconz/test_config_flow.py +++ b/tests/components/deconz/test_config_flow.py @@ -336,6 +336,24 @@ async def test_hassio_update_instance(hass): assert entry.data[config_flow.CONF_HOST] == "mock-deconz" +async def test_hassio_dont_update_instance(hass): + """Test we can update an existing config entry.""" + entry = MockConfigEntry( + domain=config_flow.DOMAIN, + data={config_flow.CONF_BRIDGEID: "id", config_flow.CONF_HOST: "1.2.3.4"}, + ) + entry.add_to_hass(hass) + + result = await hass.config_entries.flow.async_init( + config_flow.DOMAIN, + data={config_flow.CONF_HOST: "1.2.3.4", config_flow.CONF_SERIAL: "id"}, + context={"source": "hassio"}, + ) + + assert result["type"] == "abort" + assert result["reason"] == "already_configured" + + async def test_hassio_confirm(hass): """Test we can finish a config flow.""" result = await hass.config_entries.flow.async_init( From 85a1726e69d4aa55a9d88468969d1995d0425f7e Mon Sep 17 00:00:00 2001 From: tyjtyj Date: Sun, 1 Sep 2019 16:24:54 +0800 Subject: [PATCH 06/16] Fix google_maps scan interval (#26328) Reported on https://github.com/home-assistant/home-assistant/issues/26275 --- homeassistant/components/google_maps/device_tracker.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/google_maps/device_tracker.py b/homeassistant/components/google_maps/device_tracker.py index 2149e40e504..2b5550860ee 100644 --- a/homeassistant/components/google_maps/device_tracker.py +++ b/homeassistant/components/google_maps/device_tracker.py @@ -52,7 +52,7 @@ class GoogleMapsScanner: self.see = see self.username = config[CONF_USERNAME] self.max_gps_accuracy = config[CONF_MAX_GPS_ACCURACY] - self.scan_interval = config.get(CONF_SCAN_INTERVAL) or timedelta(60) + self.scan_interval = config.get(CONF_SCAN_INTERVAL) or timedelta(seconds=60) credfile = "{}.{}".format( hass.config.path(CREDENTIALS_FILE), slugify(self.username) From f6cf4c38e741091b00a6b09a432839db517fb5e2 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sun, 1 Sep 2019 22:31:00 -0700 Subject: [PATCH 07/16] Bumped version to 0.98.2 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 2f2546378db..6d195da991e 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 98 -PATCH_VERSION = "1" +PATCH_VERSION = "2" __short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION) __version__ = "{}.{}".format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 6, 0) From b50ac6f4869081cb930adbbadcec9532d9b1e239 Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Tue, 3 Sep 2019 10:17:03 +0200 Subject: [PATCH 08/16] Upgrade pyhaversion to 3.1.0 (#26232) --- homeassistant/components/version/manifest.json | 2 +- homeassistant/components/version/sensor.py | 12 ++++++++++-- requirements_all.txt | 2 +- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/version/manifest.json b/homeassistant/components/version/manifest.json index 2a48f91a6f8..815e7ff9a25 100644 --- a/homeassistant/components/version/manifest.json +++ b/homeassistant/components/version/manifest.json @@ -3,7 +3,7 @@ "name": "Version", "documentation": "https://www.home-assistant.io/components/version", "requirements": [ - "pyhaversion==3.0.2" + "pyhaversion==3.1.0" ], "dependencies": [], "codeowners": [ diff --git a/homeassistant/components/version/sensor.py b/homeassistant/components/version/sensor.py index 438ea8f690c..3e00b87e984 100644 --- a/homeassistant/components/version/sensor.py +++ b/homeassistant/components/version/sensor.py @@ -28,7 +28,7 @@ ALL_IMAGES = [ "odroid-c2", "odroid-xu", ] -ALL_SOURCES = ["local", "pypi", "hassio", "docker"] +ALL_SOURCES = ["local", "pypi", "hassio", "docker", "haio"] CONF_BETA = "beta" CONF_IMAGE = "image" @@ -54,7 +54,13 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( async def async_setup_platform(hass, config, async_add_entities, discovery_info=None): """Set up the Version sensor platform.""" - from pyhaversion import LocalVersion, DockerVersion, HassioVersion, PyPiVersion + from pyhaversion import ( + LocalVersion, + DockerVersion, + HassioVersion, + PyPiVersion, + HaIoVersion, + ) beta = config.get(CONF_BETA) image = config.get(CONF_IMAGE) @@ -74,6 +80,8 @@ async def async_setup_platform(hass, config, async_add_entities, discovery_info= haversion = VersionData(HassioVersion(hass.loop, session, branch, image)) elif source == "docker": haversion = VersionData(DockerVersion(hass.loop, session, branch, image)) + elif source == "haio": + haversion = VersionData(HaIoVersion(hass.loop, session)) else: haversion = VersionData(LocalVersion(hass.loop, session)) diff --git a/requirements_all.txt b/requirements_all.txt index 2bf7e6a841c..42272a0ccbb 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1186,7 +1186,7 @@ pygtfs==0.1.5 pygtt==1.1.2 # homeassistant.components.version -pyhaversion==3.0.2 +pyhaversion==3.1.0 # homeassistant.components.heos pyheos==0.6.0 From a74bb3fd5e7b66bf6afb24cc4d831a5303fb797f Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Tue, 3 Sep 2019 07:12:10 +0200 Subject: [PATCH 09/16] String has nothing to do with class method naming (#26368) --- homeassistant/components/deconz/.translations/en.json | 2 +- homeassistant/components/deconz/strings.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/deconz/.translations/en.json b/homeassistant/components/deconz/.translations/en.json index 57da3c706a0..3c6656d6ae6 100644 --- a/homeassistant/components/deconz/.translations/en.json +++ b/homeassistant/components/deconz/.translations/en.json @@ -43,7 +43,7 @@ }, "options": { "step": { - "async_step_deconz_devices": { + "deconz_devices": { "data": { "allow_clip_sensor": "Allow deCONZ CLIP sensors", "allow_deconz_groups": "Allow deCONZ light groups" diff --git a/homeassistant/components/deconz/strings.json b/homeassistant/components/deconz/strings.json index ea9ea280515..7081f816e6a 100644 --- a/homeassistant/components/deconz/strings.json +++ b/homeassistant/components/deconz/strings.json @@ -43,7 +43,7 @@ }, "options": { "step": { - "async_step_deconz_devices": { + "deconz_devices": { "description": "Configure visibility of deCONZ device types", "data": { "allow_clip_sensor": "Allow deCONZ CLIP sensors", From a980eedd226321732ff2a6889dc23a49363f217b Mon Sep 17 00:00:00 2001 From: Anders Melchiorsen Date: Tue, 3 Sep 2019 14:14:33 +0200 Subject: [PATCH 10/16] Fix race during initial Sonos group construction (#26371) * Fix race during initial Sonos group construction * Update homeassistant/components/sonos/media_player.py --- homeassistant/components/sonos/media_player.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/sonos/media_player.py b/homeassistant/components/sonos/media_player.py index 86e30621334..70461ad15d2 100644 --- a/homeassistant/components/sonos/media_player.py +++ b/homeassistant/components/sonos/media_player.py @@ -337,8 +337,16 @@ class SonosEntity(MediaPlayerDevice): async def async_added_to_hass(self): """Subscribe sonos events.""" await self.async_seen() + self.hass.data[DATA_SONOS].entities.append(self) + def _rebuild_groups(): + """Build the current group topology.""" + for entity in self.hass.data[DATA_SONOS].entities: + entity.update_groups() + + self.hass.async_add_executor_job(_rebuild_groups) + @property def unique_id(self): """Return a unique ID.""" @@ -469,10 +477,6 @@ class SonosEntity(MediaPlayerDevice): self.update_volume() self._set_favorites() - # New player available, build the current group topology - for entity in self.hass.data[DATA_SONOS].entities: - entity.update_groups() - player = self.soco def subscribe(service, action): From d4905477b812213da2333103c9fdd789151ae2d8 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 3 Sep 2019 23:13:34 -0700 Subject: [PATCH 11/16] Allow core config updated (#26398) --- homeassistant/components/websocket_api/permissions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/homeassistant/components/websocket_api/permissions.py b/homeassistant/components/websocket_api/permissions.py index 7aa845a298d..ffbb80fa19e 100644 --- a/homeassistant/components/websocket_api/permissions.py +++ b/homeassistant/components/websocket_api/permissions.py @@ -8,6 +8,7 @@ from homeassistant.const import ( EVENT_SERVICE_REMOVED, EVENT_STATE_CHANGED, EVENT_THEMES_UPDATED, + EVENT_CORE_CONFIG_UPDATE, ) from homeassistant.components.persistent_notification import ( EVENT_PERSISTENT_NOTIFICATIONS_UPDATED, @@ -22,6 +23,7 @@ from homeassistant.components.frontend import EVENT_PANELS_UPDATED # Except for state_changed, which is handled accordingly. SUBSCRIBE_WHITELIST = { EVENT_COMPONENT_LOADED, + EVENT_CORE_CONFIG_UPDATE, EVENT_PANELS_UPDATED, EVENT_PERSISTENT_NOTIFICATIONS_UPDATED, EVENT_SERVICE_REGISTERED, From 93e4cd6bb22ab8295d32b53651bb2f21aa76b2fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20H=C3=B8yer=20Iversen?= Date: Wed, 4 Sep 2019 09:13:17 +0300 Subject: [PATCH 12/16] Met, check for existing location (#26400) --- .../components/met/.translations/en.json | 2 +- homeassistant/components/met/config_flow.py | 18 +++++++++++++----- homeassistant/components/met/strings.json | 2 +- tests/components/met/test_config_flow.py | 4 +++- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/met/.translations/en.json b/homeassistant/components/met/.translations/en.json index 21ae7cb78fa..93d028b0626 100644 --- a/homeassistant/components/met/.translations/en.json +++ b/homeassistant/components/met/.translations/en.json @@ -1,7 +1,7 @@ { "config": { "error": { - "name_exists": "Name already exists" + "name_exists": "Location already exists" }, "step": { "user": { diff --git a/homeassistant/components/met/config_flow.py b/homeassistant/components/met/config_flow.py index 795ba57d988..c7ff4973c7d 100644 --- a/homeassistant/components/met/config_flow.py +++ b/homeassistant/components/met/config_flow.py @@ -12,9 +12,15 @@ from .const import DOMAIN, HOME_LOCATION_NAME, CONF_TRACK_HOME @callback def configured_instances(hass): """Return a set of configured SimpliSafe instances.""" - return set( - entry.data[CONF_NAME] for entry in hass.config_entries.async_entries(DOMAIN) - ) + entites = [] + for entry in hass.config_entries.async_entries(DOMAIN): + if entry.data.get("track_home"): + entites.append("home") + continue + entites.append( + f"{entry.data.get(CONF_LATITUDE)}-{entry.data.get(CONF_LONGITUDE)}" + ) + return set(entites) class MetFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): @@ -32,11 +38,13 @@ class MetFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): self._errors = {} if user_input is not None: - if user_input[CONF_NAME] not in configured_instances(self.hass): + if ( + f"{user_input.get(CONF_LATITUDE)}-{user_input.get(CONF_LONGITUDE)}" + not in configured_instances(self.hass) + ): return self.async_create_entry( title=user_input[CONF_NAME], data=user_input ) - self._errors[CONF_NAME] = "name_exists" return await self._show_config_form( diff --git a/homeassistant/components/met/strings.json b/homeassistant/components/met/strings.json index f5c49bac3c4..0c52e624418 100644 --- a/homeassistant/components/met/strings.json +++ b/homeassistant/components/met/strings.json @@ -14,7 +14,7 @@ } }, "error": { - "name_exists": "Name already exists" + "name_exists": "Location already exists" } } } diff --git a/tests/components/met/test_config_flow.py b/tests/components/met/test_config_flow.py index 22061386b93..32f3be676e0 100644 --- a/tests/components/met/test_config_flow.py +++ b/tests/components/met/test_config_flow.py @@ -102,7 +102,7 @@ async def test_flow_entry_created_from_user_input(): async def test_flow_entry_config_entry_already_exists(): """Test that create data from user input and config_entry already exists. - Test when the form should show when user puts existing name + Test when the form should show when user puts existing location in the config gui. Then the form should show with error """ hass = Mock() @@ -112,6 +112,8 @@ async def test_flow_entry_config_entry_already_exists(): first_entry = MockConfigEntry(domain="met") first_entry.data["name"] = "home" + first_entry.data[CONF_LONGITUDE] = "0" + first_entry.data[CONF_LATITUDE] = "0" first_entry.add_to_hass(hass) test_data = { From 8cf02e0b223572604e07d6e79e05ddac90aee7ab Mon Sep 17 00:00:00 2001 From: ehendrix23 Date: Tue, 3 Sep 2019 20:00:05 -0600 Subject: [PATCH 13/16] Update to 0.1.13 (#26402) Update to 0.1.13 --- homeassistant/components/harmony/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/harmony/manifest.json b/homeassistant/components/harmony/manifest.json index b2f9e69e014..a957db0675f 100644 --- a/homeassistant/components/harmony/manifest.json +++ b/homeassistant/components/harmony/manifest.json @@ -3,7 +3,7 @@ "name": "Harmony", "documentation": "https://www.home-assistant.io/components/harmony", "requirements": [ - "aioharmony==0.1.11" + "aioharmony==0.1.13" ], "dependencies": [], "codeowners": [ diff --git a/requirements_all.txt b/requirements_all.txt index 42272a0ccbb..bb6035b01e1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -142,7 +142,7 @@ aiofreepybox==0.0.8 aioftp==0.12.0 # homeassistant.components.harmony -aioharmony==0.1.11 +aioharmony==0.1.13 # homeassistant.components.emulated_hue # homeassistant.components.http From 7bccbcbcc3737cf8076a91d6f68017bb4bfef150 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 3 Sep 2019 18:57:32 -0700 Subject: [PATCH 14/16] Fix state report (#26406) * Fix state report * Update test --- homeassistant/components/alexa/state_report.py | 7 +++++-- tests/components/alexa/test_state_report.py | 4 ++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/alexa/state_report.py b/homeassistant/components/alexa/state_report.py index 1e22d5fc09f..fbf928fd23e 100644 --- a/homeassistant/components/alexa/state_report.py +++ b/homeassistant/components/alexa/state_report.py @@ -97,12 +97,15 @@ async def async_send_changereport_message( _LOGGER.debug("Sent: %s", json.dumps(message_serialized)) _LOGGER.debug("Received (%s): %s", response.status, response_text) - if response.status == 202 and not invalidate_access_token: + if response.status == 202: return response_json = json.loads(response_text) - if response_json["payload"]["code"] == "INVALID_ACCESS_TOKEN_EXCEPTION": + if ( + response_json["payload"]["code"] == "INVALID_ACCESS_TOKEN_EXCEPTION" + and not invalidate_access_token + ): config.async_invalidate_access_token() return await async_send_changereport_message( hass, config, alexa_entity, invalidate_access_token=False diff --git a/tests/components/alexa/test_state_report.py b/tests/components/alexa/test_state_report.py index f6bb4c9cc29..2b3f9f34adf 100644 --- a/tests/components/alexa/test_state_report.py +++ b/tests/components/alexa/test_state_report.py @@ -5,7 +5,7 @@ from . import TEST_URL, DEFAULT_CONFIG async def test_report_state(hass, aioclient_mock): """Test proactive state reports.""" - aioclient_mock.post(TEST_URL, json={"data": "is irrelevant"}, status=202) + aioclient_mock.post(TEST_URL, text="", status=202) hass.states.async_set( "binary_sensor.test_contact", @@ -39,7 +39,7 @@ async def test_report_state(hass, aioclient_mock): async def test_send_add_or_update_message(hass, aioclient_mock): """Test sending an AddOrUpdateReport message.""" - aioclient_mock.post(TEST_URL, json={"data": "is irrelevant"}) + aioclient_mock.post(TEST_URL, text="") hass.states.async_set( "binary_sensor.test_contact", From 860843ada1690dcf7c968834109012f8a23899fa Mon Sep 17 00:00:00 2001 From: Greg Laabs Date: Tue, 3 Sep 2019 23:11:30 -0700 Subject: [PATCH 15/16] Bump ISY994's PyISY dependency to 1.1.2 (#26413) Fixed a major bug that was responsible for ISY events getting seemingly random delays up to 24 seconds --- homeassistant/components/isy994/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/isy994/manifest.json b/homeassistant/components/isy994/manifest.json index 7860c080b2f..0dd0f1eae80 100644 --- a/homeassistant/components/isy994/manifest.json +++ b/homeassistant/components/isy994/manifest.json @@ -3,7 +3,7 @@ "name": "Isy994", "documentation": "https://www.home-assistant.io/components/isy994", "requirements": [ - "PyISY==1.1.1" + "PyISY==1.1.2" ], "dependencies": [], "codeowners": [] diff --git a/requirements_all.txt b/requirements_all.txt index bb6035b01e1..3660514e355 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -50,7 +50,7 @@ PyEssent==0.13 PyGithub==1.43.5 # homeassistant.components.isy994 -PyISY==1.1.1 +PyISY==1.1.2 # homeassistant.components.mvglive PyMVGLive==1.1.4 From b8f9319cb0cbeee2c4058e5339f1a6a32da2b45c Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 3 Sep 2019 23:20:25 -0700 Subject: [PATCH 16/16] Bumped version to 0.98.3 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 6d195da991e..2a20917b3be 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -2,7 +2,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 0 MINOR_VERSION = 98 -PATCH_VERSION = "2" +PATCH_VERSION = "3" __short_version__ = "{}.{}".format(MAJOR_VERSION, MINOR_VERSION) __version__ = "{}.{}".format(__short_version__, PATCH_VERSION) REQUIRED_PYTHON_VER = (3, 6, 0)