From 4b5056a45623f36a8ebac9d5954c5be185cee91b Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Wed, 30 Dec 2020 12:18:22 +0100 Subject: [PATCH 01/39] Bumped version to 2021.1.0b0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index de18fd4ed04..2ff32fc8392 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 2021 MINOR_VERSION = 1 -PATCH_VERSION = "0.dev0" +PATCH_VERSION = "0b0" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 1) From 335aceedfbc7768d5671aeef10e24a02b9fc2e71 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 30 Dec 2020 12:10:42 -1000 Subject: [PATCH 02/39] Update py-august to 0.25.2 to fix august token refreshes (#40109) * Update py-august to 0.26.0 to fix august token refreshes * bump version --- homeassistant/components/august/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/august/manifest.json b/homeassistant/components/august/manifest.json index c2c383468f6..67649b7edba 100644 --- a/homeassistant/components/august/manifest.json +++ b/homeassistant/components/august/manifest.json @@ -2,7 +2,7 @@ "domain": "august", "name": "August", "documentation": "https://www.home-assistant.io/integrations/august", - "requirements": ["py-august==0.25.0"], + "requirements": ["py-august==0.25.2"], "dependencies": ["configurator"], "codeowners": ["@bdraco"], "config_flow": true diff --git a/requirements_all.txt b/requirements_all.txt index 8477f615aab..cdf9eedec8f 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1192,7 +1192,7 @@ pushover_complete==1.1.1 pwmled==1.6.7 # homeassistant.components.august -py-august==0.25.0 +py-august==0.25.2 # homeassistant.components.canary py-canary==0.5.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 2e038049fad..22246aa4ece 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -597,7 +597,7 @@ pure-python-adb[async]==0.3.0.dev0 pushbullet.py==0.11.0 # homeassistant.components.august -py-august==0.25.0 +py-august==0.25.2 # homeassistant.components.canary py-canary==0.5.0 From e65903822de83fd28c925abacc7525901e4b90ad Mon Sep 17 00:00:00 2001 From: Raman Gupta <7243222+raman325@users.noreply.github.com> Date: Fri, 1 Jan 2021 06:35:05 -0600 Subject: [PATCH 03/39] Suppress vizio logging API call failures to prevent no-op logs (#44388) --- .../components/vizio/media_player.py | 43 +++++++++++-------- tests/components/vizio/test_config_flow.py | 1 + tests/components/vizio/test_media_player.py | 27 ++++++++++-- 3 files changed, 50 insertions(+), 21 deletions(-) diff --git a/homeassistant/components/vizio/media_player.py b/homeassistant/components/vizio/media_player.py index 61c9ca54854..4c06c89692a 100644 --- a/homeassistant/components/vizio/media_player.py +++ b/homeassistant/components/vizio/media_player.py @@ -184,10 +184,10 @@ class VizioDevice(MediaPlayerEntity): async def async_update(self) -> None: """Retrieve latest state of the device.""" if not self._model: - self._model = await self._device.get_model_name() + self._model = await self._device.get_model_name(log_api_exception=False) if not self._sw_version: - self._sw_version = await self._device.get_version() + self._sw_version = await self._device.get_version(log_api_exception=False) is_on = await self._device.get_power_state(log_api_exception=False) @@ -236,7 +236,9 @@ class VizioDevice(MediaPlayerEntity): if not self._available_sound_modes: self._available_sound_modes = ( await self._device.get_setting_options( - VIZIO_AUDIO_SETTINGS, VIZIO_SOUND_MODE + VIZIO_AUDIO_SETTINGS, + VIZIO_SOUND_MODE, + log_api_exception=False, ) ) else: @@ -306,6 +308,7 @@ class VizioDevice(MediaPlayerEntity): setting_type, setting_name, new_value, + log_api_exception=False, ) async def async_added_to_hass(self) -> None: @@ -453,52 +456,58 @@ class VizioDevice(MediaPlayerEntity): """Select sound mode.""" if sound_mode in self._available_sound_modes: await self._device.set_setting( - VIZIO_AUDIO_SETTINGS, VIZIO_SOUND_MODE, sound_mode + VIZIO_AUDIO_SETTINGS, + VIZIO_SOUND_MODE, + sound_mode, + log_api_exception=False, ) async def async_turn_on(self) -> None: """Turn the device on.""" - await self._device.pow_on() + await self._device.pow_on(log_api_exception=False) async def async_turn_off(self) -> None: """Turn the device off.""" - await self._device.pow_off() + await self._device.pow_off(log_api_exception=False) async def async_mute_volume(self, mute: bool) -> None: """Mute the volume.""" if mute: - await self._device.mute_on() + await self._device.mute_on(log_api_exception=False) self._is_volume_muted = True else: - await self._device.mute_off() + await self._device.mute_off(log_api_exception=False) self._is_volume_muted = False async def async_media_previous_track(self) -> None: """Send previous channel command.""" - await self._device.ch_down() + await self._device.ch_down(log_api_exception=False) async def async_media_next_track(self) -> None: """Send next channel command.""" - await self._device.ch_up() + await self._device.ch_up(log_api_exception=False) async def async_select_source(self, source: str) -> None: """Select input source.""" if source in self._available_inputs: - await self._device.set_input(source) + await self._device.set_input(source, log_api_exception=False) elif source in self._get_additional_app_names(): await self._device.launch_app_config( **next( app["config"] for app in self._additional_app_configs if app["name"] == source - ) + ), + log_api_exception=False, ) elif source in self._available_apps: - await self._device.launch_app(source, self._all_apps) + await self._device.launch_app( + source, self._all_apps, log_api_exception=False + ) async def async_volume_up(self) -> None: """Increase volume of the device.""" - await self._device.vol_up(num=self._volume_step) + await self._device.vol_up(num=self._volume_step, log_api_exception=False) if self._volume_level is not None: self._volume_level = min( @@ -507,7 +516,7 @@ class VizioDevice(MediaPlayerEntity): async def async_volume_down(self) -> None: """Decrease volume of the device.""" - await self._device.vol_down(num=self._volume_step) + await self._device.vol_down(num=self._volume_step, log_api_exception=False) if self._volume_level is not None: self._volume_level = max( @@ -519,10 +528,10 @@ class VizioDevice(MediaPlayerEntity): if self._volume_level is not None: if volume > self._volume_level: num = int(self._max_volume * (volume - self._volume_level)) - await self._device.vol_up(num=num) + await self._device.vol_up(num=num, log_api_exception=False) self._volume_level = volume elif volume < self._volume_level: num = int(self._max_volume * (self._volume_level - volume)) - await self._device.vol_down(num=num) + await self._device.vol_down(num=num, log_api_exception=False) self._volume_level = volume diff --git a/tests/components/vizio/test_config_flow.py b/tests/components/vizio/test_config_flow.py index e966188afd2..5f33aa2be4a 100644 --- a/tests/components/vizio/test_config_flow.py +++ b/tests/components/vizio/test_config_flow.py @@ -858,6 +858,7 @@ async def test_zeroconf_ignore( async def test_zeroconf_no_unique_id( hass: HomeAssistantType, + vizio_guess_device_type: pytest.fixture, vizio_no_unique_id: pytest.fixture, ) -> None: """Test zeroconf discovery aborts when unique_id is None.""" diff --git a/tests/components/vizio/test_media_player.py b/tests/components/vizio/test_media_player.py index 996d46e08a7..0d11ec2289c 100644 --- a/tests/components/vizio/test_media_player.py +++ b/tests/components/vizio/test_media_player.py @@ -40,6 +40,7 @@ from homeassistant.components.vizio.const import ( CONF_ADDITIONAL_CONFIGS, CONF_APPS, CONF_VOLUME_STEP, + DEFAULT_VOLUME_STEP, DOMAIN, SERVICE_UPDATE_SETTING, VIZIO_SCHEMA, @@ -259,6 +260,7 @@ async def _test_service( **kwargs, ) -> None: """Test generic Vizio media player entity service.""" + kwargs["log_api_exception"] = False service_data = {ATTR_ENTITY_ID: ENTITY_ID} if additional_service_data: service_data.update(additional_service_data) @@ -378,13 +380,27 @@ async def test_services( {ATTR_INPUT_SOURCE: "USB"}, "USB", ) - await _test_service(hass, MP_DOMAIN, "vol_up", SERVICE_VOLUME_UP, None) - await _test_service(hass, MP_DOMAIN, "vol_down", SERVICE_VOLUME_DOWN, None) await _test_service( - hass, MP_DOMAIN, "vol_up", SERVICE_VOLUME_SET, {ATTR_MEDIA_VOLUME_LEVEL: 1} + hass, MP_DOMAIN, "vol_up", SERVICE_VOLUME_UP, None, num=DEFAULT_VOLUME_STEP ) await _test_service( - hass, MP_DOMAIN, "vol_down", SERVICE_VOLUME_SET, {ATTR_MEDIA_VOLUME_LEVEL: 0} + hass, MP_DOMAIN, "vol_down", SERVICE_VOLUME_DOWN, None, num=DEFAULT_VOLUME_STEP + ) + await _test_service( + hass, + MP_DOMAIN, + "vol_up", + SERVICE_VOLUME_SET, + {ATTR_MEDIA_VOLUME_LEVEL: 1}, + num=(100 - 15), + ) + await _test_service( + hass, + MP_DOMAIN, + "vol_down", + SERVICE_VOLUME_SET, + {ATTR_MEDIA_VOLUME_LEVEL: 0}, + num=(15 - 0), ) await _test_service(hass, MP_DOMAIN, "ch_up", SERVICE_MEDIA_NEXT_TRACK, None) await _test_service(hass, MP_DOMAIN, "ch_down", SERVICE_MEDIA_PREVIOUS_TRACK, None) @@ -394,6 +410,9 @@ async def test_services( "set_setting", SERVICE_SELECT_SOUND_MODE, {ATTR_SOUND_MODE: "Music"}, + "audio", + "eq", + "Music", ) # Test that the update_setting service does config validation/transformation correctly await _test_service( From 8a689a010548d86e049b165234d580d5a976c555 Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Thu, 31 Dec 2020 00:02:56 +0100 Subject: [PATCH 04/39] Add motion binary sensor (#44445) --- homeassistant/components/shelly/binary_sensor.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/homeassistant/components/shelly/binary_sensor.py b/homeassistant/components/shelly/binary_sensor.py index 53038352d4d..d53f089054a 100644 --- a/homeassistant/components/shelly/binary_sensor.py +++ b/homeassistant/components/shelly/binary_sensor.py @@ -3,6 +3,7 @@ from homeassistant.components.binary_sensor import ( DEVICE_CLASS_CONNECTIVITY, DEVICE_CLASS_GAS, DEVICE_CLASS_MOISTURE, + DEVICE_CLASS_MOTION, DEVICE_CLASS_OPENING, DEVICE_CLASS_POWER, DEVICE_CLASS_PROBLEM, @@ -70,6 +71,9 @@ SENSORS = { default_enabled=False, removal_condition=is_momentary_input, ), + ("sensor", "motion"): BlockAttributeDescription( + name="Motion", device_class=DEVICE_CLASS_MOTION + ), } REST_SENSORS = { From 1b26f6e8e0f81ae86290949232dc45217b0818cf Mon Sep 17 00:00:00 2001 From: Sian Date: Sat, 2 Jan 2021 01:36:36 +1030 Subject: [PATCH 05/39] Correct Dyson climate fan auto mode (#44569) Co-authored-by: Justin Gauthier --- homeassistant/components/dyson/climate.py | 8 ++++++-- tests/components/dyson/test_climate.py | 3 +-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/dyson/climate.py b/homeassistant/components/dyson/climate.py index d2c23f46093..a71c124c633 100644 --- a/homeassistant/components/dyson/climate.py +++ b/homeassistant/components/dyson/climate.py @@ -2,6 +2,7 @@ import logging from libpurecool.const import ( + AutoMode, FanPower, FanSpeed, FanState, @@ -333,7 +334,10 @@ class DysonPureHotCoolEntity(ClimateEntity): @property def fan_mode(self): """Return the fan setting.""" - if self._device.state.fan_state == FanState.FAN_OFF.value: + if ( + self._device.state.auto_mode != AutoMode.AUTO_ON.value + and self._device.state.fan_state == FanState.FAN_OFF.value + ): return FAN_OFF return SPEED_MAP[self._device.state.speed] @@ -368,7 +372,7 @@ class DysonPureHotCoolEntity(ClimateEntity): elif fan_mode == FAN_HIGH: self._device.set_fan_speed(FanSpeed.FAN_SPEED_10) elif fan_mode == FAN_AUTO: - self._device.set_fan_speed(FanSpeed.FAN_SPEED_AUTO) + self._device.enable_auto_mode() def set_hvac_mode(self, hvac_mode): """Set new target hvac mode.""" diff --git a/tests/components/dyson/test_climate.py b/tests/components/dyson/test_climate.py index 77105dc73db..c4e4c91087c 100644 --- a/tests/components/dyson/test_climate.py +++ b/tests/components/dyson/test_climate.py @@ -677,8 +677,7 @@ async def test_purehotcool_set_fan_mode(devices, login, hass): {ATTR_ENTITY_ID: "climate.living_room", ATTR_FAN_MODE: FAN_AUTO}, True, ) - assert device.set_fan_speed.call_count == 4 - device.set_fan_speed.assert_called_with(FanSpeed.FAN_SPEED_AUTO) + assert device.enable_auto_mode.call_count == 1 @patch("homeassistant.components.dyson.DysonAccount.login", return_value=True) From 470fe887a529195e2d62d9e2069f781b4112e875 Mon Sep 17 00:00:00 2001 From: Mark Allanson Date: Thu, 31 Dec 2020 00:16:53 +0000 Subject: [PATCH 06/39] Upgrade canary integration to use py-canary 0.5.1 (#44645) Fixes #35569 --- homeassistant/components/canary/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/canary/manifest.json b/homeassistant/components/canary/manifest.json index b4598d64087..af6b0ce54ba 100644 --- a/homeassistant/components/canary/manifest.json +++ b/homeassistant/components/canary/manifest.json @@ -2,7 +2,7 @@ "domain": "canary", "name": "Canary", "documentation": "https://www.home-assistant.io/integrations/canary", - "requirements": ["py-canary==0.5.0"], + "requirements": ["py-canary==0.5.1"], "dependencies": ["ffmpeg"], "codeowners": [], "config_flow": true diff --git a/requirements_all.txt b/requirements_all.txt index cdf9eedec8f..4369011a58a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1195,7 +1195,7 @@ pwmled==1.6.7 py-august==0.25.2 # homeassistant.components.canary -py-canary==0.5.0 +py-canary==0.5.1 # homeassistant.components.cpuspeed py-cpuinfo==7.0.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 22246aa4ece..0153cfee3db 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -600,7 +600,7 @@ pushbullet.py==0.11.0 py-august==0.25.2 # homeassistant.components.canary -py-canary==0.5.0 +py-canary==0.5.1 # homeassistant.components.melissa py-melissa-climate==2.1.4 From 7d99a35547e6cc27e30f176f362ed4583335ba44 Mon Sep 17 00:00:00 2001 From: "David F. Mulcahey" Date: Wed, 30 Dec 2020 09:11:08 -0500 Subject: [PATCH 07/39] Bump ZHA quirks version to 0.0.50 (#44650) --- homeassistant/components/zha/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/zha/manifest.json b/homeassistant/components/zha/manifest.json index ed2460614fc..ebca96da5fd 100644 --- a/homeassistant/components/zha/manifest.json +++ b/homeassistant/components/zha/manifest.json @@ -7,7 +7,7 @@ "bellows==0.21.0", "pyserial==3.5", "pyserial-asyncio==0.5", - "zha-quirks==0.0.49", + "zha-quirks==0.0.50", "zigpy-cc==0.5.2", "zigpy-deconz==0.11.0", "zigpy==0.28.2", diff --git a/requirements_all.txt b/requirements_all.txt index 4369011a58a..e74131e3479 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2339,7 +2339,7 @@ zengge==0.2 zeroconf==0.28.7 # homeassistant.components.zha -zha-quirks==0.0.49 +zha-quirks==0.0.50 # homeassistant.components.zhong_hong zhong_hong_hvac==1.0.9 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 0153cfee3db..7d4bf31e2e0 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1144,7 +1144,7 @@ zeep[async]==4.0.0 zeroconf==0.28.7 # homeassistant.components.zha -zha-quirks==0.0.49 +zha-quirks==0.0.50 # homeassistant.components.zha zigpy-cc==0.5.2 From 3cd97398aa8a3bf6d49c38d2c295c030bced5993 Mon Sep 17 00:00:00 2001 From: Daniel Lintott Date: Wed, 30 Dec 2020 18:15:27 +0000 Subject: [PATCH 08/39] Bump zm-py version to 0.5.2 (#44658) --- homeassistant/components/zoneminder/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/zoneminder/manifest.json b/homeassistant/components/zoneminder/manifest.json index b3a87510e5a..039513f100e 100644 --- a/homeassistant/components/zoneminder/manifest.json +++ b/homeassistant/components/zoneminder/manifest.json @@ -2,6 +2,6 @@ "domain": "zoneminder", "name": "ZoneMinder", "documentation": "https://www.home-assistant.io/integrations/zoneminder", - "requirements": ["zm-py==0.4.0"], + "requirements": ["zm-py==0.5.2"], "codeowners": ["@rohankapoorcom"] } diff --git a/requirements_all.txt b/requirements_all.txt index e74131e3479..26b139a905c 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2366,4 +2366,4 @@ zigpy-znp==0.3.0 zigpy==0.28.2 # homeassistant.components.zoneminder -zm-py==0.4.0 +zm-py==0.5.2 From 610ee24bb15f0a23d914d594983e50dba234334b Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Wed, 30 Dec 2020 23:39:14 +0000 Subject: [PATCH 09/39] always sync unit_of_measurement (#44670) --- homeassistant/components/utility_meter/sensor.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/homeassistant/components/utility_meter/sensor.py b/homeassistant/components/utility_meter/sensor.py index 9a4ed9e7782..6b25ec7d123 100644 --- a/homeassistant/components/utility_meter/sensor.py +++ b/homeassistant/components/utility_meter/sensor.py @@ -145,13 +145,7 @@ class UtilityMeterSensor(RestoreEntity): ): return - if ( - self._unit_of_measurement is None - and new_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) is not None - ): - self._unit_of_measurement = new_state.attributes.get( - ATTR_UNIT_OF_MEASUREMENT - ) + self._unit_of_measurement = new_state.attributes.get(ATTR_UNIT_OF_MEASUREMENT) try: diff = Decimal(new_state.state) - Decimal(old_state.state) From 2b1df2e63facc22c18ec2c6dbb1ebd44f5871c39 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 1 Jan 2021 20:54:43 +0100 Subject: [PATCH 10/39] Catch Shelly zeroconf types with uppercase too (#44672) Co-authored-by: Franck Nijhof --- homeassistant/components/shelly/config_flow.py | 3 --- tests/components/shelly/test_config_flow.py | 11 ----------- 2 files changed, 14 deletions(-) diff --git a/homeassistant/components/shelly/config_flow.py b/homeassistant/components/shelly/config_flow.py index 261c1898ca9..b3dd7bb80fe 100644 --- a/homeassistant/components/shelly/config_flow.py +++ b/homeassistant/components/shelly/config_flow.py @@ -138,9 +138,6 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): async def async_step_zeroconf(self, zeroconf_info): """Handle zeroconf discovery.""" - if not zeroconf_info.get("name", "").startswith("shelly"): - return self.async_abort(reason="not_shelly") - try: self.info = info = await self._async_get_info(zeroconf_info["host"]) except HTTP_CONNECT_ERRORS: diff --git a/tests/components/shelly/test_config_flow.py b/tests/components/shelly/test_config_flow.py index 71c971757c1..2850be11450 100644 --- a/tests/components/shelly/test_config_flow.py +++ b/tests/components/shelly/test_config_flow.py @@ -488,14 +488,3 @@ async def test_zeroconf_require_auth(hass): } assert len(mock_setup.mock_calls) == 1 assert len(mock_setup_entry.mock_calls) == 1 - - -async def test_zeroconf_not_shelly(hass): - """Test we filter out non-shelly devices.""" - result = await hass.config_entries.flow.async_init( - DOMAIN, - data={"host": "1.1.1.1", "name": "notshelly"}, - context={"source": config_entries.SOURCE_ZEROCONF}, - ) - assert result["type"] == "abort" - assert result["reason"] == "not_shelly" From 34a6b4deb08321152fe5db8330aa9a9b44f67a12 Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Thu, 31 Dec 2020 10:22:24 -0800 Subject: [PATCH 11/39] Fix legacy nest api binary_sensor initialization (#44674) --- .../components/nest/binary_sensor.py | 2 +- .../components/nest/legacy/binary_sensor.py | 2 +- tests/components/nest/test_init_legacy.py | 87 +++++++++++++++++++ 3 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 tests/components/nest/test_init_legacy.py diff --git a/homeassistant/components/nest/binary_sensor.py b/homeassistant/components/nest/binary_sensor.py index dc58dd2856f..d49ec8535cc 100644 --- a/homeassistant/components/nest/binary_sensor.py +++ b/homeassistant/components/nest/binary_sensor.py @@ -4,7 +4,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.helpers.typing import HomeAssistantType from .const import DATA_SDM -from .legacy.sensor import async_setup_legacy_entry +from .legacy.binary_sensor import async_setup_legacy_entry async def async_setup_entry( diff --git a/homeassistant/components/nest/legacy/binary_sensor.py b/homeassistant/components/nest/legacy/binary_sensor.py index 4470bd14676..32c30f747d2 100644 --- a/homeassistant/components/nest/legacy/binary_sensor.py +++ b/homeassistant/components/nest/legacy/binary_sensor.py @@ -61,7 +61,7 @@ def setup_platform(hass, config, add_entities, discovery_info=None): """ -async def async_setup_entry(hass, entry, async_add_entities): +async def async_setup_legacy_entry(hass, entry, async_add_entities): """Set up a Nest binary sensor based on a config entry.""" nest = hass.data[DATA_NEST] diff --git a/tests/components/nest/test_init_legacy.py b/tests/components/nest/test_init_legacy.py new file mode 100644 index 00000000000..f85fcdaa749 --- /dev/null +++ b/tests/components/nest/test_init_legacy.py @@ -0,0 +1,87 @@ +"""Test basic initialization for the Legacy Nest API using mocks for the Nest python library.""" + +import time + +from homeassistant.setup import async_setup_component + +from tests.async_mock import MagicMock, PropertyMock, patch +from tests.common import MockConfigEntry + +DOMAIN = "nest" + +CONFIG = { + "nest": { + "client_id": "some-client-id", + "client_secret": "some-client-secret", + }, +} + +CONFIG_ENTRY_DATA = { + "auth_implementation": "local", + "tokens": { + "expires_at": time.time() + 86400, + "access_token": { + "token": "some-token", + }, + }, +} + + +def make_thermostat(): + """Make a mock thermostat with dummy values.""" + device = MagicMock() + type(device).device_id = PropertyMock(return_value="a.b.c.d.e.f.g") + type(device).name = PropertyMock(return_value="My Thermostat") + type(device).name_long = PropertyMock(return_value="My Thermostat") + type(device).serial = PropertyMock(return_value="serial-number") + type(device).mode = "off" + type(device).hvac_state = "off" + type(device).target = PropertyMock(return_value=31.0) + type(device).temperature = PropertyMock(return_value=30.1) + type(device).min_temperature = PropertyMock(return_value=10.0) + type(device).max_temperature = PropertyMock(return_value=50.0) + type(device).humidity = PropertyMock(return_value=40.4) + type(device).software_version = PropertyMock(return_value="a.b.c") + return device + + +async def test_thermostat(hass): + """Test simple initialization for thermostat entities.""" + + thermostat = make_thermostat() + + structure = MagicMock() + type(structure).name = PropertyMock(return_value="My Room") + type(structure).thermostats = PropertyMock(return_value=[thermostat]) + type(structure).eta = PropertyMock(return_value="away") + + nest = MagicMock() + type(nest).structures = PropertyMock(return_value=[structure]) + + config_entry = MockConfigEntry(domain=DOMAIN, data=CONFIG_ENTRY_DATA) + config_entry.add_to_hass(hass) + with patch("homeassistant.components.nest.legacy.Nest", return_value=nest), patch( + "homeassistant.components.nest.legacy.sensor._VALID_SENSOR_TYPES", + ["humidity", "temperature"], + ), patch( + "homeassistant.components.nest.legacy.binary_sensor._VALID_BINARY_SENSOR_TYPES", + {"fan": None}, + ): + assert await async_setup_component(hass, DOMAIN, CONFIG) + await hass.async_block_till_done() + + climate = hass.states.get("climate.my_thermostat") + assert climate is not None + assert climate.state == "off" + + temperature = hass.states.get("sensor.my_thermostat_temperature") + assert temperature is not None + assert temperature.state == "-1.1" + + humidity = hass.states.get("sensor.my_thermostat_humidity") + assert humidity is not None + assert humidity.state == "40.4" + + fan = hass.states.get("binary_sensor.my_thermostat_fan") + assert fan is not None + assert fan.state == "on" From 1c2e4226dc34f023a7a7ef759972a2ecba1d73e3 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Thu, 31 Dec 2020 01:06:26 +0100 Subject: [PATCH 12/39] Zeroconf lowercase (#44675) --- .../components/brother/manifest.json | 2 +- homeassistant/components/zeroconf/__init__.py | 36 +++++++++++-------- homeassistant/generated/zeroconf.py | 2 +- script/hassfest/manifest.py | 20 +++++++++-- tests/components/zeroconf/test_init.py | 8 +++-- 5 files changed, 48 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/brother/manifest.json b/homeassistant/components/brother/manifest.json index 0e534147cb1..9bb9ba00261 100644 --- a/homeassistant/components/brother/manifest.json +++ b/homeassistant/components/brother/manifest.json @@ -4,7 +4,7 @@ "documentation": "https://www.home-assistant.io/integrations/brother", "codeowners": ["@bieniu"], "requirements": ["brother==0.1.20"], - "zeroconf": [{"type": "_printer._tcp.local.", "name":"Brother*"}], + "zeroconf": [{ "type": "_printer._tcp.local.", "name": "brother*" }], "config_flow": true, "quality_scale": "platinum" } diff --git a/homeassistant/components/zeroconf/__init__.py b/homeassistant/components/zeroconf/__init__.py index 68300adbcfe..fdf4b98faf8 100644 --- a/homeassistant/components/zeroconf/__init__.py +++ b/homeassistant/components/zeroconf/__init__.py @@ -284,22 +284,30 @@ async def _async_start_zeroconf_browser(hass, zeroconf): # likely bad homekit data return + if "name" in info: + lowercase_name = info["name"].lower() + else: + lowercase_name = None + + if "macaddress" in info.get("properties", {}): + uppercase_mac = info["properties"]["macaddress"].upper() + else: + uppercase_mac = None + for entry in zeroconf_types[service_type]: if len(entry) > 1: - if "macaddress" in entry: - if "properties" not in info: - continue - if "macaddress" not in info["properties"]: - continue - if not fnmatch.fnmatch( - info["properties"]["macaddress"], entry["macaddress"] - ): - continue - if "name" in entry: - if "name" not in info: - continue - if not fnmatch.fnmatch(info["name"], entry["name"]): - continue + if ( + uppercase_mac is not None + and "macaddress" in entry + and not fnmatch.fnmatch(uppercase_mac, entry["macaddress"]) + ): + continue + if ( + lowercase_name is not None + and "name" in entry + and not fnmatch.fnmatch(lowercase_name, entry["name"]) + ): + continue hass.add_job( hass.config_entries.flow.async_init( diff --git a/homeassistant/generated/zeroconf.py b/homeassistant/generated/zeroconf.py index 57b6e6cb123..49527666f53 100644 --- a/homeassistant/generated/zeroconf.py +++ b/homeassistant/generated/zeroconf.py @@ -116,7 +116,7 @@ ZEROCONF = { "_printer._tcp.local.": [ { "domain": "brother", - "name": "Brother*" + "name": "brother*" } ], "_spotify-connect._tcp.local.": [ diff --git a/script/hassfest/manifest.py b/script/hassfest/manifest.py index 389e380af85..7500483ec53 100644 --- a/script/hassfest/manifest.py +++ b/script/hassfest/manifest.py @@ -33,6 +33,22 @@ def documentation_url(value: str) -> str: return value +def verify_lowercase(value: str): + """Verify a value is lowercase.""" + if value.lower() != value: + raise vol.Invalid("Value needs to be lowercase") + + return value + + +def verify_uppercase(value: str): + """Verify a value is uppercase.""" + if value.upper() != value: + raise vol.Invalid("Value needs to be uppercase") + + return value + + MANIFEST_SCHEMA = vol.Schema( { vol.Required("domain"): str, @@ -45,8 +61,8 @@ MANIFEST_SCHEMA = vol.Schema( vol.Schema( { vol.Required("type"): str, - vol.Optional("macaddress"): str, - vol.Optional("name"): str, + vol.Optional("macaddress"): vol.All(str, verify_uppercase), + vol.Optional("name"): vol.All(str, verify_lowercase), } ), ) diff --git a/tests/components/zeroconf/test_init.py b/tests/components/zeroconf/test_init.py index 8767953b363..6b79c552911 100644 --- a/tests/components/zeroconf/test_init.py +++ b/tests/components/zeroconf/test_init.py @@ -242,13 +242,17 @@ async def test_zeroconf_match(hass, mock_zeroconf): handlers[0]( zeroconf, "_http._tcp.local.", - "shelly108._http._tcp.local.", + "Shelly108._http._tcp.local.", ServiceStateChange.Added, ) with patch.dict( zc_gen.ZEROCONF, - {"_http._tcp.local.": [{"domain": "shelly", "name": "shelly*"}]}, + { + "_http._tcp.local.": [ + {"domain": "shelly", "name": "shelly*", "macaddress": "FFAADD*"} + ] + }, clear=True, ), patch.object( hass.config_entries.flow, "async_init" From 864546201ebce130dd727dabd358dd1a5c2132cd Mon Sep 17 00:00:00 2001 From: Alexei Chetroi Date: Thu, 31 Dec 2020 08:07:15 -0500 Subject: [PATCH 13/39] Bump up ZHA dependencies (#44680) - zigpy == 0.29.0 - zigpy_deconz == 0.11.1 - zha-quirks == 0.0.51 --- homeassistant/components/zha/manifest.json | 6 +++--- requirements_all.txt | 6 +++--- requirements_test_all.txt | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/zha/manifest.json b/homeassistant/components/zha/manifest.json index ebca96da5fd..54fceda03a6 100644 --- a/homeassistant/components/zha/manifest.json +++ b/homeassistant/components/zha/manifest.json @@ -7,10 +7,10 @@ "bellows==0.21.0", "pyserial==3.5", "pyserial-asyncio==0.5", - "zha-quirks==0.0.50", + "zha-quirks==0.0.51", "zigpy-cc==0.5.2", - "zigpy-deconz==0.11.0", - "zigpy==0.28.2", + "zigpy-deconz==0.11.1", + "zigpy==0.29.0", "zigpy-xbee==0.13.0", "zigpy-zigate==0.7.3", "zigpy-znp==0.3.0" diff --git a/requirements_all.txt b/requirements_all.txt index 26b139a905c..b238a797135 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2339,7 +2339,7 @@ zengge==0.2 zeroconf==0.28.7 # homeassistant.components.zha -zha-quirks==0.0.50 +zha-quirks==0.0.51 # homeassistant.components.zhong_hong zhong_hong_hvac==1.0.9 @@ -2351,7 +2351,7 @@ ziggo-mediabox-xl==1.1.0 zigpy-cc==0.5.2 # homeassistant.components.zha -zigpy-deconz==0.11.0 +zigpy-deconz==0.11.1 # homeassistant.components.zha zigpy-xbee==0.13.0 @@ -2363,7 +2363,7 @@ zigpy-zigate==0.7.3 zigpy-znp==0.3.0 # homeassistant.components.zha -zigpy==0.28.2 +zigpy==0.29.0 # homeassistant.components.zoneminder zm-py==0.5.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 7d4bf31e2e0..4c9dc5cc37e 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1144,13 +1144,13 @@ zeep[async]==4.0.0 zeroconf==0.28.7 # homeassistant.components.zha -zha-quirks==0.0.50 +zha-quirks==0.0.51 # homeassistant.components.zha zigpy-cc==0.5.2 # homeassistant.components.zha -zigpy-deconz==0.11.0 +zigpy-deconz==0.11.1 # homeassistant.components.zha zigpy-xbee==0.13.0 @@ -1162,4 +1162,4 @@ zigpy-zigate==0.7.3 zigpy-znp==0.3.0 # homeassistant.components.zha -zigpy==0.28.2 +zigpy==0.29.0 From 39b9821d2956f0f41234e086479c50f669a22bcb Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Thu, 31 Dec 2020 14:04:12 -0800 Subject: [PATCH 14/39] Fix broken test test_auto_purge in recorder (#44687) * Fix failing test due to edge-of-2021 bug * Rewrite test_auto_purge to make the intent more clear --- tests/components/recorder/test_init.py | 45 +++++++++++++++++++++----- 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/tests/components/recorder/test_init.py b/tests/components/recorder/test_init.py index fcda7b0bb67..41c1f52b993 100644 --- a/tests/components/recorder/test_init.py +++ b/tests/components/recorder/test_init.py @@ -23,7 +23,7 @@ from homeassistant.util import dt as dt_util from .common import wait_recording_done from tests.async_mock import patch -from tests.common import async_fire_time_changed, get_test_home_assistant +from tests.common import fire_time_changed, get_test_home_assistant def test_saving_state(hass, hass_recorder): @@ -351,8 +351,15 @@ async def test_defaults_set(hass): assert recorder_config["purge_keep_days"] == 10 +def run_tasks_at_time(hass, test_time): + """Advance the clock and wait for any callbacks to finish.""" + fire_time_changed(hass, test_time) + hass.block_till_done() + hass.data[DATA_INSTANCE].block_till_done() + + def test_auto_purge(hass_recorder): - """Test saving and restoring a state.""" + """Test periodic purge alarm scheduling.""" hass = hass_recorder() original_tz = dt_util.DEFAULT_TIME_ZONE @@ -360,18 +367,40 @@ def test_auto_purge(hass_recorder): tz = dt_util.get_time_zone("Europe/Copenhagen") dt_util.set_default_time_zone(tz) + # Purging is schedule to happen at 4:12am every day. Exercise this behavior + # by firing alarms and advancing the clock around this time. Pick an arbitrary + # year in the future to avoid boundary conditions relative to the current date. + # + # The clock is started at 4:15am then advanced forward below now = dt_util.utcnow() - test_time = tz.localize(datetime(now.year + 1, 1, 1, 4, 12, 0)) - async_fire_time_changed(hass, test_time) + test_time = tz.localize(datetime(now.year + 2, 1, 1, 4, 15, 0)) + run_tasks_at_time(hass, test_time) with patch( "homeassistant.components.recorder.purge.purge_old_data", return_value=True ) as purge_old_data: - for delta in (-1, 0, 1): - async_fire_time_changed(hass, test_time + timedelta(seconds=delta)) - hass.block_till_done() - hass.data[DATA_INSTANCE].block_till_done() + # Advance one day, and the purge task should run + test_time = test_time + timedelta(days=1) + run_tasks_at_time(hass, test_time) + assert len(purge_old_data.mock_calls) == 1 + purge_old_data.reset_mock() + + # Advance one day, and the purge task should run again + test_time = test_time + timedelta(days=1) + run_tasks_at_time(hass, test_time) + assert len(purge_old_data.mock_calls) == 1 + + purge_old_data.reset_mock() + + # Advance less than one full day. The alarm should not yet fire. + test_time = test_time + timedelta(hours=23) + run_tasks_at_time(hass, test_time) + assert len(purge_old_data.mock_calls) == 0 + + # Advance to the next day and fire the alarm again + test_time = test_time + timedelta(hours=1) + run_tasks_at_time(hass, test_time) assert len(purge_old_data.mock_calls) == 1 dt_util.set_default_time_zone(original_tz) From 6d33f6a115b50bf809778b634f518291a23b42e4 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 1 Jan 2021 02:03:34 -1000 Subject: [PATCH 15/39] Fix script wait templates with now/utcnow (#44717) --- homeassistant/helpers/event.py | 6 +++--- homeassistant/helpers/script.py | 15 +++++++++++---- tests/helpers/test_event.py | 27 +++++++++++++++++++++++++++ tests/helpers/test_script.py | 26 ++++++++++++++++++++++++++ 4 files changed, 67 insertions(+), 7 deletions(-) diff --git a/homeassistant/helpers/event.py b/homeassistant/helpers/event.py index 661e1a11b56..f06ac8aca3f 100644 --- a/homeassistant/helpers/event.py +++ b/homeassistant/helpers/event.py @@ -715,9 +715,9 @@ def async_track_template( hass.async_run_hass_job( job, - event.data.get("entity_id"), - event.data.get("old_state"), - event.data.get("new_state"), + event and event.data.get("entity_id"), + event and event.data.get("old_state"), + event and event.data.get("new_state"), ) info = async_track_template_result( diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index 48a662e3a81..77c842a27fe 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -62,7 +62,11 @@ from homeassistant.core import ( callback, ) from homeassistant.helpers import condition, config_validation as cv, service, template -from homeassistant.helpers.event import async_call_later, async_track_template +from homeassistant.helpers.event import ( + TrackTemplate, + async_call_later, + async_track_template_result, +) from homeassistant.helpers.script_variables import ScriptVariables from homeassistant.helpers.trigger import ( async_initialize_triggers, @@ -355,7 +359,7 @@ class _ScriptRun: return @callback - def async_script_wait(entity_id, from_s, to_s): + def _async_script_wait(event, updates): """Handle script after template condition is true.""" self._variables["wait"] = { "remaining": to_context.remaining if to_context else delay, @@ -364,9 +368,12 @@ class _ScriptRun: done.set() to_context = None - unsub = async_track_template( - self._hass, wait_template, async_script_wait, self._variables + info = async_track_template_result( + self._hass, + [TrackTemplate(wait_template, self._variables)], + _async_script_wait, ) + unsub = info.async_remove self._changed() done = asyncio.Event() diff --git a/tests/helpers/test_event.py b/tests/helpers/test_event.py index 1b9ddc52191..9c7ddb09f85 100644 --- a/tests/helpers/test_event.py +++ b/tests/helpers/test_event.py @@ -908,6 +908,33 @@ async def test_track_template_error_can_recover(hass, caplog): assert "UndefinedError" not in caplog.text +async def test_track_template_time_change(hass, caplog): + """Test tracking template with time change.""" + template_error = Template("{{ utcnow().minute % 2 == 0 }}", hass) + calls = [] + + @ha.callback + def error_callback(entity_id, old_state, new_state): + calls.append((entity_id, old_state, new_state)) + + start_time = dt_util.utcnow() + timedelta(hours=24) + time_that_will_not_match_right_away = start_time.replace(minute=1, second=0) + with patch( + "homeassistant.util.dt.utcnow", return_value=time_that_will_not_match_right_away + ): + async_track_template(hass, template_error, error_callback) + await hass.async_block_till_done() + assert not calls + + first_time = start_time.replace(minute=2, second=0) + with patch("homeassistant.util.dt.utcnow", return_value=first_time): + async_fire_time_changed(hass, first_time) + await hass.async_block_till_done() + + assert len(calls) == 1 + assert calls[0] == (None, None, None) + + async def test_track_template_result(hass): """Test tracking template.""" specific_runs = [] diff --git a/tests/helpers/test_script.py b/tests/helpers/test_script.py index 92666335f28..c81ed681d42 100644 --- a/tests/helpers/test_script.py +++ b/tests/helpers/test_script.py @@ -780,6 +780,32 @@ async def test_wait_template_variables_in(hass): assert not script_obj.is_running +async def test_wait_template_with_utcnow(hass): + """Test the wait template with utcnow.""" + sequence = cv.SCRIPT_SCHEMA({"wait_template": "{{ utcnow().hours == 12 }}"}) + script_obj = script.Script(hass, sequence, "Test Name", "test_domain") + wait_started_flag = async_watch_for_action(script_obj, "wait") + start_time = dt_util.utcnow() + timedelta(hours=24) + + try: + hass.async_create_task(script_obj.async_run(context=Context())) + async_fire_time_changed(hass, start_time.replace(hour=5)) + assert not script_obj.is_running + async_fire_time_changed(hass, start_time.replace(hour=12)) + + await asyncio.wait_for(wait_started_flag.wait(), 1) + + assert script_obj.is_running + except (AssertionError, asyncio.TimeoutError): + await script_obj.async_stop() + raise + else: + async_fire_time_changed(hass, start_time.replace(hour=3)) + await hass.async_block_till_done() + + assert not script_obj.is_running + + @pytest.mark.parametrize("mode", ["no_timeout", "timeout_finish", "timeout_not_finish"]) @pytest.mark.parametrize("action_type", ["template", "trigger"]) async def test_wait_variables_out(hass, mode, action_type): From af1d46aa6c42f260b050dd4469326ad9a2e4a26d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 1 Jan 2021 01:40:08 -1000 Subject: [PATCH 16/39] Fix rest notify GET without params configured (#44723) --- homeassistant/components/rest/notify.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/rest/notify.py b/homeassistant/components/rest/notify.py index 3e4f97d5bc7..15b871cde5c 100644 --- a/homeassistant/components/rest/notify.py +++ b/homeassistant/components/rest/notify.py @@ -197,7 +197,7 @@ class RestNotificationService(BaseNotificationService): response = requests.get( self._resource, headers=self._headers, - params=self._params.update(data), + params={**self._params, **data} if self._params else data, timeout=10, auth=self._auth, verify=self._verify_ssl, From c60390a52aea39491ffffff1a46ad255ded58dd2 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 1 Jan 2021 08:28:20 -1000 Subject: [PATCH 17/39] Fix templates for rest notify (#44724) --- homeassistant/components/rest/notify.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/rest/notify.py b/homeassistant/components/rest/notify.py index 15b871cde5c..f15df428640 100644 --- a/homeassistant/components/rest/notify.py +++ b/homeassistant/components/rest/notify.py @@ -30,6 +30,7 @@ from homeassistant.const import ( ) import homeassistant.helpers.config_validation as cv from homeassistant.helpers.reload import setup_reload_service +from homeassistant.helpers.template import Template from . import DOMAIN, PLATFORMS @@ -56,8 +57,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend( vol.Optional(CONF_NAME): cv.string, vol.Optional(CONF_TARGET_PARAMETER_NAME): cv.string, vol.Optional(CONF_TITLE_PARAMETER_NAME): cv.string, - vol.Optional(CONF_DATA): dict, - vol.Optional(CONF_DATA_TEMPLATE): {cv.match_all: cv.template_complex}, + vol.Optional(CONF_DATA): vol.All(dict, cv.template_complex), + vol.Optional(CONF_DATA_TEMPLATE): vol.All(dict, cv.template_complex), vol.Optional(CONF_AUTHENTICATION): vol.In( [HTTP_BASIC_AUTHENTICATION, HTTP_DIGEST_AUTHENTICATION] ), @@ -155,9 +156,7 @@ class RestNotificationService(BaseNotificationService): # integrations, so just return the first target in the list. data[self._target_param_name] = kwargs[ATTR_TARGET][0] - if self._data: - data.update(self._data) - elif self._data_template: + if self._data_template or self._data: kwargs[ATTR_MESSAGE] = message def _data_template_creator(value): @@ -168,10 +167,15 @@ class RestNotificationService(BaseNotificationService): return { key: _data_template_creator(item) for key, item in value.items() } + if not isinstance(value, Template): + return value value.hass = self._hass return value.async_render(kwargs, parse_result=False) - data.update(_data_template_creator(self._data_template)) + if self._data: + data.update(_data_template_creator(self._data)) + if self._data_template: + data.update(_data_template_creator(self._data_template)) if self._method == "POST": response = requests.post( From e781e1b26c95bf21a4f95dc84a606fc6b4752f7b Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Fri, 1 Jan 2021 18:39:59 +0100 Subject: [PATCH 18/39] Bump H11 library to support non RFC line endings (#44735) --- homeassistant/package_constraints.txt | 3 +++ script/gen_requirements_all.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 7eb736c0037..6f25618871f 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -37,6 +37,9 @@ pycryptodome>=3.6.6 # Constrain urllib3 to ensure we deal with CVE-2019-11236 & CVE-2019-11324 urllib3>=1.24.3 +# Constrain H11 to ensure we get a new enough version to support non-rfc line endings +h11>=0.12.0 + # Constrain httplib2 to protect against CVE-2020-11078 httplib2>=0.18.0 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index f627346c67b..130fd2cc245 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -65,6 +65,9 @@ pycryptodome>=3.6.6 # Constrain urllib3 to ensure we deal with CVE-2019-11236 & CVE-2019-11324 urllib3>=1.24.3 +# Constrain H11 to ensure we get a new enough version to support non-rfc line endings +h11>=0.12.0 + # Constrain httplib2 to protect against CVE-2020-11078 httplib2>=0.18.0 From 79aad3f07bb485599fce2ea5db2d11a8c1567830 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Fri, 1 Jan 2021 21:14:18 +0100 Subject: [PATCH 19/39] Bumped version to 2021.1.0b1 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 2ff32fc8392..8a6d0f58937 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 2021 MINOR_VERSION = 1 -PATCH_VERSION = "0b0" +PATCH_VERSION = "0b1" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 1) From 92e354ca38d051639aa73bae15b820b6b6d6bef2 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 2 Jan 2021 01:34:10 +0100 Subject: [PATCH 20/39] Guard unbound var for DSMR (#44673) --- homeassistant/components/dsmr/sensor.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/dsmr/sensor.py b/homeassistant/components/dsmr/sensor.py index 0c53fbd6079..78cd317bb3e 100644 --- a/homeassistant/components/dsmr/sensor.py +++ b/homeassistant/components/dsmr/sensor.py @@ -197,6 +197,10 @@ async def async_setup_entry( async def connect_and_reconnect(): """Connect to DSMR and keep reconnecting until Home Assistant stops.""" + stop_listener = None + transport = None + protocol = None + while hass.state != CoreState.stopping: # Start DSMR asyncio.Protocol reader try: @@ -211,10 +215,9 @@ async def async_setup_entry( # Wait for reader to close await protocol.wait_closed() - # Unexpected disconnect - if transport: - # remove listener - stop_listener() + # Unexpected disconnect + if not hass.is_stopping: + stop_listener() transport = None protocol = None @@ -234,7 +237,7 @@ async def async_setup_entry( protocol = None except CancelledError: if stop_listener: - stop_listener() + stop_listener() # pylint: disable=not-callable if transport: transport.close() From 8da79479d3ef6dce44686dba507686407c5e3110 Mon Sep 17 00:00:00 2001 From: Maciej Bieniek Date: Mon, 4 Jan 2021 13:14:07 +0100 Subject: [PATCH 21/39] Change rest sensors update interval for Shelly Motion (#44692) * Change rest sensors update interval for Shelly Motion * Cleaning * Fix typo * Remove unnecessary parentheses --- homeassistant/components/shelly/__init__.py | 12 +++++++++++- homeassistant/components/shelly/const.py | 3 +++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/shelly/__init__.py b/homeassistant/components/shelly/__init__.py index cd08b625a5d..147d9fb950d 100644 --- a/homeassistant/components/shelly/__init__.py +++ b/homeassistant/components/shelly/__init__.py @@ -24,6 +24,7 @@ from homeassistant.helpers import ( ) from .const import ( + BATTERY_DEVICES_WITH_PERMANENT_CONNECTION, COAP, DATA_CONFIG_ENTRY, DOMAIN, @@ -241,12 +242,21 @@ class ShellyDeviceRestWrapper(update_coordinator.DataUpdateCoordinator): def __init__(self, hass, device: aioshelly.Device): """Initialize the Shelly device wrapper.""" + if ( + device.settings["device"]["type"] + in BATTERY_DEVICES_WITH_PERMANENT_CONNECTION + ): + update_interval = ( + SLEEP_PERIOD_MULTIPLIER * device.settings["coiot"]["update_period"] + ) + else: + update_interval = REST_SENSORS_UPDATE_INTERVAL super().__init__( hass, _LOGGER, name=get_device_name(device), - update_interval=timedelta(seconds=REST_SENSORS_UPDATE_INTERVAL), + update_interval=timedelta(seconds=update_interval), ) self.device = device diff --git a/homeassistant/components/shelly/const.py b/homeassistant/components/shelly/const.py index cd747466973..9f5c5b2efc7 100644 --- a/homeassistant/components/shelly/const.py +++ b/homeassistant/components/shelly/const.py @@ -32,3 +32,6 @@ INPUTS_EVENTS_DICT = { "SL": "single_long", "LS": "long_single", } + +# List of battery devices that maintain a permanent WiFi connection +BATTERY_DEVICES_WITH_PERMANENT_CONNECTION = ["SHMOS-01"] From f33c1332b9d8fa7c4b5c4017bc797ec0e02f03a6 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 3 Jan 2021 23:51:44 -1000 Subject: [PATCH 22/39] Add index to old_state_id column for postgres and older databases (#44757) * Add index to old_state_id column for older databases The schema was updated in #43610 but the index was not added on migration. * Handle postgresql missing ondelete * create index first --- homeassistant/components/recorder/migration.py | 12 +++++++++++- homeassistant/components/recorder/models.py | 2 +- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/recorder/migration.py b/homeassistant/components/recorder/migration.py index c633c114b46..4501b25385e 100644 --- a/homeassistant/components/recorder/migration.py +++ b/homeassistant/components/recorder/migration.py @@ -211,7 +211,13 @@ def _update_states_table_with_foreign_key_options(engine): inspector = reflection.Inspector.from_engine(engine) alters = [] for foreign_key in inspector.get_foreign_keys(TABLE_STATES): - if foreign_key["name"] and not foreign_key["options"]: + if foreign_key["name"] and ( + # MySQL/MariaDB will have empty options + not foreign_key["options"] + or + # Postgres will have ondelete set to None + foreign_key["options"].get("ondelete") is None + ): alters.append( { "old_fk": ForeignKeyConstraint((), (), name=foreign_key["name"]), @@ -312,6 +318,10 @@ def _apply_update(engine, new_version, old_version): _create_index(engine, "events", "ix_events_event_type_time_fired") _drop_index(engine, "events", "ix_events_event_type") elif new_version == 10: + # Now done in step 11 + pass + elif new_version == 11: + _create_index(engine, "states", "ix_states_old_state_id") _update_states_table_with_foreign_key_options(engine) else: raise ValueError(f"No schema migration defined for version {new_version}") diff --git a/homeassistant/components/recorder/models.py b/homeassistant/components/recorder/models.py index 5b37f7e3f9d..9481e954bde 100644 --- a/homeassistant/components/recorder/models.py +++ b/homeassistant/components/recorder/models.py @@ -25,7 +25,7 @@ import homeassistant.util.dt as dt_util # pylint: disable=invalid-name Base = declarative_base() -SCHEMA_VERSION = 10 +SCHEMA_VERSION = 11 _LOGGER = logging.getLogger(__name__) From 506fdc877a1dfc6b4e307b0bbb0d6c4a655cb910 Mon Sep 17 00:00:00 2001 From: Pascal Vizeli Date: Sat, 2 Jan 2021 12:07:52 +0100 Subject: [PATCH 23/39] Update docker base image 2021.01.0 (#44761) --- build.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/build.json b/build.json index 49cee1ff280..a7ce097ae84 100644 --- a/build.json +++ b/build.json @@ -1,11 +1,11 @@ { "image": "homeassistant/{arch}-homeassistant", "build_from": { - "aarch64": "homeassistant/aarch64-homeassistant-base:2020.11.2", - "armhf": "homeassistant/armhf-homeassistant-base:2020.11.2", - "armv7": "homeassistant/armv7-homeassistant-base:2020.11.2", - "amd64": "homeassistant/amd64-homeassistant-base:2020.11.2", - "i386": "homeassistant/i386-homeassistant-base:2020.11.2" + "aarch64": "homeassistant/aarch64-homeassistant-base:2021.01.0", + "armhf": "homeassistant/armhf-homeassistant-base:2021.01.0", + "armv7": "homeassistant/armv7-homeassistant-base:2021.01.0", + "amd64": "homeassistant/amd64-homeassistant-base:2021.01.0", + "i386": "homeassistant/i386-homeassistant-base:2021.01.0" }, "labels": { "io.hass.type": "core" From f42ce2b0d1ae6a077a335c071082c2b55b6c2c4a Mon Sep 17 00:00:00 2001 From: Bob Matcuk Date: Mon, 4 Jan 2021 06:33:34 -0500 Subject: [PATCH 24/39] Fix bug with blink auth flow (#44769) --- homeassistant/components/blink/config_flow.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/blink/config_flow.py b/homeassistant/components/blink/config_flow.py index d244c316483..5c77add3118 100644 --- a/homeassistant/components/blink/config_flow.py +++ b/homeassistant/components/blink/config_flow.py @@ -36,6 +36,7 @@ def _send_blink_2fa_pin(auth, pin): """Send 2FA pin to blink servers.""" blink = Blink() blink.auth = auth + blink.setup_login_ids() blink.setup_urls() return auth.send_auth_key(blink, pin) From 5f91f14a49995e936d732b5b803ff3ada99d4a05 Mon Sep 17 00:00:00 2001 From: Matthias Alphart Date: Mon, 4 Jan 2021 04:49:29 +0100 Subject: [PATCH 25/39] Fix knx.send service not accepting floats (#44802) --- homeassistant/components/knx/__init__.py | 25 ++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/knx/__init__.py b/homeassistant/components/knx/__init__.py index 1d547e895bf..31230315954 100644 --- a/homeassistant/components/knx/__init__.py +++ b/homeassistant/components/knx/__init__.py @@ -131,14 +131,23 @@ CONFIG_SCHEMA = vol.Schema( extra=vol.ALLOW_EXTRA, ) -SERVICE_KNX_SEND_SCHEMA = vol.Schema( - { - vol.Required(SERVICE_KNX_ATTR_ADDRESS): cv.string, - vol.Required(SERVICE_KNX_ATTR_PAYLOAD): vol.Any( - cv.positive_int, [cv.positive_int] - ), - vol.Optional(SERVICE_KNX_ATTR_TYPE): vol.Any(int, float, str), - } +SERVICE_KNX_SEND_SCHEMA = vol.Any( + vol.Schema( + { + vol.Required(SERVICE_KNX_ATTR_ADDRESS): cv.string, + vol.Required(SERVICE_KNX_ATTR_PAYLOAD): cv.match_all, + vol.Required(SERVICE_KNX_ATTR_TYPE): vol.Any(int, float, str), + } + ), + vol.Schema( + # without type given payload is treated as raw bytes + { + vol.Required(SERVICE_KNX_ATTR_ADDRESS): cv.string, + vol.Required(SERVICE_KNX_ATTR_PAYLOAD): vol.Any( + cv.positive_int, [cv.positive_int] + ), + } + ), ) From e4fcc9c692d737bcdaf5aa9fbb8828d12247d343 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Mon, 4 Jan 2021 13:17:44 +0100 Subject: [PATCH 26/39] Bumped version to 2021.1.0b2 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 8a6d0f58937..dff0d120c9d 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 2021 MINOR_VERSION = 1 -PATCH_VERSION = "0b1" +PATCH_VERSION = "0b2" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 1) From b3fda469cf0b28b873373c40841aef1ba345f7dc Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 4 Jan 2021 10:18:54 -1000 Subject: [PATCH 27/39] Fix zeroconf outgoing dns compression corruption for large packets (#44828) --- homeassistant/components/zeroconf/manifest.json | 2 +- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/zeroconf/manifest.json b/homeassistant/components/zeroconf/manifest.json index 753ac2a2441..654eec820c3 100644 --- a/homeassistant/components/zeroconf/manifest.json +++ b/homeassistant/components/zeroconf/manifest.json @@ -2,7 +2,7 @@ "domain": "zeroconf", "name": "Zero-configuration networking (zeroconf)", "documentation": "https://www.home-assistant.io/integrations/zeroconf", - "requirements": ["zeroconf==0.28.7"], + "requirements": ["zeroconf==0.28.8"], "dependencies": ["api"], "codeowners": ["@bdraco"], "quality_scale": "internal" diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 6f25618871f..1c9ddc70f50 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -30,7 +30,7 @@ sqlalchemy==1.3.20 voluptuous-serialize==2.4.0 voluptuous==0.12.1 yarl==1.4.2 -zeroconf==0.28.7 +zeroconf==0.28.8 pycryptodome>=3.6.6 diff --git a/requirements_all.txt b/requirements_all.txt index b238a797135..005c6e03e93 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2336,7 +2336,7 @@ zeep[async]==4.0.0 zengge==0.2 # homeassistant.components.zeroconf -zeroconf==0.28.7 +zeroconf==0.28.8 # homeassistant.components.zha zha-quirks==0.0.51 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 4c9dc5cc37e..96b7618c1d5 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1141,7 +1141,7 @@ yeelight==0.5.4 zeep[async]==4.0.0 # homeassistant.components.zeroconf -zeroconf==0.28.7 +zeroconf==0.28.8 # homeassistant.components.zha zha-quirks==0.0.51 From 9396d9db5fad7226ccd76ca0e1e7086c87118713 Mon Sep 17 00:00:00 2001 From: TheJulianJES Date: Tue, 5 Jan 2021 03:57:05 +0100 Subject: [PATCH 28/39] Implement color mode for ZHA light polling (#44829) --- homeassistant/components/zha/light.py | 35 +++++++++++++++++++-------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/zha/light.py b/homeassistant/components/zha/light.py index 4a25fa3c988..32b8a064054 100644 --- a/homeassistant/components/zha/light.py +++ b/homeassistant/components/zha/light.py @@ -1,6 +1,7 @@ """Lights on Zigbee Home Automation networks.""" from collections import Counter from datetime import timedelta +import enum import functools import itertools import logging @@ -88,6 +89,14 @@ SUPPORT_GROUP_LIGHT = ( ) +class LightColorMode(enum.IntEnum): + """ZCL light color mode enum.""" + + HS_COLOR = 0x00 + XY_COLOR = 0x01 + COLOR_TEMP = 0x02 + + async def async_setup_entry(hass, config_entry, async_add_entities): """Set up the Zigbee Home Automation light from config entry.""" entities_to_create = hass.data[DATA_ZHA][light.DOMAIN] @@ -442,6 +451,7 @@ class Light(BaseLight, ZhaEntity): self._brightness = level if self._color_channel: attributes = [ + "color_mode", "color_temperature", "current_x", "current_y", @@ -452,16 +462,21 @@ class Light(BaseLight, ZhaEntity): attributes, from_cache=False ) - color_temp = results.get("color_temperature") - if color_temp is not None: - self._color_temp = color_temp - - color_x = results.get("current_x") - color_y = results.get("current_y") - if color_x is not None and color_y is not None: - self._hs_color = color_util.color_xy_to_hs( - float(color_x / 65535), float(color_y / 65535) - ) + color_mode = results.get("color_mode") + if color_mode is not None: + if color_mode == LightColorMode.COLOR_TEMP: + color_temp = results.get("color_temperature") + if color_temp is not None and color_mode: + self._color_temp = color_temp + self._hs_color = None + else: + color_x = results.get("current_x") + color_y = results.get("current_y") + if color_x is not None and color_y is not None: + self._hs_color = color_util.color_xy_to_hs( + float(color_x / 65535), float(color_y / 65535) + ) + self._color_temp = None color_loop_active = results.get("color_loop_active") if color_loop_active is not None: From e4a84bb1c361fa662a89ad5b1893df1b6c87e5ce Mon Sep 17 00:00:00 2001 From: Andre Lengwenus Date: Tue, 5 Jan 2021 10:01:34 +0100 Subject: [PATCH 29/39] Bump pypck to 0.7.8 (#44834) --- homeassistant/components/lcn/__init__.py | 3 ++- homeassistant/components/lcn/binary_sensor.py | 17 ++++++++++------- homeassistant/components/lcn/climate.py | 5 +++-- homeassistant/components/lcn/cover.py | 3 ++- homeassistant/components/lcn/light.py | 6 ++++-- homeassistant/components/lcn/manifest.json | 8 ++++++-- homeassistant/components/lcn/sensor.py | 6 ++++-- homeassistant/components/lcn/switch.py | 6 ++++-- requirements_all.txt | 2 +- 9 files changed, 36 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/lcn/__init__.py b/homeassistant/components/lcn/__init__.py index 72f11b7b005..cc1e47d71fc 100644 --- a/homeassistant/components/lcn/__init__.py +++ b/homeassistant/components/lcn/__init__.py @@ -139,7 +139,8 @@ class LcnEntity(Entity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" - self.device_connection.register_for_inputs(self.input_received) + if not self.device_connection.is_group: + self.device_connection.register_for_inputs(self.input_received) @property def name(self): diff --git a/homeassistant/components/lcn/binary_sensor.py b/homeassistant/components/lcn/binary_sensor.py index 5d712045c93..415668f5924 100644 --- a/homeassistant/components/lcn/binary_sensor.py +++ b/homeassistant/components/lcn/binary_sensor.py @@ -50,9 +50,10 @@ class LcnRegulatorLockSensor(LcnEntity, BinarySensorEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - await self.device_connection.activate_status_request_handler( - self.setpoint_variable - ) + if not self.device_connection.is_group: + await self.device_connection.activate_status_request_handler( + self.setpoint_variable + ) @property def is_on(self): @@ -85,9 +86,10 @@ class LcnBinarySensor(LcnEntity, BinarySensorEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - await self.device_connection.activate_status_request_handler( - self.bin_sensor_port - ) + if not self.device_connection.is_group: + await self.device_connection.activate_status_request_handler( + self.bin_sensor_port + ) @property def is_on(self): @@ -116,7 +118,8 @@ class LcnLockKeysSensor(LcnEntity, BinarySensorEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - await self.device_connection.activate_status_request_handler(self.source) + if not self.device_connection.is_group: + await self.device_connection.activate_status_request_handler(self.source) @property def is_on(self): diff --git a/homeassistant/components/lcn/climate.py b/homeassistant/components/lcn/climate.py index e3eb92a426f..ece3994f651 100644 --- a/homeassistant/components/lcn/climate.py +++ b/homeassistant/components/lcn/climate.py @@ -63,8 +63,9 @@ class LcnClimate(LcnEntity, ClimateEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - await self.device_connection.activate_status_request_handler(self.variable) - await self.device_connection.activate_status_request_handler(self.setpoint) + if not self.device_connection.is_group: + await self.device_connection.activate_status_request_handler(self.variable) + await self.device_connection.activate_status_request_handler(self.setpoint) @property def supported_features(self): diff --git a/homeassistant/components/lcn/cover.py b/homeassistant/components/lcn/cover.py index c5e407573ba..3d7c2a06a3b 100644 --- a/homeassistant/components/lcn/cover.py +++ b/homeassistant/components/lcn/cover.py @@ -161,7 +161,8 @@ class LcnRelayCover(LcnEntity, CoverEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - await self.device_connection.activate_status_request_handler(self.motor) + if not self.device_connection.is_group: + await self.device_connection.activate_status_request_handler(self.motor) @property def is_closed(self): diff --git a/homeassistant/components/lcn/light.py b/homeassistant/components/lcn/light.py index c6ef895b7df..5242ed1cc59 100644 --- a/homeassistant/components/lcn/light.py +++ b/homeassistant/components/lcn/light.py @@ -68,7 +68,8 @@ class LcnOutputLight(LcnEntity, LightEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - await self.device_connection.activate_status_request_handler(self.output) + if not self.device_connection.is_group: + await self.device_connection.activate_status_request_handler(self.output) @property def supported_features(self): @@ -155,7 +156,8 @@ class LcnRelayLight(LcnEntity, LightEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - await self.device_connection.activate_status_request_handler(self.output) + if not self.device_connection.is_group: + await self.device_connection.activate_status_request_handler(self.output) @property def is_on(self): diff --git a/homeassistant/components/lcn/manifest.json b/homeassistant/components/lcn/manifest.json index f07c4d9c646..919051d7e7a 100644 --- a/homeassistant/components/lcn/manifest.json +++ b/homeassistant/components/lcn/manifest.json @@ -2,6 +2,10 @@ "domain": "lcn", "name": "LCN", "documentation": "https://www.home-assistant.io/integrations/lcn", - "requirements": ["pypck==0.7.7"], - "codeowners": ["@alengwenus"] + "requirements": [ + "pypck==0.7.8" + ], + "codeowners": [ + "@alengwenus" + ] } diff --git a/homeassistant/components/lcn/sensor.py b/homeassistant/components/lcn/sensor.py index 26b54def974..4d4be5e1259 100644 --- a/homeassistant/components/lcn/sensor.py +++ b/homeassistant/components/lcn/sensor.py @@ -57,7 +57,8 @@ class LcnVariableSensor(LcnEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - await self.device_connection.activate_status_request_handler(self.variable) + if not self.device_connection.is_group: + await self.device_connection.activate_status_request_handler(self.variable) @property def state(self): @@ -98,7 +99,8 @@ class LcnLedLogicSensor(LcnEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - await self.device_connection.activate_status_request_handler(self.source) + if not self.device_connection.is_group: + await self.device_connection.activate_status_request_handler(self.source) @property def state(self): diff --git a/homeassistant/components/lcn/switch.py b/homeassistant/components/lcn/switch.py index 5891629627e..6f9cc25db99 100644 --- a/homeassistant/components/lcn/switch.py +++ b/homeassistant/components/lcn/switch.py @@ -50,7 +50,8 @@ class LcnOutputSwitch(LcnEntity, SwitchEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - await self.device_connection.activate_status_request_handler(self.output) + if not self.device_connection.is_group: + await self.device_connection.activate_status_request_handler(self.output) @property def is_on(self): @@ -97,7 +98,8 @@ class LcnRelaySwitch(LcnEntity, SwitchEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - await self.device_connection.activate_status_request_handler(self.output) + if not self.device_connection.is_group: + await self.device_connection.activate_status_request_handler(self.output) @property def is_on(self): diff --git a/requirements_all.txt b/requirements_all.txt index 005c6e03e93..76641ab9f7a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1604,7 +1604,7 @@ pyownet==0.10.0.post1 pypca==0.0.7 # homeassistant.components.lcn -pypck==0.7.7 +pypck==0.7.8 # homeassistant.components.pjlink pypjlink2==1.2.1 From 0b8251d9a1d14130b5adfab96c3c870e76c67cb6 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Tue, 5 Jan 2021 17:35:28 +0100 Subject: [PATCH 30/39] Make Alexa custom ID unique (#44839) * Make Alexa custom ID unique * Lint * Lint --- homeassistant/components/alexa/config.py | 5 +++++ homeassistant/components/alexa/entities.py | 2 +- .../components/alexa/smart_home_http.py | 5 +++++ .../components/cloud/alexa_config.py | 19 ++++++++++++++--- homeassistant/components/cloud/client.py | 16 ++++++++------ .../components/cloud/google_config.py | 2 +- homeassistant/components/cloud/http_api.py | 9 +++++--- tests/components/alexa/__init__.py | 7 ++++++- tests/components/alexa/test_entities.py | 21 +++++++++++++++++++ tests/components/cloud/test_alexa_config.py | 17 ++++++++++----- 10 files changed, 83 insertions(+), 20 deletions(-) diff --git a/homeassistant/components/alexa/config.py b/homeassistant/components/alexa/config.py index 7d3a3994ace..cc5c604dc8c 100644 --- a/homeassistant/components/alexa/config.py +++ b/homeassistant/components/alexa/config.py @@ -45,6 +45,11 @@ class AbstractConfig(ABC): """Return if proactive mode is enabled.""" return self._unsub_proactive_report is not None + @callback + @abstractmethod + def user_identifier(self): + """Return an identifier for the user that represents this config.""" + async def async_enable_proactive_mode(self): """Enable proactive mode.""" if self._unsub_proactive_report is None: diff --git a/homeassistant/components/alexa/entities.py b/homeassistant/components/alexa/entities.py index 574ba6b8ba7..c05d9641b9a 100644 --- a/homeassistant/components/alexa/entities.py +++ b/homeassistant/components/alexa/entities.py @@ -329,7 +329,7 @@ class AlexaEntity: "manufacturer": "Home Assistant", "model": self.entity.domain, "softwareVersion": __version__, - "customIdentifier": self.entity_id, + "customIdentifier": f"{self.config.user_identifier()}-{self.entity_id}", }, } diff --git a/homeassistant/components/alexa/smart_home_http.py b/homeassistant/components/alexa/smart_home_http.py index 41ebfb340eb..41738c824fb 100644 --- a/homeassistant/components/alexa/smart_home_http.py +++ b/homeassistant/components/alexa/smart_home_http.py @@ -53,6 +53,11 @@ class AlexaConfig(AbstractConfig): """Return config locale.""" return self._config.get(CONF_LOCALE) + @core.callback + def user_identifier(self): + """Return an identifier for the user that represents this config.""" + return "" + def should_expose(self, entity_id): """If an entity should be exposed.""" return self._config[CONF_FILTER](entity_id) diff --git a/homeassistant/components/cloud/alexa_config.py b/homeassistant/components/cloud/alexa_config.py index 1bb74053ea4..7abbefe85ff 100644 --- a/homeassistant/components/cloud/alexa_config.py +++ b/homeassistant/components/cloud/alexa_config.py @@ -5,7 +5,7 @@ import logging import aiohttp import async_timeout -from hass_nabucasa import cloud_api +from hass_nabucasa import Cloud, cloud_api from homeassistant.components.alexa import ( config as alexa_config, @@ -14,7 +14,7 @@ from homeassistant.components.alexa import ( state_report as alexa_state_report, ) from homeassistant.const import CLOUD_NEVER_EXPOSED_ENTITIES, HTTP_BAD_REQUEST -from homeassistant.core import callback, split_entity_id +from homeassistant.core import HomeAssistant, callback, split_entity_id from homeassistant.helpers import entity_registry from homeassistant.helpers.event import async_call_later from homeassistant.util.dt import utcnow @@ -32,10 +32,18 @@ SYNC_DELAY = 1 class AlexaConfig(alexa_config.AbstractConfig): """Alexa Configuration.""" - def __init__(self, hass, config, prefs: CloudPreferences, cloud): + def __init__( + self, + hass: HomeAssistant, + config: dict, + cloud_user: str, + prefs: CloudPreferences, + cloud: Cloud, + ): """Initialize the Alexa config.""" super().__init__(hass) self._config = config + self._cloud_user = cloud_user self._prefs = prefs self._cloud = cloud self._token = None @@ -85,6 +93,11 @@ class AlexaConfig(alexa_config.AbstractConfig): """Return entity config.""" return self._config.get(CONF_ENTITY_CONFIG) or {} + @callback + def user_identifier(self): + """Return an identifier for the user that represents this config.""" + return self._cloud_user + def should_expose(self, entity_id): """If an entity should be exposed.""" if entity_id in CLOUD_NEVER_EXPOSED_ENTITIES: diff --git a/homeassistant/components/cloud/client.py b/homeassistant/components/cloud/client.py index 2a2d383f362..155a39e49b6 100644 --- a/homeassistant/components/cloud/client.py +++ b/homeassistant/components/cloud/client.py @@ -79,13 +79,15 @@ class CloudClient(Interface): """Return true if we want start a remote connection.""" return self._prefs.remote_enabled - @property - def alexa_config(self) -> alexa_config.AlexaConfig: + async def get_alexa_config(self) -> alexa_config.AlexaConfig: """Return Alexa config.""" if self._alexa_config is None: assert self.cloud is not None + + cloud_user = await self._prefs.get_cloud_user() + self._alexa_config = alexa_config.AlexaConfig( - self._hass, self.alexa_user_config, self._prefs, self.cloud + self._hass, self.alexa_user_config, cloud_user, self._prefs, self.cloud ) return self._alexa_config @@ -110,8 +112,9 @@ class CloudClient(Interface): async def enable_alexa(_): """Enable Alexa.""" + aconf = await self.get_alexa_config() try: - await self.alexa_config.async_enable_proactive_mode() + await aconf.async_enable_proactive_mode() except aiohttp.ClientError as err: # If no internet available yet if self._hass.is_running: logging.getLogger(__package__).warning( @@ -133,7 +136,7 @@ class CloudClient(Interface): tasks = [] - if self.alexa_config.enabled and self.alexa_config.should_report_state: + if self._prefs.alexa_enabled and self._prefs.alexa_report_state: tasks.append(enable_alexa) if self._prefs.google_enabled: @@ -164,9 +167,10 @@ class CloudClient(Interface): async def async_alexa_message(self, payload: Dict[Any, Any]) -> Dict[Any, Any]: """Process cloud alexa message to client.""" cloud_user = await self._prefs.get_cloud_user() + aconfig = await self.get_alexa_config() return await alexa_sh.async_handle_message( self._hass, - self.alexa_config, + aconfig, payload, context=Context(user_id=cloud_user), enabled=self._prefs.alexa_enabled, diff --git a/homeassistant/components/cloud/google_config.py b/homeassistant/components/cloud/google_config.py index 4b5891359b6..2ac0bc40252 100644 --- a/homeassistant/components/cloud/google_config.py +++ b/homeassistant/components/cloud/google_config.py @@ -28,7 +28,7 @@ _LOGGER = logging.getLogger(__name__) class CloudGoogleConfig(AbstractConfig): """HA Cloud Configuration for Google Assistant.""" - def __init__(self, hass, config, cloud_user, prefs: CloudPreferences, cloud): + def __init__(self, hass, config, cloud_user: str, prefs: CloudPreferences, cloud): """Initialize the Google config.""" super().__init__(hass) self._config = config diff --git a/homeassistant/components/cloud/http_api.py b/homeassistant/components/cloud/http_api.py index 3075f6a3f9d..a4d8b84b1ad 100644 --- a/homeassistant/components/cloud/http_api.py +++ b/homeassistant/components/cloud/http_api.py @@ -397,9 +397,10 @@ async def websocket_update_prefs(hass, connection, msg): # If we turn alexa linking on, validate that we can fetch access token if changes.get(PREF_ALEXA_REPORT_STATE): + alexa_config = await cloud.client.get_alexa_config() try: with async_timeout.timeout(10): - await cloud.client.alexa_config.async_get_access_token() + await alexa_config.async_get_access_token() except asyncio.TimeoutError: connection.send_error( msg["id"], "alexa_timeout", "Timeout validating Alexa access token." @@ -555,7 +556,8 @@ async def google_assistant_update(hass, connection, msg): async def alexa_list(hass, connection, msg): """List all alexa entities.""" cloud = hass.data[DOMAIN] - entities = alexa_entities.async_get_entities(hass, cloud.client.alexa_config) + alexa_config = await cloud.client.get_alexa_config() + entities = alexa_entities.async_get_entities(hass, alexa_config) result = [] @@ -603,10 +605,11 @@ async def alexa_update(hass, connection, msg): async def alexa_sync(hass, connection, msg): """Sync with Alexa.""" cloud = hass.data[DOMAIN] + alexa_config = await cloud.client.get_alexa_config() with async_timeout.timeout(10): try: - success = await cloud.client.alexa_config.async_sync_entities() + success = await alexa_config.async_sync_entities() except alexa_errors.NoTokenAvailable: connection.send_error( msg["id"], diff --git a/tests/components/alexa/__init__.py b/tests/components/alexa/__init__.py index d9c1a5a40cd..bc007fefb84 100644 --- a/tests/components/alexa/__init__.py +++ b/tests/components/alexa/__init__.py @@ -2,7 +2,7 @@ from uuid import uuid4 from homeassistant.components.alexa import config, smart_home -from homeassistant.core import Context +from homeassistant.core import Context, callback from tests.common import async_mock_service @@ -37,6 +37,11 @@ class MockConfig(config.AbstractConfig): """Return config locale.""" return TEST_LOCALE + @callback + def user_identifier(self): + """Return an identifier for the user that represents this config.""" + return "mock-user-id" + def should_expose(self, entity_id): """If an entity should be exposed.""" return True diff --git a/tests/components/alexa/test_entities.py b/tests/components/alexa/test_entities.py index 6b48c313fcc..45991375ba0 100644 --- a/tests/components/alexa/test_entities.py +++ b/tests/components/alexa/test_entities.py @@ -1,5 +1,6 @@ """Test Alexa entity representation.""" from homeassistant.components.alexa import smart_home +from homeassistant.const import __version__ from . import DEFAULT_CONFIG, get_new_request @@ -20,6 +21,26 @@ async def test_unsupported_domain(hass): assert not msg["payload"]["endpoints"] +async def test_serialize_discovery(hass): + """Test we handle an interface raising unexpectedly during serialize discovery.""" + request = get_new_request("Alexa.Discovery", "Discover") + + hass.states.async_set("switch.bla", "on", {"friendly_name": "Boop Woz"}) + + msg = await smart_home.async_handle_message(hass, DEFAULT_CONFIG, request) + + assert "event" in msg + msg = msg["event"] + endpoint = msg["payload"]["endpoints"][0] + + assert endpoint["additionalAttributes"] == { + "manufacturer": "Home Assistant", + "model": "switch", + "softwareVersion": __version__, + "customIdentifier": "mock-user-id-switch.bla", + } + + async def test_serialize_discovery_recovers(hass, caplog): """Test we handle an interface raising unexpectedly during serialize discovery.""" request = get_new_request("Alexa.Discovery", "Discover") diff --git a/tests/components/cloud/test_alexa_config.py b/tests/components/cloud/test_alexa_config.py index e54a5dcde01..ce761952921 100644 --- a/tests/components/cloud/test_alexa_config.py +++ b/tests/components/cloud/test_alexa_config.py @@ -16,7 +16,9 @@ async def test_alexa_config_expose_entity_prefs(hass, cloud_prefs): alexa_entity_configs={"light.kitchen": entity_conf}, alexa_default_expose=["light"], ) - conf = alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), cloud_prefs, None) + conf = alexa_config.AlexaConfig( + hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, None + ) assert not conf.should_expose("light.kitchen") entity_conf["should_expose"] = True @@ -33,7 +35,9 @@ async def test_alexa_config_expose_entity_prefs(hass, cloud_prefs): async def test_alexa_config_report_state(hass, cloud_prefs): """Test Alexa config should expose using prefs.""" - conf = alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), cloud_prefs, None) + conf = alexa_config.AlexaConfig( + hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, None + ) assert cloud_prefs.alexa_report_state is False assert conf.should_report_state is False @@ -68,6 +72,7 @@ async def test_alexa_config_invalidate_token(hass, cloud_prefs, aioclient_mock): conf = alexa_config.AlexaConfig( hass, ALEXA_SCHEMA({}), + "mock-user-id", cloud_prefs, Mock( alexa_access_token_url="http://example/alexa_token", @@ -114,7 +119,7 @@ def patch_sync_helper(): async def test_alexa_update_expose_trigger_sync(hass, cloud_prefs): """Test Alexa config responds to updating exposed entities.""" - alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), cloud_prefs, None) + alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, None) with patch_sync_helper() as (to_update, to_remove): await cloud_prefs.async_update_alexa_entity_config( @@ -147,7 +152,9 @@ async def test_alexa_update_expose_trigger_sync(hass, cloud_prefs): async def test_alexa_entity_registry_sync(hass, mock_cloud_login, cloud_prefs): """Test Alexa config responds to entity registry.""" - alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), cloud_prefs, hass.data["cloud"]) + alexa_config.AlexaConfig( + hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, hass.data["cloud"] + ) with patch_sync_helper() as (to_update, to_remove): hass.bus.async_fire( @@ -197,7 +204,7 @@ async def test_alexa_entity_registry_sync(hass, mock_cloud_login, cloud_prefs): async def test_alexa_update_report_state(hass, cloud_prefs): """Test Alexa config responds to reporting state.""" - alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), cloud_prefs, None) + alexa_config.AlexaConfig(hass, ALEXA_SCHEMA({}), "mock-user-id", cloud_prefs, None) with patch( "homeassistant.components.cloud.alexa_config.AlexaConfig.async_sync_entities", From fdce5878c657e5ef7546f9ec9290da0a8bac55e8 Mon Sep 17 00:00:00 2001 From: Finbarr Brady Date: Tue, 5 Jan 2021 16:22:25 +0000 Subject: [PATCH 31/39] =?UTF-8?q?Bump=20openwebifpy=20version:=203.1.6=20?= =?UTF-8?q?=E2=86=92=203.2.7=20(#44847)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- homeassistant/components/enigma2/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/enigma2/manifest.json b/homeassistant/components/enigma2/manifest.json index fe461654ecd..da6765368ae 100644 --- a/homeassistant/components/enigma2/manifest.json +++ b/homeassistant/components/enigma2/manifest.json @@ -2,6 +2,6 @@ "domain": "enigma2", "name": "Enigma2 (OpenWebif)", "documentation": "https://www.home-assistant.io/integrations/enigma2", - "requirements": ["openwebifpy==3.1.6"], + "requirements": ["openwebifpy==3.2.7"], "codeowners": ["@fbradyirl"] } diff --git a/requirements_all.txt b/requirements_all.txt index 76641ab9f7a..2486c7317b1 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1058,7 +1058,7 @@ openhomedevice==0.7.2 opensensemap-api==0.1.5 # homeassistant.components.enigma2 -openwebifpy==3.1.6 +openwebifpy==3.2.7 # homeassistant.components.luci openwrt-luci-rpc==1.1.6 From 2ee50a4d547c6e603ca457754a443c34b45e22fd Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 5 Jan 2021 20:55:17 +0100 Subject: [PATCH 32/39] Fix Canary doing I/O in event loop (#44854) --- homeassistant/components/canary/camera.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/canary/camera.py b/homeassistant/components/canary/camera.py index fd2f08c1488..0493a964cc4 100644 --- a/homeassistant/components/canary/camera.py +++ b/homeassistant/components/canary/camera.py @@ -127,11 +127,14 @@ class CanaryCamera(CoordinatorEntity, Camera): async def async_camera_image(self): """Return a still image response from the camera.""" await self.hass.async_add_executor_job(self.renew_live_stream_session) + live_stream_url = await self.hass.async_add_executor_job( + getattr, self._live_stream_session, "live_stream_url" + ) ffmpeg = ImageFrame(self._ffmpeg.binary) image = await asyncio.shield( ffmpeg.get_image( - self._live_stream_session.live_stream_url, + live_stream_url, output_format=IMAGE_JPEG, extra_cmd=self._ffmpeg_arguments, ) From 587676f436ea7960c5efd479d4a9291679e0836e Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Tue, 5 Jan 2021 23:27:35 +0100 Subject: [PATCH 33/39] Update frontend to 20201229.1 (#44861) --- homeassistant/components/frontend/manifest.json | 2 +- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/frontend/manifest.json b/homeassistant/components/frontend/manifest.json index abe98b98c8c..241b07fd591 100644 --- a/homeassistant/components/frontend/manifest.json +++ b/homeassistant/components/frontend/manifest.json @@ -2,7 +2,7 @@ "domain": "frontend", "name": "Home Assistant Frontend", "documentation": "https://www.home-assistant.io/integrations/frontend", - "requirements": ["home-assistant-frontend==20201229.0"], + "requirements": ["home-assistant-frontend==20201229.1"], "dependencies": [ "api", "auth", diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 1c9ddc70f50..11e7dd89918 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -13,7 +13,7 @@ defusedxml==0.6.0 distro==1.5.0 emoji==0.5.4 hass-nabucasa==0.39.0 -home-assistant-frontend==20201229.0 +home-assistant-frontend==20201229.1 httpx==0.16.1 importlib-metadata==1.6.0;python_version<'3.8' jinja2>=2.11.2 diff --git a/requirements_all.txt b/requirements_all.txt index 2486c7317b1..0cf2451432e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -762,7 +762,7 @@ hole==0.5.1 holidays==0.10.4 # homeassistant.components.frontend -home-assistant-frontend==20201229.0 +home-assistant-frontend==20201229.1 # homeassistant.components.zwave homeassistant-pyozw==0.1.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 96b7618c1d5..70249117ee3 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -394,7 +394,7 @@ hole==0.5.1 holidays==0.10.4 # homeassistant.components.frontend -home-assistant-frontend==20201229.0 +home-assistant-frontend==20201229.1 # homeassistant.components.zwave homeassistant-pyozw==0.1.10 From c258c2653f7c6b1b7cfff0044b1ef5d694f10863 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 5 Jan 2021 23:31:18 +0100 Subject: [PATCH 34/39] Bumped version to 2021.1.0b3 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index dff0d120c9d..52254ad68e9 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 2021 MINOR_VERSION = 1 -PATCH_VERSION = "0b2" +PATCH_VERSION = "0b3" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 1) From 88eac0be85da203eefffd1e8e3c1102796a75c84 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Thu, 31 Dec 2020 01:18:58 +0100 Subject: [PATCH 35/39] Bump pytradfri to 7.0.6 (#44661) --- homeassistant/components/tradfri/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/tradfri/manifest.json b/homeassistant/components/tradfri/manifest.json index 57f58f05993..5c6bf76a169 100644 --- a/homeassistant/components/tradfri/manifest.json +++ b/homeassistant/components/tradfri/manifest.json @@ -3,7 +3,7 @@ "name": "IKEA TRÅDFRI", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/tradfri", - "requirements": ["pytradfri[async]==7.0.5"], + "requirements": ["pytradfri[async]==7.0.6"], "homekit": { "models": ["TRADFRI"] }, diff --git a/requirements_all.txt b/requirements_all.txt index 0cf2451432e..4d1bd88a62e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1852,7 +1852,7 @@ pytraccar==0.9.0 pytrackr==0.0.5 # homeassistant.components.tradfri -pytradfri[async]==7.0.5 +pytradfri[async]==7.0.6 # homeassistant.components.trafikverket_train # homeassistant.components.trafikverket_weatherstation diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 70249117ee3..278822f3c07 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -912,7 +912,7 @@ pytile==4.0.0 pytraccar==0.9.0 # homeassistant.components.tradfri -pytradfri[async]==7.0.5 +pytradfri[async]==7.0.6 # homeassistant.components.vera pyvera==0.3.11 From b6d323b0082a39540319e72fd4f135e5fb5d4b37 Mon Sep 17 00:00:00 2001 From: jjlawren Date: Wed, 6 Jan 2021 07:12:19 -0600 Subject: [PATCH 36/39] Fix Plex media summary attribute (#44863) --- homeassistant/components/plex/media_player.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/plex/media_player.py b/homeassistant/components/plex/media_player.py index 4d765cc0508..24e37216b70 100644 --- a/homeassistant/components/plex/media_player.py +++ b/homeassistant/components/plex/media_player.py @@ -518,7 +518,7 @@ class PlexMediaPlayer(MediaPlayerEntity): "media_content_rating", "media_library_title", "player_source", - "summary", + "media_summary", "username", ]: value = getattr(self, attr, None) From 9d03b56c5c05ce28487d1e98a3a69dc1f410d82c Mon Sep 17 00:00:00 2001 From: treylok Date: Wed, 6 Jan 2021 06:40:24 -0600 Subject: [PATCH 37/39] Bump python-ecobee-api to 0.2.8 (#44866) --- homeassistant/components/ecobee/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/ecobee/manifest.json b/homeassistant/components/ecobee/manifest.json index 38d6b4577b6..040744b27aa 100644 --- a/homeassistant/components/ecobee/manifest.json +++ b/homeassistant/components/ecobee/manifest.json @@ -3,6 +3,6 @@ "name": "ecobee", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/ecobee", - "requirements": ["python-ecobee-api==0.2.7"], + "requirements": ["python-ecobee-api==0.2.8"], "codeowners": ["@marthoc"] } diff --git a/requirements_all.txt b/requirements_all.txt index 4d1bd88a62e..cc6cd185743 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1738,7 +1738,7 @@ python-clementine-remote==1.0.1 python-digitalocean==1.13.2 # homeassistant.components.ecobee -python-ecobee-api==0.2.7 +python-ecobee-api==0.2.8 # homeassistant.components.eq3btsmart # python-eq3bt==0.1.11 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 278822f3c07..466c072f4a9 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -870,7 +870,7 @@ pysqueezebox==0.5.5 pysyncthru==0.7.0 # homeassistant.components.ecobee -python-ecobee-api==0.2.7 +python-ecobee-api==0.2.8 # homeassistant.components.darksky python-forecastio==1.4.0 From 9c478e8de70a6be7fb5f76320bcc9200ee737e1c Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Wed, 6 Jan 2021 16:03:04 +0100 Subject: [PATCH 38/39] Bumped version to 2021.1.0 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 52254ad68e9..4baa7e7bc3a 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 2021 MINOR_VERSION = 1 -PATCH_VERSION = "0b3" +PATCH_VERSION = "0" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 1) From 57d119a7fe4296a1bb06e380d76fd8f97ddef443 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Wed, 6 Jan 2021 16:47:02 +0100 Subject: [PATCH 39/39] Revert "Bump pypck to 0.7.8" (#44884) This reverts commit addafd517f3617071468b2f4ae3fa31f655a9ed2. --- homeassistant/components/lcn/__init__.py | 3 +-- homeassistant/components/lcn/binary_sensor.py | 17 +++++++---------- homeassistant/components/lcn/climate.py | 5 ++--- homeassistant/components/lcn/cover.py | 3 +-- homeassistant/components/lcn/light.py | 6 ++---- homeassistant/components/lcn/manifest.json | 8 ++------ homeassistant/components/lcn/sensor.py | 6 ++---- homeassistant/components/lcn/switch.py | 6 ++---- requirements_all.txt | 2 +- 9 files changed, 20 insertions(+), 36 deletions(-) diff --git a/homeassistant/components/lcn/__init__.py b/homeassistant/components/lcn/__init__.py index cc1e47d71fc..72f11b7b005 100644 --- a/homeassistant/components/lcn/__init__.py +++ b/homeassistant/components/lcn/__init__.py @@ -139,8 +139,7 @@ class LcnEntity(Entity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" - if not self.device_connection.is_group: - self.device_connection.register_for_inputs(self.input_received) + self.device_connection.register_for_inputs(self.input_received) @property def name(self): diff --git a/homeassistant/components/lcn/binary_sensor.py b/homeassistant/components/lcn/binary_sensor.py index 415668f5924..5d712045c93 100644 --- a/homeassistant/components/lcn/binary_sensor.py +++ b/homeassistant/components/lcn/binary_sensor.py @@ -50,10 +50,9 @@ class LcnRegulatorLockSensor(LcnEntity, BinarySensorEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - if not self.device_connection.is_group: - await self.device_connection.activate_status_request_handler( - self.setpoint_variable - ) + await self.device_connection.activate_status_request_handler( + self.setpoint_variable + ) @property def is_on(self): @@ -86,10 +85,9 @@ class LcnBinarySensor(LcnEntity, BinarySensorEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - if not self.device_connection.is_group: - await self.device_connection.activate_status_request_handler( - self.bin_sensor_port - ) + await self.device_connection.activate_status_request_handler( + self.bin_sensor_port + ) @property def is_on(self): @@ -118,8 +116,7 @@ class LcnLockKeysSensor(LcnEntity, BinarySensorEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - if not self.device_connection.is_group: - await self.device_connection.activate_status_request_handler(self.source) + await self.device_connection.activate_status_request_handler(self.source) @property def is_on(self): diff --git a/homeassistant/components/lcn/climate.py b/homeassistant/components/lcn/climate.py index ece3994f651..e3eb92a426f 100644 --- a/homeassistant/components/lcn/climate.py +++ b/homeassistant/components/lcn/climate.py @@ -63,9 +63,8 @@ class LcnClimate(LcnEntity, ClimateEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - if not self.device_connection.is_group: - await self.device_connection.activate_status_request_handler(self.variable) - await self.device_connection.activate_status_request_handler(self.setpoint) + await self.device_connection.activate_status_request_handler(self.variable) + await self.device_connection.activate_status_request_handler(self.setpoint) @property def supported_features(self): diff --git a/homeassistant/components/lcn/cover.py b/homeassistant/components/lcn/cover.py index 3d7c2a06a3b..c5e407573ba 100644 --- a/homeassistant/components/lcn/cover.py +++ b/homeassistant/components/lcn/cover.py @@ -161,8 +161,7 @@ class LcnRelayCover(LcnEntity, CoverEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - if not self.device_connection.is_group: - await self.device_connection.activate_status_request_handler(self.motor) + await self.device_connection.activate_status_request_handler(self.motor) @property def is_closed(self): diff --git a/homeassistant/components/lcn/light.py b/homeassistant/components/lcn/light.py index 5242ed1cc59..c6ef895b7df 100644 --- a/homeassistant/components/lcn/light.py +++ b/homeassistant/components/lcn/light.py @@ -68,8 +68,7 @@ class LcnOutputLight(LcnEntity, LightEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - if not self.device_connection.is_group: - await self.device_connection.activate_status_request_handler(self.output) + await self.device_connection.activate_status_request_handler(self.output) @property def supported_features(self): @@ -156,8 +155,7 @@ class LcnRelayLight(LcnEntity, LightEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - if not self.device_connection.is_group: - await self.device_connection.activate_status_request_handler(self.output) + await self.device_connection.activate_status_request_handler(self.output) @property def is_on(self): diff --git a/homeassistant/components/lcn/manifest.json b/homeassistant/components/lcn/manifest.json index 919051d7e7a..f07c4d9c646 100644 --- a/homeassistant/components/lcn/manifest.json +++ b/homeassistant/components/lcn/manifest.json @@ -2,10 +2,6 @@ "domain": "lcn", "name": "LCN", "documentation": "https://www.home-assistant.io/integrations/lcn", - "requirements": [ - "pypck==0.7.8" - ], - "codeowners": [ - "@alengwenus" - ] + "requirements": ["pypck==0.7.7"], + "codeowners": ["@alengwenus"] } diff --git a/homeassistant/components/lcn/sensor.py b/homeassistant/components/lcn/sensor.py index 4d4be5e1259..26b54def974 100644 --- a/homeassistant/components/lcn/sensor.py +++ b/homeassistant/components/lcn/sensor.py @@ -57,8 +57,7 @@ class LcnVariableSensor(LcnEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - if not self.device_connection.is_group: - await self.device_connection.activate_status_request_handler(self.variable) + await self.device_connection.activate_status_request_handler(self.variable) @property def state(self): @@ -99,8 +98,7 @@ class LcnLedLogicSensor(LcnEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - if not self.device_connection.is_group: - await self.device_connection.activate_status_request_handler(self.source) + await self.device_connection.activate_status_request_handler(self.source) @property def state(self): diff --git a/homeassistant/components/lcn/switch.py b/homeassistant/components/lcn/switch.py index 6f9cc25db99..5891629627e 100644 --- a/homeassistant/components/lcn/switch.py +++ b/homeassistant/components/lcn/switch.py @@ -50,8 +50,7 @@ class LcnOutputSwitch(LcnEntity, SwitchEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - if not self.device_connection.is_group: - await self.device_connection.activate_status_request_handler(self.output) + await self.device_connection.activate_status_request_handler(self.output) @property def is_on(self): @@ -98,8 +97,7 @@ class LcnRelaySwitch(LcnEntity, SwitchEntity): async def async_added_to_hass(self): """Run when entity about to be added to hass.""" await super().async_added_to_hass() - if not self.device_connection.is_group: - await self.device_connection.activate_status_request_handler(self.output) + await self.device_connection.activate_status_request_handler(self.output) @property def is_on(self): diff --git a/requirements_all.txt b/requirements_all.txt index cc6cd185743..8e3b891c2e7 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1604,7 +1604,7 @@ pyownet==0.10.0.post1 pypca==0.0.7 # homeassistant.components.lcn -pypck==0.7.8 +pypck==0.7.7 # homeassistant.components.pjlink pypjlink2==1.2.1