From 217e3c44d6aff05fb187ae8db574eff5546cbb52 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sun, 13 Dec 2020 13:00:53 -0600 Subject: [PATCH 01/16] Bump HAP-python to 3.1.0 (#44176) Fixes many spec compliance issues, unavailable cases following an unexpected exception, and a thread safety race condition. --- homeassistant/components/homekit/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/homekit/manifest.json b/homeassistant/components/homekit/manifest.json index 486e9f1643c..d188dd270ab 100644 --- a/homeassistant/components/homekit/manifest.json +++ b/homeassistant/components/homekit/manifest.json @@ -3,7 +3,7 @@ "name": "HomeKit", "documentation": "https://www.home-assistant.io/integrations/homekit", "requirements": [ - "HAP-python==3.0.0", + "HAP-python==3.1.0", "fnvhash==0.1.0", "PyQRCode==1.2.1", "base36==0.1.1", diff --git a/requirements_all.txt b/requirements_all.txt index 3b1fa3f76e6..c8c91f98414 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -17,7 +17,7 @@ Adafruit-SHT31==1.0.2 # Adafruit_BBIO==1.1.1 # homeassistant.components.homekit -HAP-python==3.0.0 +HAP-python==3.1.0 # homeassistant.components.mastodon Mastodon.py==1.5.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index e8d3dfedfc8..cf6042a8cc9 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -4,7 +4,7 @@ -r requirements_test.txt # homeassistant.components.homekit -HAP-python==3.0.0 +HAP-python==3.1.0 # homeassistant.components.flick_electric PyFlick==0.0.2 From c8bb6eb3bf1671a60f16918b05dae6fc845a5df9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 14 Dec 2020 10:04:41 +0100 Subject: [PATCH 02/16] Update denonavr to 0.9.8 (#44194) --- homeassistant/components/denonavr/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/denonavr/manifest.json b/homeassistant/components/denonavr/manifest.json index c8341a3ec2c..31085292fbb 100644 --- a/homeassistant/components/denonavr/manifest.json +++ b/homeassistant/components/denonavr/manifest.json @@ -3,7 +3,7 @@ "name": "Denon AVR Network Receivers", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/denonavr", - "requirements": ["denonavr==0.9.7", "getmac==0.8.2"], + "requirements": ["denonavr==0.9.8", "getmac==0.8.2"], "codeowners": ["@scarface-4711", "@starkillerOG"], "ssdp": [ { diff --git a/requirements_all.txt b/requirements_all.txt index c8c91f98414..d3471c1856e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -481,7 +481,7 @@ defusedxml==0.6.0 deluge-client==1.7.1 # homeassistant.components.denonavr -denonavr==0.9.7 +denonavr==0.9.8 # homeassistant.components.devolo_home_control devolo-home-control-api==0.16.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index cf6042a8cc9..0c5fb601f5a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -254,7 +254,7 @@ debugpy==1.2.0 defusedxml==0.6.0 # homeassistant.components.denonavr -denonavr==0.9.7 +denonavr==0.9.8 # homeassistant.components.devolo_home_control devolo-home-control-api==0.16.0 From 839468549326bbec8b40b9eff40781fde8b481bf Mon Sep 17 00:00:00 2001 From: Greg Dowling Date: Wed, 16 Dec 2020 23:01:39 +0000 Subject: [PATCH 03/16] Bump pyroon to 0.0.28 (#44302) --- homeassistant/components/roon/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/roon/manifest.json b/homeassistant/components/roon/manifest.json index 4f5601a7f30..4bd5903253a 100644 --- a/homeassistant/components/roon/manifest.json +++ b/homeassistant/components/roon/manifest.json @@ -4,7 +4,7 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/roon", "requirements": [ - "roonapi==0.0.25" + "roonapi==0.0.28" ], "codeowners": [ "@pavoni" diff --git a/requirements_all.txt b/requirements_all.txt index d3471c1856e..1d827f2a163 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1958,7 +1958,7 @@ rokuecp==0.6.0 roombapy==1.6.2 # homeassistant.components.roon -roonapi==0.0.25 +roonapi==0.0.28 # homeassistant.components.rova rova==0.1.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 0c5fb601f5a..6fd738050e2 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -960,7 +960,7 @@ rokuecp==0.6.0 roombapy==1.6.2 # homeassistant.components.roon -roonapi==0.0.25 +roonapi==0.0.28 # homeassistant.components.rpi_power rpi-bad-power==0.1.0 From 2be5547c571df26236059ceb08e5abfe1776b7d4 Mon Sep 17 00:00:00 2001 From: Jc2k Date: Thu, 17 Dec 2020 16:12:06 +0000 Subject: [PATCH 04/16] Fix velux homekit covers not enumerated correctly (#44318) --- .../components/homekit_controller/cover.py | 1 + .../specific_devices/test_velux_gateway.py | 79 ++++ .../homekit_controller/velux_gateway.json | 380 ++++++++++++++++++ 3 files changed, 460 insertions(+) create mode 100644 tests/components/homekit_controller/specific_devices/test_velux_gateway.py create mode 100644 tests/fixtures/homekit_controller/velux_gateway.json diff --git a/homeassistant/components/homekit_controller/cover.py b/homeassistant/components/homekit_controller/cover.py index fdf48ebba5d..6c945c81115 100644 --- a/homeassistant/components/homekit_controller/cover.py +++ b/homeassistant/components/homekit_controller/cover.py @@ -248,4 +248,5 @@ class HomeKitWindowCover(HomeKitEntity, CoverEntity): ENTITY_TYPES = { ServicesTypes.GARAGE_DOOR_OPENER: HomeKitGarageDoorCover, ServicesTypes.WINDOW_COVERING: HomeKitWindowCover, + ServicesTypes.WINDOW: HomeKitWindowCover, } diff --git a/tests/components/homekit_controller/specific_devices/test_velux_gateway.py b/tests/components/homekit_controller/specific_devices/test_velux_gateway.py new file mode 100644 index 00000000000..033b4aa7b4d --- /dev/null +++ b/tests/components/homekit_controller/specific_devices/test_velux_gateway.py @@ -0,0 +1,79 @@ +""" +Test against characteristics captured from a Velux Gateway. + +https://github.com/home-assistant/core/issues/44314 +""" + +from homeassistant.components.cover import ( + SUPPORT_CLOSE, + SUPPORT_OPEN, + SUPPORT_SET_POSITION, +) + +from tests.components.homekit_controller.common import ( + Helper, + setup_accessories_from_file, + setup_test_accessories, +) + + +async def test_simpleconnect_cover_setup(hass): + """Test that a velux gateway can be correctly setup in HA.""" + accessories = await setup_accessories_from_file(hass, "velux_gateway.json") + config_entry, pairing = await setup_test_accessories(hass, accessories) + + entity_registry = await hass.helpers.entity_registry.async_get_registry() + + # Check that the cover is correctly found and set up + cover_id = "cover.velux_window" + cover = entity_registry.async_get(cover_id) + assert cover.unique_id == "homekit-1111111a114a111a-8" + + cover_helper = Helper( + hass, + cover_id, + pairing, + accessories[0], + config_entry, + ) + + cover_state = await cover_helper.poll_and_get_state() + assert cover_state.attributes["friendly_name"] == "VELUX Window" + assert cover_state.state == "closed" + assert cover_state.attributes["supported_features"] == ( + SUPPORT_CLOSE | SUPPORT_SET_POSITION | SUPPORT_OPEN + ) + + # Check that one of the sensors is correctly found and set up + sensor_id = "sensor.velux_sensor_temperature" + sensor = entity_registry.async_get(sensor_id) + assert sensor.unique_id == "homekit-a11b111-8" + + sensor_helper = Helper( + hass, + sensor_id, + pairing, + accessories[0], + config_entry, + ) + + sensor_state = await sensor_helper.poll_and_get_state() + assert sensor_state.attributes["friendly_name"] == "VELUX Sensor Temperature" + assert sensor_state.state == "18.9" + + # The cover and sensor are different devices (accessories) attached to the same bridge + assert cover.device_id != sensor.device_id + + device_registry = await hass.helpers.device_registry.async_get_registry() + + device = device_registry.async_get(cover.device_id) + assert device.manufacturer == "VELUX" + assert device.name == "VELUX Window" + assert device.model == "VELUX Window" + assert device.sw_version == "48" + + bridge = device_registry.async_get(device.via_device_id) + assert bridge.manufacturer == "VELUX" + assert bridge.name == "VELUX Gateway" + assert bridge.model == "VELUX Gateway" + assert bridge.sw_version == "70" diff --git a/tests/fixtures/homekit_controller/velux_gateway.json b/tests/fixtures/homekit_controller/velux_gateway.json new file mode 100644 index 00000000000..1a6f60537b3 --- /dev/null +++ b/tests/fixtures/homekit_controller/velux_gateway.json @@ -0,0 +1,380 @@ +[ + { + "aid": 1, + "services": [ + { + "type": "0000003E-0000-1000-8000-0026BB765291", + "iid": 1, + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 2, + "perms": [ + "pr" + ], + "format": "string", + "value": "VELUX Gateway" + }, + { + "type": "00000020-0000-1000-8000-0026BB765291", + "iid": 3, + "perms": [ + "pr" + ], + "format": "string", + "value": "VELUX" + }, + { + "type": "00000021-0000-1000-8000-0026BB765291", + "iid": 4, + "perms": [ + "pr" + ], + "format": "string", + "value": "VELUX Gateway" + }, + { + "type": "00000030-0000-1000-8000-0026BB765291", + "iid": 5, + "perms": [ + "pr" + ], + "format": "string", + "value": "a1a11a1" + }, + { + "type": "00000014-0000-1000-8000-0026BB765291", + "iid": 6, + "perms": [ + "pw" + ], + "format": "bool" + }, + { + "type": "00000052-0000-1000-8000-0026BB765291", + "iid": 7, + "perms": [ + "pr" + ], + "format": "string", + "value": "70" + } + ], + "hidden": false, + "primary": false + }, + { + "type": "000000A2-0000-1000-8000-0026BB765291", + "iid": 8, + "characteristics": [ + { + "type": "00000037-0000-1000-8000-0026BB765291", + "iid": 9, + "perms": [ + "pr" + ], + "format": "string", + "value": "1.1.0" + } + ], + "hidden": false, + "primary": false + } + ] + }, + { + "aid": 2, + "services": [ + { + "type": "0000003E-0000-1000-8000-0026BB765291", + "iid": 1, + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 2, + "perms": [ + "pr" + ], + "format": "string", + "value": "VELUX Sensor" + }, + { + "type": "00000020-0000-1000-8000-0026BB765291", + "iid": 3, + "perms": [ + "pr" + ], + "format": "string", + "value": "VELUX" + }, + { + "type": "00000021-0000-1000-8000-0026BB765291", + "iid": 4, + "perms": [ + "pr" + ], + "format": "string", + "value": "VELUX Sensor" + }, + { + "type": "00000030-0000-1000-8000-0026BB765291", + "iid": 5, + "perms": [ + "pr" + ], + "format": "string", + "value": "a11b111" + }, + { + "type": "00000014-0000-1000-8000-0026BB765291", + "iid": 7, + "perms": [ + "pw" + ], + "format": "bool" + }, + { + "type": "00000052-0000-1000-8000-0026BB765291", + "iid": 6, + "perms": [ + "pr" + ], + "format": "string", + "value": "16" + } + ], + "hidden": false, + "primary": false + }, + { + "type": "0000008A-0000-1000-8000-0026BB765291", + "iid": 8, + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 9, + "perms": [ + "pr" + ], + "format": "string", + "value": "Temperature sensor" + }, + { + "type": "00000011-0000-1000-8000-0026BB765291", + "iid": 10, + "perms": [ + "pr", + "ev" + ], + "format": "float", + "value": 18.9, + "minValue": 0, + "maxValue": 50, + "minStep": 0.1, + "unit": "celsius" + } + ], + "hidden": false, + "primary": true + }, + { + "type": "00000082-0000-1000-8000-0026BB765291", + "iid": 11, + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 12, + "perms": [ + "pr" + ], + "format": "string", + "value": "Humidity sensor" + }, + { + "type": "00000010-0000-1000-8000-0026BB765291", + "iid": 13, + "perms": [ + "pr", + "ev" + ], + "format": "float", + "value": 58, + "minValue": 0, + "maxValue": 100, + "minStep": 1, + "unit": "percentage" + } + ], + "hidden": false, + "primary": false + }, + { + "type": "00000097-0000-1000-8000-0026BB765291", + "iid": 14, + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 15, + "perms": [ + "pr" + ], + "format": "string", + "value": "Carbon Dioxide sensor" + }, + { + "type": "00000092-0000-1000-8000-0026BB765291", + "iid": 16, + "perms": [ + "pr", + "ev" + ], + "format": "uint8", + "value": 0, + "maxValue": 1, + "minValue": 0, + "minStep": 1 + }, + { + "type": "00000093-0000-1000-8000-0026BB765291", + "iid": 17, + "perms": [ + "pr", + "ev" + ], + "format": "float", + "value": 400, + "minValue": 0, + "maxValue": 5000 + } + ], + "hidden": false, + "primary": false + } + ] + }, + { + "aid": 3, + "services": [ + { + "type": "0000003E-0000-1000-8000-0026BB765291", + "iid": 1, + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 2, + "perms": [ + "pr" + ], + "format": "string", + "value": "VELUX Window" + }, + { + "type": "00000020-0000-1000-8000-0026BB765291", + "iid": 3, + "perms": [ + "pr" + ], + "format": "string", + "value": "VELUX" + }, + { + "type": "00000021-0000-1000-8000-0026BB765291", + "iid": 4, + "perms": [ + "pr" + ], + "format": "string", + "value": "VELUX Window" + }, + { + "type": "00000030-0000-1000-8000-0026BB765291", + "iid": 5, + "perms": [ + "pr" + ], + "format": "string", + "value": "1111111a114a111a" + }, + { + "type": "00000014-0000-1000-8000-0026BB765291", + "iid": 7, + "perms": [ + "pw" + ], + "format": "bool" + }, + { + "type": "00000052-0000-1000-8000-0026BB765291", + "iid": 6, + "perms": [ + "pr" + ], + "format": "string", + "value": "48" + } + ], + "hidden": false, + "primary": false + }, + { + "type": "0000008B-0000-1000-8000-0026BB765291", + "iid": 8, + "characteristics": [ + { + "type": "00000023-0000-1000-8000-0026BB765291", + "iid": 9, + "perms": [ + "pr" + ], + "format": "string", + "value": "Roof Window" + }, + { + "type": "0000007C-0000-1000-8000-0026BB765291", + "iid": 11, + "perms": [ + "pr", + "pw", + "ev" + ], + "format": "uint8", + "value": 0, + "maxValue": 100, + "minValue": 0, + "unit": "percentage", + "minStep": 1 + }, + { + "type": "0000006D-0000-1000-8000-0026BB765291", + "iid": 10, + "perms": [ + "pr", + "ev" + ], + "format": "uint8", + "value": 0, + "maxValue": 100, + "minValue": 0, + "unit": "percentage", + "minStep": 1 + }, + { + "type": "00000072-0000-1000-8000-0026BB765291", + "iid": 12, + "perms": [ + "pr", + "ev" + ], + "format": "uint8", + "value": 2, + "maxValue": 2, + "minValue": 0, + "minStep": 1 + } + ], + "hidden": false, + "primary": true + } + ] + } +] \ No newline at end of file From 9c5dba6a2405f3c252c3596fc9987f63279d17d5 Mon Sep 17 00:00:00 2001 From: ehendrix23 Date: Thu, 17 Dec 2020 11:08:19 -0700 Subject: [PATCH 05/16] Bump pyMyQ to version 2.0.12 (#44328) --- homeassistant/components/myq/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/myq/manifest.json b/homeassistant/components/myq/manifest.json index ee3471725b6..5f863ad7f34 100644 --- a/homeassistant/components/myq/manifest.json +++ b/homeassistant/components/myq/manifest.json @@ -2,7 +2,7 @@ "domain": "myq", "name": "MyQ", "documentation": "https://www.home-assistant.io/integrations/myq", - "requirements": ["pymyq==2.0.11"], + "requirements": ["pymyq==2.0.12"], "codeowners": ["@bdraco"], "config_flow": true, "homekit": { diff --git a/requirements_all.txt b/requirements_all.txt index 1d827f2a163..328e2183892 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1542,7 +1542,7 @@ pymsteams==0.1.12 pymusiccast==0.1.6 # homeassistant.components.myq -pymyq==2.0.11 +pymyq==2.0.12 # homeassistant.components.mysensors pymysensors==0.18.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 6fd738050e2..e6d54280d07 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -782,7 +782,7 @@ pymodbus==2.3.0 pymonoprice==0.3 # homeassistant.components.myq -pymyq==2.0.11 +pymyq==2.0.12 # homeassistant.components.nut pynut2==2.1.2 From 89168dd3720e9f0f30eaaebd02f4b642901a9917 Mon Sep 17 00:00:00 2001 From: rubenbe Date: Fri, 18 Dec 2020 08:37:32 +0100 Subject: [PATCH 06/16] Update pytradfri to 7.0.5 (#44347) --- 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 7ffa8ed24bf..57f58f05993 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.4"], + "requirements": ["pytradfri[async]==7.0.5"], "homekit": { "models": ["TRADFRI"] }, diff --git a/requirements_all.txt b/requirements_all.txt index 328e2183892..86d05943729 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1858,7 +1858,7 @@ pytraccar==0.9.0 pytrackr==0.0.5 # homeassistant.components.tradfri -pytradfri[async]==7.0.4 +pytradfri[async]==7.0.5 # homeassistant.components.trafikverket_train # homeassistant.components.trafikverket_weatherstation diff --git a/requirements_test_all.txt b/requirements_test_all.txt index e6d54280d07..579a659950b 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -915,7 +915,7 @@ pytile==4.0.0 pytraccar==0.9.0 # homeassistant.components.tradfri -pytradfri[async]==7.0.4 +pytradfri[async]==7.0.5 # homeassistant.components.vera pyvera==0.3.11 From 0cac5b7cb343b1afdaa6cbe0b8f0e77818dc81fc Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Fri, 18 Dec 2020 13:12:16 -0700 Subject: [PATCH 07/16] Bump pyiqvia to 0.3.1 (#44358) --- homeassistant/components/iqvia/__init__.py | 2 +- homeassistant/components/iqvia/config_flow.py | 2 +- homeassistant/components/iqvia/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/iqvia/__init__.py b/homeassistant/components/iqvia/__init__.py index db0df3a073b..bf1725a036a 100644 --- a/homeassistant/components/iqvia/__init__.py +++ b/homeassistant/components/iqvia/__init__.py @@ -52,7 +52,7 @@ async def async_setup_entry(hass, entry): ) websession = aiohttp_client.async_get_clientsession(hass) - client = Client(entry.data[CONF_ZIP_CODE], websession) + client = Client(entry.data[CONF_ZIP_CODE], session=websession) async def async_get_data_from_api(api_coro): """Get data from a particular API coroutine.""" diff --git a/homeassistant/components/iqvia/config_flow.py b/homeassistant/components/iqvia/config_flow.py index e43c61985d6..ecd1e3c3c4b 100644 --- a/homeassistant/components/iqvia/config_flow.py +++ b/homeassistant/components/iqvia/config_flow.py @@ -30,7 +30,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): websession = aiohttp_client.async_get_clientsession(self.hass) try: - Client(user_input[CONF_ZIP_CODE], websession) + Client(user_input[CONF_ZIP_CODE], session=websession) except InvalidZipError: return self.async_show_form( step_id="user", diff --git a/homeassistant/components/iqvia/manifest.json b/homeassistant/components/iqvia/manifest.json index 5ab331df44e..6445b4ad91f 100644 --- a/homeassistant/components/iqvia/manifest.json +++ b/homeassistant/components/iqvia/manifest.json @@ -3,6 +3,6 @@ "name": "IQVIA", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/iqvia", - "requirements": ["numpy==1.19.2", "pyiqvia==0.2.1"], + "requirements": ["numpy==1.19.2", "pyiqvia==0.3.1"], "codeowners": ["@bachya"] } diff --git a/requirements_all.txt b/requirements_all.txt index 86d05943729..f55280326cf 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1455,7 +1455,7 @@ pyipma==2.0.5 pyipp==0.11.0 # homeassistant.components.iqvia -pyiqvia==0.2.1 +pyiqvia==0.3.1 # homeassistant.components.irish_rail_transport pyirishrail==0.0.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 579a659950b..da18893a910 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -734,7 +734,7 @@ pyipma==2.0.5 pyipp==0.11.0 # homeassistant.components.iqvia -pyiqvia==0.2.1 +pyiqvia==0.3.1 # homeassistant.components.isy994 pyisy==2.1.0 From f76211d58aee0c1c074cb2bcdefff2c86bda5867 Mon Sep 17 00:00:00 2001 From: Aaron Bach Date: Fri, 18 Dec 2020 12:28:18 -0700 Subject: [PATCH 08/16] Fix bug in unloading RainMachine options listener (#44359) * Fix bug in unloading RainMachine options listener * Order --- homeassistant/components/rainmachine/__init__.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/rainmachine/__init__.py b/homeassistant/components/rainmachine/__init__.py index 41c56e38db6..c8697adbcd4 100644 --- a/homeassistant/components/rainmachine/__init__.py +++ b/homeassistant/components/rainmachine/__init__.py @@ -275,7 +275,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: ]: hass.services.async_register(DOMAIN, service, method, schema=schema) - hass.data[DOMAIN][DATA_LISTENER] = entry.add_update_listener(async_reload_entry) + hass.data[DOMAIN][DATA_LISTENER][entry.entry_id] = entry.add_update_listener( + async_reload_entry + ) return True From a58219bbc7314b4479db4de380bb3d338c79e88b Mon Sep 17 00:00:00 2001 From: On Freund Date: Tue, 22 Dec 2020 13:32:56 +0200 Subject: [PATCH 09/16] Fix Volumio pause with missing track type (#44447) --- homeassistant/components/volumio/media_player.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/volumio/media_player.py b/homeassistant/components/volumio/media_player.py index 89fb17affc8..69790e71732 100644 --- a/homeassistant/components/volumio/media_player.py +++ b/homeassistant/components/volumio/media_player.py @@ -204,7 +204,7 @@ class Volumio(MediaPlayerEntity): async def async_media_pause(self): """Send media_pause command to media player.""" - if self._state["trackType"] == "webradio": + if self._state.get("trackType") == "webradio": await self._volumio.stop() else: await self._volumio.pause() From 78f81b6e3736ad60c93dee549ce5484d33d8acab Mon Sep 17 00:00:00 2001 From: MatthewFlamm <39341281+MatthewFlamm@users.noreply.github.com> Date: Sat, 26 Dec 2020 07:53:34 -0500 Subject: [PATCH 10/16] Fix falsey comparisons in NWS weather (#44486) --- homeassistant/components/nws/weather.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/nws/weather.py b/homeassistant/components/nws/weather.py index 69dac297b1b..34c2909188f 100644 --- a/homeassistant/components/nws/weather.py +++ b/homeassistant/components/nws/weather.py @@ -161,7 +161,7 @@ class NWSWeather(WeatherEntity): temp_c = None if self.observation: temp_c = self.observation.get("temperature") - if temp_c: + if temp_c is not None: return convert_temperature(temp_c, TEMP_CELSIUS, TEMP_FAHRENHEIT) return None @@ -273,7 +273,7 @@ class NWSWeather(WeatherEntity): data[ATTR_FORECAST_WIND_BEARING] = forecast_entry.get("windBearing") wind_speed = forecast_entry.get("windSpeedAvg") - if wind_speed: + if wind_speed is not None: if self.is_metric: data[ATTR_FORECAST_WIND_SPEED] = round( convert_distance(wind_speed, LENGTH_MILES, LENGTH_KILOMETERS) From 59c20686c1aa429af78cf9683046f5aa33f914ab Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Sat, 26 Dec 2020 22:24:05 +0100 Subject: [PATCH 11/16] Bump pydeconz to version 77 (#44514) --- homeassistant/components/deconz/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/deconz/manifest.json b/homeassistant/components/deconz/manifest.json index c2846f8c57f..22711b84b9d 100644 --- a/homeassistant/components/deconz/manifest.json +++ b/homeassistant/components/deconz/manifest.json @@ -3,7 +3,7 @@ "name": "deCONZ", "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/deconz", - "requirements": ["pydeconz==76"], + "requirements": ["pydeconz==77"], "ssdp": [ { "manufacturer": "Royal Philips Electronics" diff --git a/requirements_all.txt b/requirements_all.txt index f55280326cf..63d574c3922 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1337,7 +1337,7 @@ pydaikin==2.3.1 pydanfossair==0.1.0 # homeassistant.components.deconz -pydeconz==76 +pydeconz==77 # homeassistant.components.delijn pydelijn==0.6.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index da18893a910..bd9819319f5 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -673,7 +673,7 @@ pycountry==19.8.18 pydaikin==2.3.1 # homeassistant.components.deconz -pydeconz==76 +pydeconz==77 # homeassistant.components.dexcom pydexcom==0.2.0 From 99d7c8391747e0cfb954eb014be0e8cc19ee2e7a Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Mon, 28 Dec 2020 14:41:39 +0100 Subject: [PATCH 12/16] Fix Tasmota device triggers (#44574) --- .../components/tasmota/device_trigger.py | 4 +- .../components/tasmota/test_device_trigger.py | 147 ++++++++++++++++-- 2 files changed, 139 insertions(+), 12 deletions(-) diff --git a/homeassistant/components/tasmota/device_trigger.py b/homeassistant/components/tasmota/device_trigger.py index e7dad0885a0..f06d815e5c5 100644 --- a/homeassistant/components/tasmota/device_trigger.py +++ b/homeassistant/components/tasmota/device_trigger.py @@ -56,7 +56,7 @@ class TriggerInstance: event_trigger.CONF_EVENT_TYPE: TASMOTA_EVENT, event_trigger.CONF_EVENT_DATA: { "mac": self.trigger.tasmota_trigger.cfg.mac, - "source": self.trigger.tasmota_trigger.cfg.source, + "source": self.trigger.tasmota_trigger.cfg.subtype, "event": self.trigger.tasmota_trigger.cfg.event, }, } @@ -126,7 +126,7 @@ class Trigger: def _on_trigger(): data = { "mac": self.tasmota_trigger.cfg.mac, - "source": self.tasmota_trigger.cfg.source, + "source": self.tasmota_trigger.cfg.subtype, "event": self.tasmota_trigger.cfg.event, } self.hass.bus.async_fire( diff --git a/tests/components/tasmota/test_device_trigger.py b/tests/components/tasmota/test_device_trigger.py index 42fc5dc7a49..2c88533f30d 100644 --- a/tests/components/tasmota/test_device_trigger.py +++ b/tests/components/tasmota/test_device_trigger.py @@ -21,7 +21,42 @@ from tests.common import ( from tests.components.blueprint.conftest import stub_blueprint_populate # noqa -async def test_get_triggers(hass, device_reg, entity_reg, mqtt_mock, setup_tasmota): +async def test_get_triggers_btn(hass, device_reg, entity_reg, mqtt_mock, setup_tasmota): + """Test we get the expected triggers from a discovered mqtt device.""" + config = copy.deepcopy(DEFAULT_CONFIG) + config["btn"][0] = 1 + config["btn"][1] = 1 + config["so"]["13"] = 1 + config["so"]["73"] = 1 + mac = config["mac"] + + async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{mac}/config", json.dumps(config)) + await hass.async_block_till_done() + + device_entry = device_reg.async_get_device(set(), {("mac", mac)}) + expected_triggers = [ + { + "platform": "device", + "domain": DOMAIN, + "device_id": device_entry.id, + "discovery_id": "00000049A3BC_button_1_SINGLE", + "type": "button_short_press", + "subtype": "button_1", + }, + { + "platform": "device", + "domain": DOMAIN, + "device_id": device_entry.id, + "discovery_id": "00000049A3BC_button_2_SINGLE", + "type": "button_short_press", + "subtype": "button_2", + }, + ] + triggers = await async_get_device_automations(hass, "trigger", device_entry.id) + assert_lists_same(triggers, expected_triggers) + + +async def test_get_triggers_swc(hass, device_reg, entity_reg, mqtt_mock, setup_tasmota): """Test we get the expected triggers from a discovered mqtt device.""" config = copy.deepcopy(DEFAULT_CONFIG) config["swc"][0] = 0 @@ -239,13 +274,83 @@ async def test_update_remove_triggers( assert triggers == [] -async def test_if_fires_on_mqtt_message( +async def test_if_fires_on_mqtt_message_btn( hass, device_reg, calls, mqtt_mock, setup_tasmota ): - """Test triggers firing.""" + """Test button triggers firing.""" + # Discover a device with 2 device triggers + config = copy.deepcopy(DEFAULT_CONFIG) + config["btn"][0] = 1 + config["btn"][2] = 1 + config["so"]["73"] = 1 + mac = config["mac"] + + async_fire_mqtt_message(hass, f"{DEFAULT_PREFIX}/{mac}/config", json.dumps(config)) + await hass.async_block_till_done() + device_entry = device_reg.async_get_device(set(), {("mac", mac)}) + + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: [ + { + "trigger": { + "platform": "device", + "domain": DOMAIN, + "device_id": device_entry.id, + "discovery_id": "00000049A3BC_button_1_SINGLE", + "type": "button_short_press", + "subtype": "button_1", + }, + "action": { + "service": "test.automation", + "data_template": {"some": ("short_press_1")}, + }, + }, + { + "trigger": { + "platform": "device", + "domain": DOMAIN, + "device_id": device_entry.id, + "discovery_id": "00000049A3BC_button_3_SINGLE", + "subtype": "button_3", + "type": "button_short_press", + }, + "action": { + "service": "test.automation", + "data_template": {"some": ("short_press_3")}, + }, + }, + ] + }, + ) + + # Fake button 1 single press. + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Button1":{"Action":"SINGLE"}}' + ) + await hass.async_block_till_done() + assert len(calls) == 1 + assert calls[0].data["some"] == "short_press_1" + + # Fake button 3 single press. + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Button3":{"Action":"SINGLE"}}' + ) + await hass.async_block_till_done() + assert len(calls) == 2 + assert calls[1].data["some"] == "short_press_3" + + +async def test_if_fires_on_mqtt_message_swc( + hass, device_reg, calls, mqtt_mock, setup_tasmota +): + """Test switch triggers firing.""" # Discover a device with 2 device triggers config = copy.deepcopy(DEFAULT_CONFIG) config["swc"][0] = 0 + config["swc"][1] = 0 config["swc"][2] = 9 config["swn"][2] = "custom_switch" mac = config["mac"] @@ -270,7 +375,21 @@ async def test_if_fires_on_mqtt_message( }, "action": { "service": "test.automation", - "data_template": {"some": ("short_press")}, + "data_template": {"some": ("short_press_1")}, + }, + }, + { + "trigger": { + "platform": "device", + "domain": DOMAIN, + "device_id": device_entry.id, + "discovery_id": "00000049A3BC_switch_2_TOGGLE", + "type": "button_short_press", + "subtype": "switch_2", + }, + "action": { + "service": "test.automation", + "data_template": {"some": ("short_press_2")}, }, }, { @@ -284,28 +403,36 @@ async def test_if_fires_on_mqtt_message( }, "action": { "service": "test.automation", - "data_template": {"some": ("long_press")}, + "data_template": {"some": ("long_press_3")}, }, }, ] }, ) - # Fake short press. + # Fake switch 1 short press. async_fire_mqtt_message( hass, "tasmota_49A3BC/stat/RESULT", '{"Switch1":{"Action":"TOGGLE"}}' ) await hass.async_block_till_done() assert len(calls) == 1 - assert calls[0].data["some"] == "short_press" + assert calls[0].data["some"] == "short_press_1" - # Fake long press. + # Fake switch 2 short press. + async_fire_mqtt_message( + hass, "tasmota_49A3BC/stat/RESULT", '{"Switch2":{"Action":"TOGGLE"}}' + ) + await hass.async_block_till_done() + assert len(calls) == 2 + assert calls[1].data["some"] == "short_press_2" + + # Fake switch 3 long press. async_fire_mqtt_message( hass, "tasmota_49A3BC/stat/RESULT", '{"custom_switch":{"Action":"HOLD"}}' ) await hass.async_block_till_done() - assert len(calls) == 2 - assert calls[1].data["some"] == "long_press" + assert len(calls) == 3 + assert calls[2].data["some"] == "long_press_3" async def test_if_fires_on_mqtt_message_late_discover( From 62f8d6cc04dc3e65af64070e5483afe9be51341d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 29 Dec 2020 12:16:39 -1000 Subject: [PATCH 13/16] Fix template triggers from time events (#44603) Co-authored-by: Paulus Schoutsen --- homeassistant/components/template/trigger.py | 47 ++++++------ tests/components/template/test_trigger.py | 77 +++++++++++++++++++- 2 files changed, 99 insertions(+), 25 deletions(-) diff --git a/homeassistant/components/template/trigger.py b/homeassistant/components/template/trigger.py index 5d748edb841..80ad585486b 100644 --- a/homeassistant/components/template/trigger.py +++ b/homeassistant/components/template/trigger.py @@ -52,25 +52,33 @@ async def async_attach_trigger( if not result_as_boolean(result): return - entity_id = event.data.get("entity_id") - from_s = event.data.get("old_state") - to_s = event.data.get("new_state") + entity_id = event and event.data.get("entity_id") + from_s = event and event.data.get("old_state") + to_s = event and event.data.get("new_state") + + if entity_id is not None: + description = f"{entity_id} via template" + else: + description = "time change or manual update via template" + + template_variables = { + "platform": platform_type, + "entity_id": entity_id, + "from_state": from_s, + "to_state": to_s, + } + trigger_variables = { + "for": time_delta, + "description": description, + } @callback def call_action(*_): """Call action with right context.""" + nonlocal trigger_variables hass.async_run_hass_job( job, - { - "trigger": { - "platform": "template", - "entity_id": entity_id, - "from_state": from_s, - "to_state": to_s, - "for": time_delta if not time_delta else period, - "description": f"{entity_id} via template", - } - }, + {"trigger": {**template_variables, **trigger_variables}}, (to_s.context if to_s else None), ) @@ -78,18 +86,9 @@ async def async_attach_trigger( call_action() return - variables = { - "trigger": { - "platform": platform_type, - "entity_id": entity_id, - "from_state": from_s, - "to_state": to_s, - } - } - try: period = cv.positive_time_period( - template.render_complex(time_delta, variables) + template.render_complex(time_delta, {"trigger": template_variables}) ) except (exceptions.TemplateError, vol.Invalid) as ex: _LOGGER.error( @@ -97,6 +96,8 @@ async def async_attach_trigger( ) return + trigger_variables["for"] = period + delay_cancel = async_call_later(hass, period.seconds, call_action) info = async_track_template_result( diff --git a/tests/components/template/test_trigger.py b/tests/components/template/test_trigger.py index 828cf1fb7b4..822a274bf23 100644 --- a/tests/components/template/test_trigger.py +++ b/tests/components/template/test_trigger.py @@ -11,6 +11,7 @@ from homeassistant.core import Context, callback from homeassistant.setup import async_setup_component import homeassistant.util.dt as dt_util +from tests.async_mock import patch from tests.common import ( assert_setup_component, async_fire_time_changed, @@ -626,6 +627,7 @@ async def test_if_fires_on_change_with_for_0_advanced(hass, calls): async def test_if_fires_on_change_with_for_2(hass, calls): """Test for firing on change with for.""" + context = Context() assert await async_setup_component( hass, automation.DOMAIN, @@ -636,17 +638,33 @@ async def test_if_fires_on_change_with_for_2(hass, calls): "value_template": "{{ is_state('test.entity', 'world') }}", "for": 5, }, - "action": {"service": "test.automation"}, + "action": { + "service": "test.automation", + "data_template": { + "some": "{{ trigger.%s }}" + % "}} - {{ trigger.".join( + ( + "platform", + "entity_id", + "from_state.state", + "to_state.state", + "for", + ) + ) + }, + }, } }, ) - hass.states.async_set("test.entity", "world") + hass.states.async_set("test.entity", "world", context=context) await hass.async_block_till_done() assert len(calls) == 0 async_fire_time_changed(hass, dt_util.utcnow() + timedelta(seconds=10)) await hass.async_block_till_done() assert len(calls) == 1 + assert calls[0].context.parent_id == context.id + assert calls[0].data["some"] == "template - test.entity - hello - world - 0:00:05" async def test_if_not_fires_on_change_with_for(hass, calls): @@ -811,3 +829,58 @@ async def test_invalid_for_template_1(hass, calls): hass.states.async_set("test.entity", "world") await hass.async_block_till_done() assert mock_logger.error.called + + +async def test_if_fires_on_time_change(hass, calls): + """Test for firing on time changes.""" + 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 + ): + assert await async_setup_component( + hass, + automation.DOMAIN, + { + automation.DOMAIN: { + "trigger": { + "platform": "template", + "value_template": "{{ utcnow().minute % 2 == 0 }}", + }, + "action": {"service": "test.automation"}, + } + }, + ) + await hass.async_block_till_done() + assert len(calls) == 0 + + # Trigger once (match template) + 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 + + # Trigger again (match template) + second_time = start_time.replace(minute=4, second=0) + with patch("homeassistant.util.dt.utcnow", return_value=second_time): + async_fire_time_changed(hass, second_time) + await hass.async_block_till_done() + await hass.async_block_till_done() + assert len(calls) == 1 + + # Trigger again (do not match template) + third_time = start_time.replace(minute=5, second=0) + with patch("homeassistant.util.dt.utcnow", return_value=third_time): + async_fire_time_changed(hass, third_time) + await hass.async_block_till_done() + await hass.async_block_till_done() + assert len(calls) == 1 + + # Trigger again (match template) + forth_time = start_time.replace(minute=8, second=0) + with patch("homeassistant.util.dt.utcnow", return_value=forth_time): + async_fire_time_changed(hass, forth_time) + await hass.async_block_till_done() + await hass.async_block_till_done() + assert len(calls) == 2 From 19531b90a30294b391095184bb75dd01d87cfb81 Mon Sep 17 00:00:00 2001 From: michaeldavie Date: Tue, 29 Dec 2020 20:54:04 -0500 Subject: [PATCH 14/16] Bump env_canada to 0.2.5 (#44631) --- homeassistant/components/environment_canada/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/environment_canada/manifest.json b/homeassistant/components/environment_canada/manifest.json index 2a51c6ffd83..02a60049f07 100644 --- a/homeassistant/components/environment_canada/manifest.json +++ b/homeassistant/components/environment_canada/manifest.json @@ -2,6 +2,6 @@ "domain": "environment_canada", "name": "Environment Canada", "documentation": "https://www.home-assistant.io/integrations/environment_canada", - "requirements": ["env_canada==0.2.4"], + "requirements": ["env_canada==0.2.5"], "codeowners": ["@michaeldavie"] } diff --git a/requirements_all.txt b/requirements_all.txt index 63d574c3922..de7e05feca6 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -553,7 +553,7 @@ enocean==0.50 enturclient==0.2.1 # homeassistant.components.environment_canada -env_canada==0.2.4 +env_canada==0.2.5 # homeassistant.components.envirophat # envirophat==0.0.6 From af4849c18342a2a40f28f6b45b617a991b0b9458 Mon Sep 17 00:00:00 2001 From: Phil Cole Date: Wed, 30 Dec 2020 08:44:44 +0000 Subject: [PATCH 15/16] Bump pycarwings2 to 2.10 (#44634) --- homeassistant/components/nissan_leaf/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/nissan_leaf/manifest.json b/homeassistant/components/nissan_leaf/manifest.json index 339b5750036..db78e5ce0e9 100644 --- a/homeassistant/components/nissan_leaf/manifest.json +++ b/homeassistant/components/nissan_leaf/manifest.json @@ -2,6 +2,6 @@ "domain": "nissan_leaf", "name": "Nissan Leaf", "documentation": "https://www.home-assistant.io/integrations/nissan_leaf", - "requirements": ["pycarwings2==2.9"], + "requirements": ["pycarwings2==2.10"], "codeowners": ["@filcole"] } diff --git a/requirements_all.txt b/requirements_all.txt index de7e05feca6..f1426cebca8 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1298,7 +1298,7 @@ pyblackbird==0.5 pybotvac==0.0.17 # homeassistant.components.nissan_leaf -pycarwings2==2.9 +pycarwings2==2.10 # homeassistant.components.cloudflare pycfdns==1.2.1 From d1ad474a8d5c66341c074688b52553b6a5eef795 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Wed, 30 Dec 2020 10:17:56 +0100 Subject: [PATCH 16/16] Bumped version to 2020.12.2 --- homeassistant/const.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index 582648e8d32..ac4f07a7086 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -1,7 +1,7 @@ """Constants used by Home Assistant components.""" MAJOR_VERSION = 2020 MINOR_VERSION = 12 -PATCH_VERSION = "1" +PATCH_VERSION = "2" __short_version__ = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__ = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER = (3, 7, 1)