From 5826f9a4f605e2769a63a43f70a6dc49dcc6d87b Mon Sep 17 00:00:00 2001 From: Jonny Rimkus Date: Mon, 1 Apr 2024 10:50:21 +0200 Subject: [PATCH 01/26] Bump slixmpp version to 1.8.5 (#114448) * Update slixmpp to 1.8.5, hopefully fixes #113990 * Bump slixmpp version to 1.8.5 #114448 --- homeassistant/components/xmpp/manifest.json | 2 +- requirements_all.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/xmpp/manifest.json b/homeassistant/components/xmpp/manifest.json index 30dee6c842b535..308c3d70978189 100644 --- a/homeassistant/components/xmpp/manifest.json +++ b/homeassistant/components/xmpp/manifest.json @@ -5,5 +5,5 @@ "documentation": "https://www.home-assistant.io/integrations/xmpp", "iot_class": "cloud_push", "loggers": ["pyasn1", "slixmpp"], - "requirements": ["slixmpp==1.8.4", "emoji==2.8.0"] + "requirements": ["slixmpp==1.8.5", "emoji==2.8.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index 194dda7caac5b2..c93b665ea8c6ca 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2553,7 +2553,7 @@ sisyphus-control==3.1.3 slackclient==2.5.0 # homeassistant.components.xmpp -slixmpp==1.8.4 +slixmpp==1.8.5 # homeassistant.components.smart_meter_texas smart-meter-texas==0.4.7 From 5194faa8fd959832086fb0064beebd627f7f5a9f Mon Sep 17 00:00:00 2001 From: Joost Lekkerkerker Date: Fri, 19 Apr 2024 18:18:32 +0200 Subject: [PATCH 02/26] Make Withings recoverable after internet outage (#115124) --- homeassistant/components/withings/__init__.py | 7 +- tests/components/withings/test_init.py | 105 ++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/withings/__init__.py b/homeassistant/components/withings/__init__.py index c14fb4657313c5..665a90ec5a7aa8 100644 --- a/homeassistant/components/withings/__init__.py +++ b/homeassistant/components/withings/__init__.py @@ -12,6 +12,7 @@ from datetime import timedelta from typing import TYPE_CHECKING, Any, cast +from aiohttp import ClientError from aiohttp.hdrs import METH_POST from aiohttp.web import Request, Response from aiowithings import NotificationCategory, WithingsClient @@ -340,7 +341,11 @@ async def register_webhook( async def async_unsubscribe_webhooks(client: WithingsClient) -> None: """Unsubscribe to all Withings webhooks.""" - current_webhooks = await client.list_notification_configurations() + try: + current_webhooks = await client.list_notification_configurations() + except ClientError: + LOGGER.exception("Error when unsubscribing webhooks") + return for webhook_configuration in current_webhooks: LOGGER.debug( diff --git a/tests/components/withings/test_init.py b/tests/components/withings/test_init.py index eb089f44216cfa..42b2b8da965020 100644 --- a/tests/components/withings/test_init.py +++ b/tests/components/withings/test_init.py @@ -5,6 +5,7 @@ from unittest.mock import AsyncMock, MagicMock, patch from urllib.parse import urlparse +from aiohttp import ClientConnectionError from aiohttp.hdrs import METH_HEAD from aiowithings import ( NotificationCategory, @@ -508,6 +509,110 @@ async def test_cloud_disconnect( assert withings.subscribe_notification.call_count == 12 +async def test_internet_disconnect( + hass: HomeAssistant, + withings: AsyncMock, + webhook_config_entry: MockConfigEntry, + hass_client_no_auth: ClientSessionGenerator, + freezer: FrozenDateTimeFactory, +) -> None: + """Test we can recover from internet disconnects.""" + await mock_cloud(hass) + await hass.async_block_till_done() + + with ( + patch("homeassistant.components.cloud.async_is_logged_in", return_value=True), + patch.object(cloud, "async_is_connected", return_value=True), + patch.object(cloud, "async_active_subscription", return_value=True), + patch( + "homeassistant.components.cloud.async_create_cloudhook", + return_value="https://hooks.nabu.casa/ABCD", + ), + patch( + "homeassistant.components.withings.async_get_config_entry_implementation", + ), + patch( + "homeassistant.components.cloud.async_delete_cloudhook", + ), + patch( + "homeassistant.components.withings.webhook_generate_url", + ), + ): + await setup_integration(hass, webhook_config_entry) + await prepare_webhook_setup(hass, freezer) + + assert cloud.async_active_subscription(hass) is True + assert cloud.async_is_connected(hass) is True + assert withings.revoke_notification_configurations.call_count == 3 + assert withings.subscribe_notification.call_count == 6 + + await hass.async_block_till_done() + + withings.list_notification_configurations.side_effect = ClientConnectionError + + async_mock_cloud_connection_status(hass, False) + await hass.async_block_till_done() + + assert withings.revoke_notification_configurations.call_count == 3 + + async_mock_cloud_connection_status(hass, True) + await hass.async_block_till_done() + + assert withings.subscribe_notification.call_count == 12 + + +async def test_cloud_disconnect_retry( + hass: HomeAssistant, + withings: AsyncMock, + webhook_config_entry: MockConfigEntry, + hass_client_no_auth: ClientSessionGenerator, + freezer: FrozenDateTimeFactory, +) -> None: + """Test we retry to create webhook connection again after cloud disconnects.""" + await mock_cloud(hass) + await hass.async_block_till_done() + + with ( + patch("homeassistant.components.cloud.async_is_logged_in", return_value=True), + patch.object(cloud, "async_is_connected", return_value=True), + patch.object( + cloud, "async_active_subscription", return_value=True + ) as mock_async_active_subscription, + patch( + "homeassistant.components.cloud.async_create_cloudhook", + return_value="https://hooks.nabu.casa/ABCD", + ), + patch( + "homeassistant.components.withings.async_get_config_entry_implementation", + ), + patch( + "homeassistant.components.cloud.async_delete_cloudhook", + ), + patch( + "homeassistant.components.withings.webhook_generate_url", + ), + ): + await setup_integration(hass, webhook_config_entry) + await prepare_webhook_setup(hass, freezer) + + assert cloud.async_active_subscription(hass) is True + assert cloud.async_is_connected(hass) is True + assert mock_async_active_subscription.call_count == 3 + + await hass.async_block_till_done() + + async_mock_cloud_connection_status(hass, False) + await hass.async_block_till_done() + + assert mock_async_active_subscription.call_count == 3 + + freezer.tick(timedelta(seconds=30)) + async_fire_time_changed(hass) + await hass.async_block_till_done() + + assert mock_async_active_subscription.call_count == 4 + + @pytest.mark.parametrize( ("body", "expected_code"), [ From 7eb6b2ca3362bd848be23563a3699d8206fb4a94 Mon Sep 17 00:00:00 2001 From: avee87 <6134677+avee87@users.noreply.github.com> Date: Fri, 19 Apr 2024 17:21:21 +0100 Subject: [PATCH 03/26] Fix Hyperion light not updating state (#115389) --- homeassistant/components/hyperion/sensor.py | 4 ++-- tests/components/hyperion/test_sensor.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/hyperion/sensor.py b/homeassistant/components/hyperion/sensor.py index f537c282686570..ad972806ae515e 100644 --- a/homeassistant/components/hyperion/sensor.py +++ b/homeassistant/components/hyperion/sensor.py @@ -191,13 +191,13 @@ def _update_priorities(self, _: dict[str, Any] | None = None) -> None: if priority[KEY_COMPONENTID] == "COLOR": state_value = priority[KEY_VALUE][KEY_RGB] else: - state_value = priority[KEY_OWNER] + state_value = priority.get(KEY_OWNER) attrs = { "component_id": priority[KEY_COMPONENTID], "origin": priority[KEY_ORIGIN], "priority": priority[KEY_PRIORITY], - "owner": priority[KEY_OWNER], + "owner": priority.get(KEY_OWNER), } if priority[KEY_COMPONENTID] == "COLOR": diff --git a/tests/components/hyperion/test_sensor.py b/tests/components/hyperion/test_sensor.py index 65991b4b7e1451..8900db177fc4bb 100644 --- a/tests/components/hyperion/test_sensor.py +++ b/tests/components/hyperion/test_sensor.py @@ -159,7 +159,6 @@ async def test_visible_effect_state_changes(hass: HomeAssistant) -> None: KEY_ACTIVE: True, KEY_COMPONENTID: "COLOR", KEY_ORIGIN: "System", - KEY_OWNER: "System", KEY_PRIORITY: 250, KEY_VALUE: {KEY_RGB: [0, 0, 0]}, KEY_VISIBLE: True, From 42c13eb57feffa6db9825fc0ecb61feb9ed129bb Mon Sep 17 00:00:00 2001 From: slyoldfox Date: Fri, 19 Apr 2024 18:22:12 +0200 Subject: [PATCH 04/26] Add scheduled mode to renault charge mode (#115427) Co-authored-by: epenet <6771947+epenet@users.noreply.github.com> --- homeassistant/components/renault/select.py | 2 +- tests/components/renault/const.py | 21 ++++++++++++++++--- .../renault/snapshots/test_select.ambr | 12 +++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/renault/select.py b/homeassistant/components/renault/select.py index f6c8f73d24be41..eb79e197937713 100644 --- a/homeassistant/components/renault/select.py +++ b/homeassistant/components/renault/select.py @@ -71,6 +71,6 @@ async def async_select_option(self, option: str) -> None: coordinator="charge_mode", data_key="chargeMode", translation_key="charge_mode", - options=["always", "always_charging", "schedule_mode"], + options=["always", "always_charging", "schedule_mode", "scheduled"], ), ) diff --git a/tests/components/renault/const.py b/tests/components/renault/const.py index d849c65814962c..19c40f6ec20e8a 100644 --- a/tests/components/renault/const.py +++ b/tests/components/renault/const.py @@ -127,7 +127,12 @@ { ATTR_ENTITY_ID: "select.reg_number_charge_mode", ATTR_ICON: "mdi:calendar-remove", - ATTR_OPTIONS: ["always", "always_charging", "schedule_mode"], + ATTR_OPTIONS: [ + "always", + "always_charging", + "schedule_mode", + "scheduled", + ], ATTR_STATE: "always", ATTR_UNIQUE_ID: "vf1aaaaa555777999_charge_mode", }, @@ -363,7 +368,12 @@ { ATTR_ENTITY_ID: "select.reg_number_charge_mode", ATTR_ICON: "mdi:calendar-clock", - ATTR_OPTIONS: ["always", "always_charging", "schedule_mode"], + ATTR_OPTIONS: [ + "always", + "always_charging", + "schedule_mode", + "scheduled", + ], ATTR_STATE: "schedule_mode", ATTR_UNIQUE_ID: "vf1aaaaa555777999_charge_mode", }, @@ -599,7 +609,12 @@ { ATTR_ENTITY_ID: "select.reg_number_charge_mode", ATTR_ICON: "mdi:calendar-remove", - ATTR_OPTIONS: ["always", "always_charging", "schedule_mode"], + ATTR_OPTIONS: [ + "always", + "always_charging", + "schedule_mode", + "scheduled", + ], ATTR_STATE: "always", ATTR_UNIQUE_ID: "vf1aaaaa555777123_charge_mode", }, diff --git a/tests/components/renault/snapshots/test_select.ambr b/tests/components/renault/snapshots/test_select.ambr index 7e8356ee070d4c..0722cb5cab32a6 100644 --- a/tests/components/renault/snapshots/test_select.ambr +++ b/tests/components/renault/snapshots/test_select.ambr @@ -82,6 +82,7 @@ 'always', 'always_charging', 'schedule_mode', + 'scheduled', ]), }), 'config_entry_id': , @@ -121,6 +122,7 @@ 'always', 'always_charging', 'schedule_mode', + 'scheduled', ]), }), 'context': , @@ -175,6 +177,7 @@ 'always', 'always_charging', 'schedule_mode', + 'scheduled', ]), }), 'config_entry_id': , @@ -214,6 +217,7 @@ 'always', 'always_charging', 'schedule_mode', + 'scheduled', ]), }), 'context': , @@ -268,6 +272,7 @@ 'always', 'always_charging', 'schedule_mode', + 'scheduled', ]), }), 'config_entry_id': , @@ -307,6 +312,7 @@ 'always', 'always_charging', 'schedule_mode', + 'scheduled', ]), }), 'context': , @@ -401,6 +407,7 @@ 'always', 'always_charging', 'schedule_mode', + 'scheduled', ]), }), 'config_entry_id': , @@ -440,6 +447,7 @@ 'always', 'always_charging', 'schedule_mode', + 'scheduled', ]), }), 'context': , @@ -494,6 +502,7 @@ 'always', 'always_charging', 'schedule_mode', + 'scheduled', ]), }), 'config_entry_id': , @@ -533,6 +542,7 @@ 'always', 'always_charging', 'schedule_mode', + 'scheduled', ]), }), 'context': , @@ -587,6 +597,7 @@ 'always', 'always_charging', 'schedule_mode', + 'scheduled', ]), }), 'config_entry_id': , @@ -626,6 +637,7 @@ 'always', 'always_charging', 'schedule_mode', + 'scheduled', ]), }), 'context': , From 624762451410ff0205f99d7861bf4eb9560ab867 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 12 Apr 2024 14:13:06 -1000 Subject: [PATCH 05/26] Bump zeroconf to 0.132.1 (#115501) --- 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 7c489517dd7e41..3bddbfea576e26 100644 --- a/homeassistant/components/zeroconf/manifest.json +++ b/homeassistant/components/zeroconf/manifest.json @@ -8,5 +8,5 @@ "iot_class": "local_push", "loggers": ["zeroconf"], "quality_scale": "internal", - "requirements": ["zeroconf==0.132.0"] + "requirements": ["zeroconf==0.132.1"] } diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 366f72cd2bcaef..a63e2853ad2f38 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -60,7 +60,7 @@ voluptuous-serialize==2.6.0 voluptuous==0.13.1 webrtc-noise-gain==1.2.3 yarl==1.9.4 -zeroconf==0.132.0 +zeroconf==0.132.1 # Constrain pycryptodome to avoid vulnerability # see https://github.com/home-assistant/core/pull/16238 diff --git a/requirements_all.txt b/requirements_all.txt index c93b665ea8c6ca..b0eae5b399a8f9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2928,7 +2928,7 @@ zamg==0.3.6 zengge==0.2 # homeassistant.components.zeroconf -zeroconf==0.132.0 +zeroconf==0.132.1 # homeassistant.components.zeversolar zeversolar==0.3.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index dfa71c7ac3ec9e..169b72e5acf0be 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2263,7 +2263,7 @@ yt-dlp==2024.04.09 zamg==0.3.6 # homeassistant.components.zeroconf -zeroconf==0.132.0 +zeroconf==0.132.1 # homeassistant.components.zeversolar zeversolar==0.3.1 From e1a241607619212787f3e3a6ab49ee956b243a2a Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 12 Apr 2024 19:05:08 -1000 Subject: [PATCH 06/26] Bump zeroconf to 0.132.2 (#115505) --- 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 3bddbfea576e26..0a76af3b9c2a9d 100644 --- a/homeassistant/components/zeroconf/manifest.json +++ b/homeassistant/components/zeroconf/manifest.json @@ -8,5 +8,5 @@ "iot_class": "local_push", "loggers": ["zeroconf"], "quality_scale": "internal", - "requirements": ["zeroconf==0.132.1"] + "requirements": ["zeroconf==0.132.2"] } diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index a63e2853ad2f38..9b481092ed45f2 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -60,7 +60,7 @@ voluptuous-serialize==2.6.0 voluptuous==0.13.1 webrtc-noise-gain==1.2.3 yarl==1.9.4 -zeroconf==0.132.1 +zeroconf==0.132.2 # Constrain pycryptodome to avoid vulnerability # see https://github.com/home-assistant/core/pull/16238 diff --git a/requirements_all.txt b/requirements_all.txt index b0eae5b399a8f9..6717c1db13853d 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2928,7 +2928,7 @@ zamg==0.3.6 zengge==0.2 # homeassistant.components.zeroconf -zeroconf==0.132.1 +zeroconf==0.132.2 # homeassistant.components.zeversolar zeversolar==0.3.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 169b72e5acf0be..2fba371b28755e 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2263,7 +2263,7 @@ yt-dlp==2024.04.09 zamg==0.3.6 # homeassistant.components.zeroconf -zeroconf==0.132.1 +zeroconf==0.132.2 # homeassistant.components.zeversolar zeversolar==0.3.1 From b770edc16ef020d62b404989178db7bca560f6d5 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Sat, 13 Apr 2024 18:26:33 +0200 Subject: [PATCH 07/26] Update pillow to 10.3.0 (#115524) --- homeassistant/components/doods/manifest.json | 2 +- homeassistant/components/generic/manifest.json | 2 +- homeassistant/components/image_upload/manifest.json | 2 +- homeassistant/components/matrix/manifest.json | 2 +- homeassistant/components/proxy/manifest.json | 2 +- homeassistant/components/qrcode/manifest.json | 2 +- homeassistant/components/seven_segments/manifest.json | 2 +- homeassistant/components/sighthound/manifest.json | 2 +- homeassistant/components/tensorflow/manifest.json | 2 +- homeassistant/package_constraints.txt | 2 +- pyproject.toml | 2 +- requirements.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/doods/manifest.json b/homeassistant/components/doods/manifest.json index 73d7d3754ce369..6a198ab34e7c1d 100644 --- a/homeassistant/components/doods/manifest.json +++ b/homeassistant/components/doods/manifest.json @@ -5,5 +5,5 @@ "documentation": "https://www.home-assistant.io/integrations/doods", "iot_class": "local_polling", "loggers": ["pydoods"], - "requirements": ["pydoods==1.0.2", "Pillow==10.2.0"] + "requirements": ["pydoods==1.0.2", "Pillow==10.3.0"] } diff --git a/homeassistant/components/generic/manifest.json b/homeassistant/components/generic/manifest.json index 861e2cf26c2453..65f6aa751caa7a 100644 --- a/homeassistant/components/generic/manifest.json +++ b/homeassistant/components/generic/manifest.json @@ -6,5 +6,5 @@ "dependencies": ["http"], "documentation": "https://www.home-assistant.io/integrations/generic", "iot_class": "local_push", - "requirements": ["ha-av==10.1.1", "Pillow==10.2.0"] + "requirements": ["ha-av==10.1.1", "Pillow==10.3.0"] } diff --git a/homeassistant/components/image_upload/manifest.json b/homeassistant/components/image_upload/manifest.json index ba9140b4ed8463..7cbc484b830ddc 100644 --- a/homeassistant/components/image_upload/manifest.json +++ b/homeassistant/components/image_upload/manifest.json @@ -7,5 +7,5 @@ "documentation": "https://www.home-assistant.io/integrations/image_upload", "integration_type": "system", "quality_scale": "internal", - "requirements": ["Pillow==10.2.0"] + "requirements": ["Pillow==10.3.0"] } diff --git a/homeassistant/components/matrix/manifest.json b/homeassistant/components/matrix/manifest.json index 0838bcc3764628..2ea310aa5a6761 100644 --- a/homeassistant/components/matrix/manifest.json +++ b/homeassistant/components/matrix/manifest.json @@ -5,5 +5,5 @@ "documentation": "https://www.home-assistant.io/integrations/matrix", "iot_class": "cloud_push", "loggers": ["matrix_client"], - "requirements": ["matrix-nio==0.24.0", "Pillow==10.2.0"] + "requirements": ["matrix-nio==0.24.0", "Pillow==10.3.0"] } diff --git a/homeassistant/components/proxy/manifest.json b/homeassistant/components/proxy/manifest.json index 1b05a768b641b8..42770d71792cd6 100644 --- a/homeassistant/components/proxy/manifest.json +++ b/homeassistant/components/proxy/manifest.json @@ -3,5 +3,5 @@ "name": "Camera Proxy", "codeowners": [], "documentation": "https://www.home-assistant.io/integrations/proxy", - "requirements": ["Pillow==10.2.0"] + "requirements": ["Pillow==10.3.0"] } diff --git a/homeassistant/components/qrcode/manifest.json b/homeassistant/components/qrcode/manifest.json index e3b202a995048d..476f4e8c3c9be3 100644 --- a/homeassistant/components/qrcode/manifest.json +++ b/homeassistant/components/qrcode/manifest.json @@ -5,5 +5,5 @@ "documentation": "https://www.home-assistant.io/integrations/qrcode", "iot_class": "calculated", "loggers": ["pyzbar"], - "requirements": ["Pillow==10.2.0", "pyzbar==0.1.7"] + "requirements": ["Pillow==10.3.0", "pyzbar==0.1.7"] } diff --git a/homeassistant/components/seven_segments/manifest.json b/homeassistant/components/seven_segments/manifest.json index 6c511e3f44e76c..5e05f496d1d634 100644 --- a/homeassistant/components/seven_segments/manifest.json +++ b/homeassistant/components/seven_segments/manifest.json @@ -4,5 +4,5 @@ "codeowners": ["@fabaff"], "documentation": "https://www.home-assistant.io/integrations/seven_segments", "iot_class": "local_polling", - "requirements": ["Pillow==10.2.0"] + "requirements": ["Pillow==10.3.0"] } diff --git a/homeassistant/components/sighthound/manifest.json b/homeassistant/components/sighthound/manifest.json index e63864af707f03..b97ccc5f9cf944 100644 --- a/homeassistant/components/sighthound/manifest.json +++ b/homeassistant/components/sighthound/manifest.json @@ -5,5 +5,5 @@ "documentation": "https://www.home-assistant.io/integrations/sighthound", "iot_class": "cloud_polling", "loggers": ["simplehound"], - "requirements": ["Pillow==10.2.0", "simplehound==0.3"] + "requirements": ["Pillow==10.3.0", "simplehound==0.3"] } diff --git a/homeassistant/components/tensorflow/manifest.json b/homeassistant/components/tensorflow/manifest.json index b98c4c6e428775..40dbadca64dedd 100644 --- a/homeassistant/components/tensorflow/manifest.json +++ b/homeassistant/components/tensorflow/manifest.json @@ -10,6 +10,6 @@ "tf-models-official==2.5.0", "pycocotools==2.0.6", "numpy==1.26.0", - "Pillow==10.2.0" + "Pillow==10.3.0" ] } diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 9b481092ed45f2..13a28e34d281fc 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -40,7 +40,7 @@ mutagen==1.47.0 orjson==3.9.15 packaging>=23.1 paho-mqtt==1.6.1 -Pillow==10.2.0 +Pillow==10.3.0 pip>=21.3.1 psutil-home-assistant==0.0.1 PyJWT==2.8.0 diff --git a/pyproject.toml b/pyproject.toml index 74b6f6fa54ed2e..3a206a3f7fab81 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,7 @@ dependencies = [ "PyJWT==2.8.0", # PyJWT has loose dependency. We want the latest one. "cryptography==42.0.5", - "Pillow==10.2.0", + "Pillow==10.3.0", "pyOpenSSL==24.1.0", "orjson==3.9.15", "packaging>=23.1", diff --git a/requirements.txt b/requirements.txt index 519a8287d1821a..5635c4912e9a9e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,7 +24,7 @@ Jinja2==3.1.3 lru-dict==1.3.0 PyJWT==2.8.0 cryptography==42.0.5 -Pillow==10.2.0 +Pillow==10.3.0 pyOpenSSL==24.1.0 orjson==3.9.15 packaging>=23.1 diff --git a/requirements_all.txt b/requirements_all.txt index 6717c1db13853d..640ad0e2306c8a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -42,7 +42,7 @@ Mastodon.py==1.8.1 # homeassistant.components.seven_segments # homeassistant.components.sighthound # homeassistant.components.tensorflow -Pillow==10.2.0 +Pillow==10.3.0 # homeassistant.components.plex PlexAPI==4.15.11 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 2fba371b28755e..a65320152be86d 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -36,7 +36,7 @@ HATasmota==0.8.0 # homeassistant.components.seven_segments # homeassistant.components.sighthound # homeassistant.components.tensorflow -Pillow==10.2.0 +Pillow==10.3.0 # homeassistant.components.plex PlexAPI==4.15.11 From 038040db5e06c128b29703690fd4ca75ddace7ac Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Sat, 13 Apr 2024 10:35:07 -1000 Subject: [PATCH 08/26] Fix race in TimestampDataUpdateCoordinator (#115542) * Fix race in TimestampDataUpdateCoordinator The last_update_success_time value was being set after the listeners were fired which could lead to a loop because the listener may re-trigger an update because it thinks the data is stale * coverage * docstring --- homeassistant/helpers/update_coordinator.py | 28 ++++++++-------- tests/helpers/test_update_coordinator.py | 36 +++++++++++++++++++-- 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/homeassistant/helpers/update_coordinator.py b/homeassistant/helpers/update_coordinator.py index 287e69f7085d63..98e635e5ac7c78 100644 --- a/homeassistant/helpers/update_coordinator.py +++ b/homeassistant/helpers/update_coordinator.py @@ -403,6 +403,8 @@ async def _async_refresh( # noqa: C901 if not auth_failed and self._listeners and not self.hass.is_stopping: self._schedule_refresh() + self._async_refresh_finished() + if not self.last_update_success and not previous_update_success: return @@ -413,6 +415,15 @@ async def _async_refresh( # noqa: C901 ): self.async_update_listeners() + @callback + def _async_refresh_finished(self) -> None: + """Handle when a refresh has finished. + + Called when refresh is finished before listeners are updated. + + To be overridden by subclasses. + """ + @callback def async_set_update_error(self, err: Exception) -> None: """Manually set an error, log the message and notify listeners.""" @@ -446,20 +457,9 @@ class TimestampDataUpdateCoordinator(DataUpdateCoordinator[_DataT]): last_update_success_time: datetime | None = None - async def _async_refresh( - self, - log_failures: bool = True, - raise_on_auth_failed: bool = False, - scheduled: bool = False, - raise_on_entry_error: bool = False, - ) -> None: - """Refresh data.""" - await super()._async_refresh( - log_failures, - raise_on_auth_failed, - scheduled, - raise_on_entry_error, - ) + @callback + def _async_refresh_finished(self) -> None: + """Handle when a refresh has finished.""" if self.last_update_success: self.last_update_success_time = utcnow() diff --git a/tests/helpers/test_update_coordinator.py b/tests/helpers/test_update_coordinator.py index 25f72d76e3c8cc..775dc08f1d4c95 100644 --- a/tests/helpers/test_update_coordinator.py +++ b/tests/helpers/test_update_coordinator.py @@ -1,6 +1,6 @@ """Tests for the update coordinator.""" -from datetime import timedelta +from datetime import datetime, timedelta import logging from unittest.mock import AsyncMock, Mock, patch import urllib.error @@ -12,7 +12,7 @@ from homeassistant import config_entries from homeassistant.const import EVENT_HOMEASSISTANT_STOP -from homeassistant.core import CoreState, HomeAssistant +from homeassistant.core import CoreState, HomeAssistant, callback from homeassistant.exceptions import ConfigEntryNotReady from homeassistant.helpers import update_coordinator from homeassistant.util.dt import utcnow @@ -716,3 +716,35 @@ async def _update_method() -> int: update_callback.reset_mock() remove_callbacks() + + +async def test_timestamp_date_update_coordinator(hass: HomeAssistant) -> None: + """Test last_update_success_time is set before calling listeners.""" + last_update_success_times: list[datetime | None] = [] + + async def refresh() -> int: + return 1 + + crd = update_coordinator.TimestampDataUpdateCoordinator[int]( + hass, + _LOGGER, + name="test", + update_method=refresh, + update_interval=timedelta(seconds=10), + ) + + @callback + def listener(): + last_update_success_times.append(crd.last_update_success_time) + + unsub = crd.async_add_listener(listener) + + await crd.async_refresh() + + assert len(last_update_success_times) == 1 + # Ensure the time is set before the listener is called + assert last_update_success_times != [None] + + unsub() + await crd.async_refresh() + assert len(last_update_success_times) == 1 From 37a82c878514c4377c51cbeee7396d436271c91e Mon Sep 17 00:00:00 2001 From: Brett Adams Date: Mon, 15 Apr 2024 09:48:22 +1000 Subject: [PATCH 09/26] Fix Teslemetry sensor values (#115571) --- homeassistant/components/teslemetry/sensor.py | 5 + .../teslemetry/snapshots/test_sensor.ambr | 100 +++++++++--------- 2 files changed, 55 insertions(+), 50 deletions(-) diff --git a/homeassistant/components/teslemetry/sensor.py b/homeassistant/components/teslemetry/sensor.py index 6284a0e5368e8d..cced1090e2afa9 100644 --- a/homeassistant/components/teslemetry/sensor.py +++ b/homeassistant/components/teslemetry/sensor.py @@ -449,6 +449,11 @@ def __init__( """Initialize the sensor.""" super().__init__(vehicle, description.key) + @property + def native_value(self) -> StateType: + """Return the state of the sensor.""" + return self._value + class TeslemetryVehicleTimeSensorEntity(TeslemetryVehicleEntity, SensorEntity): """Base class for Teslemetry vehicle metric sensors.""" diff --git a/tests/components/teslemetry/snapshots/test_sensor.ambr b/tests/components/teslemetry/snapshots/test_sensor.ambr index fad04d341c946a..81142e40901fdf 100644 --- a/tests/components/teslemetry/snapshots/test_sensor.ambr +++ b/tests/components/teslemetry/snapshots/test_sensor.ambr @@ -757,7 +757,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '77', }) # --- # name: test_sensors[sensor.test_battery_level-statealt] @@ -770,7 +770,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '77', }) # --- # name: test_sensors[sensor.test_battery_range-entry] @@ -816,7 +816,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '266.87', }) # --- # name: test_sensors[sensor.test_battery_range-statealt] @@ -829,7 +829,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '266.87', }) # --- # name: test_sensors[sensor.test_charge_cable-entry] @@ -875,7 +875,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': 'IEC', }) # --- # name: test_sensors[sensor.test_charge_cable-statealt] @@ -888,7 +888,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': 'IEC', }) # --- # name: test_sensors[sensor.test_charge_energy_added-entry] @@ -934,7 +934,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '0', }) # --- # name: test_sensors[sensor.test_charge_energy_added-statealt] @@ -947,7 +947,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '0', }) # --- # name: test_sensors[sensor.test_charge_rate-entry] @@ -993,7 +993,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '0', }) # --- # name: test_sensors[sensor.test_charge_rate-statealt] @@ -1006,7 +1006,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '0', }) # --- # name: test_sensors[sensor.test_charger_current-entry] @@ -1052,7 +1052,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '0', }) # --- # name: test_sensors[sensor.test_charger_current-statealt] @@ -1065,7 +1065,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '0', }) # --- # name: test_sensors[sensor.test_charger_power-entry] @@ -1111,7 +1111,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '0', }) # --- # name: test_sensors[sensor.test_charger_power-statealt] @@ -1124,7 +1124,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '0', }) # --- # name: test_sensors[sensor.test_charger_voltage-entry] @@ -1170,7 +1170,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '2', }) # --- # name: test_sensors[sensor.test_charger_voltage-statealt] @@ -1183,7 +1183,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '2', }) # --- # name: test_sensors[sensor.test_charging-entry] @@ -1229,7 +1229,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': 'Stopped', }) # --- # name: test_sensors[sensor.test_charging-statealt] @@ -1242,7 +1242,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': 'Stopped', }) # --- # name: test_sensors[sensor.test_distance_to_arrival-entry] @@ -1288,7 +1288,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '0.039491', }) # --- # name: test_sensors[sensor.test_distance_to_arrival-statealt] @@ -1301,7 +1301,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '0', }) # --- # name: test_sensors[sensor.test_driver_temperature_setting-entry] @@ -1347,7 +1347,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '22', }) # --- # name: test_sensors[sensor.test_driver_temperature_setting-statealt] @@ -1360,7 +1360,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '22', }) # --- # name: test_sensors[sensor.test_estimate_battery_range-entry] @@ -1406,7 +1406,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '275.04', }) # --- # name: test_sensors[sensor.test_estimate_battery_range-statealt] @@ -1419,7 +1419,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '275.04', }) # --- # name: test_sensors[sensor.test_fast_charger_type-entry] @@ -1465,7 +1465,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': 'ACSingleWireCAN', }) # --- # name: test_sensors[sensor.test_fast_charger_type-statealt] @@ -1478,7 +1478,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': 'ACSingleWireCAN', }) # --- # name: test_sensors[sensor.test_ideal_battery_range-entry] @@ -1524,7 +1524,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '266.87', }) # --- # name: test_sensors[sensor.test_ideal_battery_range-statealt] @@ -1537,7 +1537,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '266.87', }) # --- # name: test_sensors[sensor.test_inside_temperature-entry] @@ -1583,7 +1583,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '29.8', }) # --- # name: test_sensors[sensor.test_inside_temperature-statealt] @@ -1596,7 +1596,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '29.8', }) # --- # name: test_sensors[sensor.test_odometer-entry] @@ -1642,7 +1642,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '6481.019282', }) # --- # name: test_sensors[sensor.test_odometer-statealt] @@ -1655,7 +1655,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '6481.019282', }) # --- # name: test_sensors[sensor.test_outside_temperature-entry] @@ -1701,7 +1701,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '30', }) # --- # name: test_sensors[sensor.test_outside_temperature-statealt] @@ -1714,7 +1714,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '30', }) # --- # name: test_sensors[sensor.test_passenger_temperature_setting-entry] @@ -1760,7 +1760,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '22', }) # --- # name: test_sensors[sensor.test_passenger_temperature_setting-statealt] @@ -1773,7 +1773,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '22', }) # --- # name: test_sensors[sensor.test_power-entry] @@ -1819,7 +1819,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '-7', }) # --- # name: test_sensors[sensor.test_power-statealt] @@ -1832,7 +1832,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '-7', }) # --- # name: test_sensors[sensor.test_shift_state-entry] @@ -2177,7 +2177,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '2.775', }) # --- # name: test_sensors[sensor.test_tire_pressure_front_left-statealt] @@ -2190,7 +2190,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '2.775', }) # --- # name: test_sensors[sensor.test_tire_pressure_front_right-entry] @@ -2236,7 +2236,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '2.8', }) # --- # name: test_sensors[sensor.test_tire_pressure_front_right-statealt] @@ -2249,7 +2249,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '2.8', }) # --- # name: test_sensors[sensor.test_tire_pressure_rear_left-entry] @@ -2295,7 +2295,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '2.775', }) # --- # name: test_sensors[sensor.test_tire_pressure_rear_left-statealt] @@ -2308,7 +2308,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '2.775', }) # --- # name: test_sensors[sensor.test_tire_pressure_rear_right-entry] @@ -2354,7 +2354,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '2.775', }) # --- # name: test_sensors[sensor.test_tire_pressure_rear_right-statealt] @@ -2367,7 +2367,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '2.775', }) # --- # name: test_sensors[sensor.test_traffic_delay-entry] @@ -2413,7 +2413,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '0', }) # --- # name: test_sensors[sensor.test_traffic_delay-statealt] @@ -2426,7 +2426,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '0', }) # --- # name: test_sensors[sensor.test_usable_battery_level-entry] @@ -2472,7 +2472,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '77', }) # --- # name: test_sensors[sensor.test_usable_battery_level-statealt] @@ -2485,7 +2485,7 @@ 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '77', }) # --- # name: test_sensors[sensor.wall_connector_fault_state_code-entry] From 3d68ee99a4e653b6740934cc429e0256a5ceaf0a Mon Sep 17 00:00:00 2001 From: jan iversen Date: Sun, 14 Apr 2024 19:22:42 +0200 Subject: [PATCH 10/26] Modbus: Bump pymodbus v3.6.8 (#115574) --- homeassistant/components/modbus/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/modbus/manifest.json b/homeassistant/components/modbus/manifest.json index 0fe8c7bc42dab8..5635adc939211d 100644 --- a/homeassistant/components/modbus/manifest.json +++ b/homeassistant/components/modbus/manifest.json @@ -6,5 +6,5 @@ "iot_class": "local_polling", "loggers": ["pymodbus"], "quality_scale": "platinum", - "requirements": ["pymodbus==3.6.7"] + "requirements": ["pymodbus==3.6.8"] } diff --git a/requirements_all.txt b/requirements_all.txt index 640ad0e2306c8a..0c1725ca089c0e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1973,7 +1973,7 @@ pymitv==1.4.3 pymochad==0.2.0 # homeassistant.components.modbus -pymodbus==3.6.7 +pymodbus==3.6.8 # homeassistant.components.monoprice pymonoprice==0.4 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index a65320152be86d..ced79b46ae8cac 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1533,7 +1533,7 @@ pymeteoclimatic==0.1.0 pymochad==0.2.0 # homeassistant.components.modbus -pymodbus==3.6.7 +pymodbus==3.6.8 # homeassistant.components.monoprice pymonoprice==0.4 From 66918d1686415d5abc51d2440c8b1211b28fbe7b Mon Sep 17 00:00:00 2001 From: Brett Adams Date: Sun, 21 Apr 2024 07:54:24 +1000 Subject: [PATCH 11/26] Fix sensor entity description in Teslemetry (#115614) Add description back to sensor entity --- homeassistant/components/teslemetry/sensor.py | 5 +- .../teslemetry/snapshots/test_sensor.ambr | 538 ++++++++++++++---- 2 files changed, 428 insertions(+), 115 deletions(-) diff --git a/homeassistant/components/teslemetry/sensor.py b/homeassistant/components/teslemetry/sensor.py index cced1090e2afa9..6380a4d0c71221 100644 --- a/homeassistant/components/teslemetry/sensor.py +++ b/homeassistant/components/teslemetry/sensor.py @@ -58,7 +58,7 @@ class TeslemetrySensorEntityDescription(SensorEntityDescription): """Describes Teslemetry Sensor entity.""" - value_fn: Callable[[StateType], StateType | datetime] = lambda x: x + value_fn: Callable[[StateType], StateType] = lambda x: x VEHICLE_DESCRIPTIONS: tuple[TeslemetrySensorEntityDescription, ...] = ( @@ -447,12 +447,13 @@ def __init__( description: TeslemetrySensorEntityDescription, ) -> None: """Initialize the sensor.""" + self.entity_description = description super().__init__(vehicle, description.key) @property def native_value(self) -> StateType: """Return the state of the sensor.""" - return self._value + return self.entity_description.value_fn(self._value) class TeslemetryVehicleTimeSensorEntity(TeslemetryVehicleEntity, SensorEntity): diff --git a/tests/components/teslemetry/snapshots/test_sensor.ambr b/tests/components/teslemetry/snapshots/test_sensor.ambr index 81142e40901fdf..0d817ad1f7e460 100644 --- a/tests/components/teslemetry/snapshots/test_sensor.ambr +++ b/tests/components/teslemetry/snapshots/test_sensor.ambr @@ -719,7 +719,9 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , @@ -736,7 +738,7 @@ 'name': None, 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Battery level', 'platform': 'teslemetry', @@ -744,13 +746,16 @@ 'supported_features': 0, 'translation_key': 'charge_state_battery_level', 'unique_id': 'VINVINVIN-charge_state_battery_level', - 'unit_of_measurement': None, + 'unit_of_measurement': '%', }) # --- # name: test_sensors[sensor.test_battery_level-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'battery', 'friendly_name': 'Test Battery level', + 'state_class': , + 'unit_of_measurement': '%', }), 'context': , 'entity_id': 'sensor.test_battery_level', @@ -763,7 +768,10 @@ # name: test_sensors[sensor.test_battery_level-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'battery', 'friendly_name': 'Test Battery level', + 'state_class': , + 'unit_of_measurement': '%', }), 'context': , 'entity_id': 'sensor.test_battery_level', @@ -778,7 +786,9 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , @@ -794,8 +804,14 @@ }), 'name': None, 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Battery range', 'platform': 'teslemetry', @@ -803,33 +819,39 @@ 'supported_features': 0, 'translation_key': 'charge_state_battery_range', 'unique_id': 'VINVINVIN-charge_state_battery_range', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_battery_range-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'distance', 'friendly_name': 'Test Battery range', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_battery_range', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '266.87', + 'state': '429.48563328', }) # --- # name: test_sensors[sensor.test_battery_range-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'distance', 'friendly_name': 'Test Battery range', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_battery_range', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '266.87', + 'state': '429.48563328', }) # --- # name: test_sensors[sensor.test_charge_cable-entry] @@ -843,7 +865,7 @@ 'device_id': , 'disabled_by': None, 'domain': 'sensor', - 'entity_category': None, + 'entity_category': , 'entity_id': 'sensor.test_charge_cable', 'has_entity_name': True, 'hidden_by': None, @@ -896,7 +918,9 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , @@ -912,8 +936,11 @@ }), 'name': None, 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Charge energy added', 'platform': 'teslemetry', @@ -921,13 +948,16 @@ 'supported_features': 0, 'translation_key': 'charge_state_charge_energy_added', 'unique_id': 'VINVINVIN-charge_state_charge_energy_added', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_charge_energy_added-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'energy', 'friendly_name': 'Test Charge energy added', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_charge_energy_added', @@ -940,7 +970,10 @@ # name: test_sensors[sensor.test_charge_energy_added-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'energy', 'friendly_name': 'Test Charge energy added', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_charge_energy_added', @@ -955,13 +988,15 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , 'disabled_by': None, 'domain': 'sensor', - 'entity_category': None, + 'entity_category': , 'entity_id': 'sensor.test_charge_rate', 'has_entity_name': True, 'hidden_by': None, @@ -971,8 +1006,11 @@ }), 'name': None, 'options': dict({ + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Charge rate', 'platform': 'teslemetry', @@ -980,13 +1018,16 @@ 'supported_features': 0, 'translation_key': 'charge_state_charge_rate', 'unique_id': 'VINVINVIN-charge_state_charge_rate', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_charge_rate-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'speed', 'friendly_name': 'Test Charge rate', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_charge_rate', @@ -999,7 +1040,10 @@ # name: test_sensors[sensor.test_charge_rate-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'speed', 'friendly_name': 'Test Charge rate', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_charge_rate', @@ -1014,13 +1058,15 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , 'disabled_by': None, 'domain': 'sensor', - 'entity_category': None, + 'entity_category': , 'entity_id': 'sensor.test_charger_current', 'has_entity_name': True, 'hidden_by': None, @@ -1031,7 +1077,7 @@ 'name': None, 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Charger current', 'platform': 'teslemetry', @@ -1039,13 +1085,16 @@ 'supported_features': 0, 'translation_key': 'charge_state_charger_actual_current', 'unique_id': 'VINVINVIN-charge_state_charger_actual_current', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_charger_current-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'current', 'friendly_name': 'Test Charger current', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_charger_current', @@ -1058,7 +1107,10 @@ # name: test_sensors[sensor.test_charger_current-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'current', 'friendly_name': 'Test Charger current', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_charger_current', @@ -1073,7 +1125,9 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , @@ -1090,7 +1144,7 @@ 'name': None, 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Charger power', 'platform': 'teslemetry', @@ -1098,13 +1152,16 @@ 'supported_features': 0, 'translation_key': 'charge_state_charger_power', 'unique_id': 'VINVINVIN-charge_state_charger_power', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_charger_power-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'power', 'friendly_name': 'Test Charger power', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_charger_power', @@ -1117,7 +1174,10 @@ # name: test_sensors[sensor.test_charger_power-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'power', 'friendly_name': 'Test Charger power', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_charger_power', @@ -1132,13 +1192,15 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , 'disabled_by': None, 'domain': 'sensor', - 'entity_category': None, + 'entity_category': , 'entity_id': 'sensor.test_charger_voltage', 'has_entity_name': True, 'hidden_by': None, @@ -1149,7 +1211,7 @@ 'name': None, 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Charger voltage', 'platform': 'teslemetry', @@ -1157,13 +1219,16 @@ 'supported_features': 0, 'translation_key': 'charge_state_charger_voltage', 'unique_id': 'VINVINVIN-charge_state_charger_voltage', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_charger_voltage-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', 'friendly_name': 'Test Charger voltage', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_charger_voltage', @@ -1176,7 +1241,10 @@ # name: test_sensors[sensor.test_charger_voltage-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'voltage', 'friendly_name': 'Test Charger voltage', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_charger_voltage', @@ -1191,7 +1259,16 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'options': list([ + 'starting', + 'charging', + 'stopped', + 'complete', + 'disconnected', + 'no_power', + ]), + }), 'config_entry_id': , 'device_class': None, 'device_id': , @@ -1208,7 +1285,7 @@ 'name': None, 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Charging', 'platform': 'teslemetry', @@ -1222,27 +1299,45 @@ # name: test_sensors[sensor.test_charging-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'enum', 'friendly_name': 'Test Charging', + 'options': list([ + 'starting', + 'charging', + 'stopped', + 'complete', + 'disconnected', + 'no_power', + ]), }), 'context': , 'entity_id': 'sensor.test_charging', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'Stopped', + 'state': 'stopped', }) # --- # name: test_sensors[sensor.test_charging-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'enum', 'friendly_name': 'Test Charging', + 'options': list([ + 'starting', + 'charging', + 'stopped', + 'complete', + 'disconnected', + 'no_power', + ]), }), 'context': , 'entity_id': 'sensor.test_charging', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'Stopped', + 'state': 'stopped', }) # --- # name: test_sensors[sensor.test_distance_to_arrival-entry] @@ -1250,7 +1345,9 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , @@ -1266,8 +1363,11 @@ }), 'name': None, 'options': dict({ + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Distance to arrival', 'platform': 'teslemetry', @@ -1275,26 +1375,32 @@ 'supported_features': 0, 'translation_key': 'drive_state_active_route_miles_to_arrival', 'unique_id': 'VINVINVIN-drive_state_active_route_miles_to_arrival', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_distance_to_arrival-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'distance', 'friendly_name': 'Test Distance to arrival', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_distance_to_arrival', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '0.039491', + 'state': '0.063555', }) # --- # name: test_sensors[sensor.test_distance_to_arrival-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'distance', 'friendly_name': 'Test Distance to arrival', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_distance_to_arrival', @@ -1309,13 +1415,15 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , 'disabled_by': None, 'domain': 'sensor', - 'entity_category': None, + 'entity_category': , 'entity_id': 'sensor.test_driver_temperature_setting', 'has_entity_name': True, 'hidden_by': None, @@ -1325,8 +1433,11 @@ }), 'name': None, 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Driver temperature setting', 'platform': 'teslemetry', @@ -1334,13 +1445,16 @@ 'supported_features': 0, 'translation_key': 'climate_state_driver_temp_setting', 'unique_id': 'VINVINVIN-climate_state_driver_temp_setting', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_driver_temperature_setting-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', 'friendly_name': 'Test Driver temperature setting', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_driver_temperature_setting', @@ -1353,7 +1467,10 @@ # name: test_sensors[sensor.test_driver_temperature_setting-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', 'friendly_name': 'Test Driver temperature setting', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_driver_temperature_setting', @@ -1368,7 +1485,9 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , @@ -1384,8 +1503,14 @@ }), 'name': None, 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Estimate battery range', 'platform': 'teslemetry', @@ -1393,33 +1518,39 @@ 'supported_features': 0, 'translation_key': 'charge_state_est_battery_range', 'unique_id': 'VINVINVIN-charge_state_est_battery_range', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_estimate_battery_range-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'distance', 'friendly_name': 'Test Estimate battery range', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_estimate_battery_range', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '275.04', + 'state': '442.63397376', }) # --- # name: test_sensors[sensor.test_estimate_battery_range-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'distance', 'friendly_name': 'Test Estimate battery range', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_estimate_battery_range', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '275.04', + 'state': '442.63397376', }) # --- # name: test_sensors[sensor.test_fast_charger_type-entry] @@ -1433,7 +1564,7 @@ 'device_id': , 'disabled_by': None, 'domain': 'sensor', - 'entity_category': None, + 'entity_category': , 'entity_id': 'sensor.test_fast_charger_type', 'has_entity_name': True, 'hidden_by': None, @@ -1486,7 +1617,9 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , @@ -1502,8 +1635,14 @@ }), 'name': None, 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Ideal battery range', 'platform': 'teslemetry', @@ -1511,33 +1650,39 @@ 'supported_features': 0, 'translation_key': 'charge_state_ideal_battery_range', 'unique_id': 'VINVINVIN-charge_state_ideal_battery_range', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_ideal_battery_range-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'distance', 'friendly_name': 'Test Ideal battery range', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_ideal_battery_range', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '266.87', + 'state': '429.48563328', }) # --- # name: test_sensors[sensor.test_ideal_battery_range-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'distance', 'friendly_name': 'Test Ideal battery range', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_ideal_battery_range', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '266.87', + 'state': '429.48563328', }) # --- # name: test_sensors[sensor.test_inside_temperature-entry] @@ -1545,7 +1690,9 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , @@ -1561,8 +1708,11 @@ }), 'name': None, 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Inside temperature', 'platform': 'teslemetry', @@ -1570,13 +1720,16 @@ 'supported_features': 0, 'translation_key': 'climate_state_inside_temp', 'unique_id': 'VINVINVIN-climate_state_inside_temp', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_inside_temperature-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', 'friendly_name': 'Test Inside temperature', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_inside_temperature', @@ -1589,7 +1742,10 @@ # name: test_sensors[sensor.test_inside_temperature-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', 'friendly_name': 'Test Inside temperature', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_inside_temperature', @@ -1604,13 +1760,15 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , 'disabled_by': None, 'domain': 'sensor', - 'entity_category': None, + 'entity_category': , 'entity_id': 'sensor.test_odometer', 'has_entity_name': True, 'hidden_by': None, @@ -1620,8 +1778,14 @@ }), 'name': None, 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 0, + }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Odometer', 'platform': 'teslemetry', @@ -1629,33 +1793,39 @@ 'supported_features': 0, 'translation_key': 'vehicle_state_odometer', 'unique_id': 'VINVINVIN-vehicle_state_odometer', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_odometer-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'distance', 'friendly_name': 'Test Odometer', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_odometer', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '6481.019282', + 'state': '10430.189495371', }) # --- # name: test_sensors[sensor.test_odometer-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'distance', 'friendly_name': 'Test Odometer', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_odometer', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '6481.019282', + 'state': '10430.189495371', }) # --- # name: test_sensors[sensor.test_outside_temperature-entry] @@ -1663,7 +1833,9 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , @@ -1679,8 +1851,11 @@ }), 'name': None, 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Outside temperature', 'platform': 'teslemetry', @@ -1688,13 +1863,16 @@ 'supported_features': 0, 'translation_key': 'climate_state_outside_temp', 'unique_id': 'VINVINVIN-climate_state_outside_temp', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_outside_temperature-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', 'friendly_name': 'Test Outside temperature', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_outside_temperature', @@ -1707,7 +1885,10 @@ # name: test_sensors[sensor.test_outside_temperature-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', 'friendly_name': 'Test Outside temperature', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_outside_temperature', @@ -1722,13 +1903,15 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , 'disabled_by': None, 'domain': 'sensor', - 'entity_category': None, + 'entity_category': , 'entity_id': 'sensor.test_passenger_temperature_setting', 'has_entity_name': True, 'hidden_by': None, @@ -1738,8 +1921,11 @@ }), 'name': None, 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Passenger temperature setting', 'platform': 'teslemetry', @@ -1747,13 +1933,16 @@ 'supported_features': 0, 'translation_key': 'climate_state_passenger_temp_setting', 'unique_id': 'VINVINVIN-climate_state_passenger_temp_setting', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_passenger_temperature_setting-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', 'friendly_name': 'Test Passenger temperature setting', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_passenger_temperature_setting', @@ -1766,7 +1955,10 @@ # name: test_sensors[sensor.test_passenger_temperature_setting-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'temperature', 'friendly_name': 'Test Passenger temperature setting', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_passenger_temperature_setting', @@ -1781,13 +1973,15 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , 'disabled_by': None, 'domain': 'sensor', - 'entity_category': None, + 'entity_category': , 'entity_id': 'sensor.test_power', 'has_entity_name': True, 'hidden_by': None, @@ -1798,7 +1992,7 @@ 'name': None, 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Power', 'platform': 'teslemetry', @@ -1806,13 +2000,16 @@ 'supported_features': 0, 'translation_key': 'drive_state_power', 'unique_id': 'VINVINVIN-drive_state_power', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_power-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'power', 'friendly_name': 'Test Power', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_power', @@ -1825,7 +2022,10 @@ # name: test_sensors[sensor.test_power-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'power', 'friendly_name': 'Test Power', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_power', @@ -1840,7 +2040,14 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'options': list([ + 'p', + 'd', + 'r', + 'n', + ]), + }), 'config_entry_id': , 'device_class': None, 'device_id': , @@ -1857,7 +2064,7 @@ 'name': None, 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Shift state', 'platform': 'teslemetry', @@ -1871,27 +2078,41 @@ # name: test_sensors[sensor.test_shift_state-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'enum', 'friendly_name': 'Test Shift state', + 'options': list([ + 'p', + 'd', + 'r', + 'n', + ]), }), 'context': , 'entity_id': 'sensor.test_shift_state', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': 'p', }) # --- # name: test_sensors[sensor.test_shift_state-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'enum', 'friendly_name': 'Test Shift state', + 'options': list([ + 'p', + 'd', + 'r', + 'n', + ]), }), 'context': , 'entity_id': 'sensor.test_shift_state', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': 'p', }) # --- # name: test_sensors[sensor.test_speed-entry] @@ -1899,7 +2120,9 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , @@ -1915,8 +2138,11 @@ }), 'name': None, 'options': dict({ + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Speed', 'platform': 'teslemetry', @@ -1924,33 +2150,39 @@ 'supported_features': 0, 'translation_key': 'drive_state_speed', 'unique_id': 'VINVINVIN-drive_state_speed', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_speed-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'speed', 'friendly_name': 'Test Speed', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_speed', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '0', }) # --- # name: test_sensors[sensor.test_speed-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'speed', 'friendly_name': 'Test Speed', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_speed', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': 'unknown', + 'state': '0', }) # --- # name: test_sensors[sensor.test_state_of_charge_at_arrival-entry] @@ -1958,13 +2190,15 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , 'disabled_by': None, 'domain': 'sensor', - 'entity_category': None, + 'entity_category': , 'entity_id': 'sensor.test_state_of_charge_at_arrival', 'has_entity_name': True, 'hidden_by': None, @@ -1975,7 +2209,7 @@ 'name': None, 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'State of charge at arrival', 'platform': 'teslemetry', @@ -1983,13 +2217,16 @@ 'supported_features': 0, 'translation_key': 'drive_state_active_route_energy_at_arrival', 'unique_id': 'VINVINVIN-drive_state_active_route_energy_at_arrival', - 'unit_of_measurement': None, + 'unit_of_measurement': '%', }) # --- # name: test_sensors[sensor.test_state_of_charge_at_arrival-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'battery', 'friendly_name': 'Test State of charge at arrival', + 'state_class': , + 'unit_of_measurement': '%', }), 'context': , 'entity_id': 'sensor.test_state_of_charge_at_arrival', @@ -2002,7 +2239,10 @@ # name: test_sensors[sensor.test_state_of_charge_at_arrival-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'battery', 'friendly_name': 'Test State of charge at arrival', + 'state_class': , + 'unit_of_measurement': '%', }), 'context': , 'entity_id': 'sensor.test_state_of_charge_at_arrival', @@ -2139,13 +2379,15 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , 'disabled_by': None, 'domain': 'sensor', - 'entity_category': None, + 'entity_category': , 'entity_id': 'sensor.test_tire_pressure_front_left', 'has_entity_name': True, 'hidden_by': None, @@ -2155,8 +2397,14 @@ }), 'name': None, 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Tire pressure front left', 'platform': 'teslemetry', @@ -2164,33 +2412,39 @@ 'supported_features': 0, 'translation_key': 'vehicle_state_tpms_pressure_fl', 'unique_id': 'VINVINVIN-vehicle_state_tpms_pressure_fl', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_tire_pressure_front_left-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'pressure', 'friendly_name': 'Test Tire pressure front left', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_tire_pressure_front_left', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2.775', + 'state': '40.2479739314961', }) # --- # name: test_sensors[sensor.test_tire_pressure_front_left-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'pressure', 'friendly_name': 'Test Tire pressure front left', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_tire_pressure_front_left', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2.775', + 'state': '40.2479739314961', }) # --- # name: test_sensors[sensor.test_tire_pressure_front_right-entry] @@ -2198,13 +2452,15 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , 'disabled_by': None, 'domain': 'sensor', - 'entity_category': None, + 'entity_category': , 'entity_id': 'sensor.test_tire_pressure_front_right', 'has_entity_name': True, 'hidden_by': None, @@ -2214,8 +2470,14 @@ }), 'name': None, 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Tire pressure front right', 'platform': 'teslemetry', @@ -2223,33 +2485,39 @@ 'supported_features': 0, 'translation_key': 'vehicle_state_tpms_pressure_fr', 'unique_id': 'VINVINVIN-vehicle_state_tpms_pressure_fr', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_tire_pressure_front_right-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'pressure', 'friendly_name': 'Test Tire pressure front right', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_tire_pressure_front_right', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2.8', + 'state': '40.6105682912393', }) # --- # name: test_sensors[sensor.test_tire_pressure_front_right-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'pressure', 'friendly_name': 'Test Tire pressure front right', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_tire_pressure_front_right', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2.8', + 'state': '40.6105682912393', }) # --- # name: test_sensors[sensor.test_tire_pressure_rear_left-entry] @@ -2257,13 +2525,15 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , 'disabled_by': None, 'domain': 'sensor', - 'entity_category': None, + 'entity_category': , 'entity_id': 'sensor.test_tire_pressure_rear_left', 'has_entity_name': True, 'hidden_by': None, @@ -2273,8 +2543,14 @@ }), 'name': None, 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Tire pressure rear left', 'platform': 'teslemetry', @@ -2282,33 +2558,39 @@ 'supported_features': 0, 'translation_key': 'vehicle_state_tpms_pressure_rl', 'unique_id': 'VINVINVIN-vehicle_state_tpms_pressure_rl', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_tire_pressure_rear_left-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'pressure', 'friendly_name': 'Test Tire pressure rear left', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_tire_pressure_rear_left', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2.775', + 'state': '40.2479739314961', }) # --- # name: test_sensors[sensor.test_tire_pressure_rear_left-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'pressure', 'friendly_name': 'Test Tire pressure rear left', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_tire_pressure_rear_left', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2.775', + 'state': '40.2479739314961', }) # --- # name: test_sensors[sensor.test_tire_pressure_rear_right-entry] @@ -2316,13 +2598,15 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , 'disabled_by': None, 'domain': 'sensor', - 'entity_category': None, + 'entity_category': , 'entity_id': 'sensor.test_tire_pressure_rear_right', 'has_entity_name': True, 'hidden_by': None, @@ -2332,8 +2616,14 @@ }), 'name': None, 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 1, + }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Tire pressure rear right', 'platform': 'teslemetry', @@ -2341,33 +2631,39 @@ 'supported_features': 0, 'translation_key': 'vehicle_state_tpms_pressure_rr', 'unique_id': 'VINVINVIN-vehicle_state_tpms_pressure_rr', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_tire_pressure_rear_right-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'pressure', 'friendly_name': 'Test Tire pressure rear right', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_tire_pressure_rear_right', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2.775', + 'state': '40.2479739314961', }) # --- # name: test_sensors[sensor.test_tire_pressure_rear_right-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'pressure', 'friendly_name': 'Test Tire pressure rear right', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_tire_pressure_rear_right', 'last_changed': , 'last_reported': , 'last_updated': , - 'state': '2.775', + 'state': '40.2479739314961', }) # --- # name: test_sensors[sensor.test_traffic_delay-entry] @@ -2375,7 +2671,9 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , @@ -2392,7 +2690,7 @@ 'name': None, 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Traffic delay', 'platform': 'teslemetry', @@ -2400,13 +2698,16 @@ 'supported_features': 0, 'translation_key': 'drive_state_active_route_traffic_minutes_delay', 'unique_id': 'VINVINVIN-drive_state_active_route_traffic_minutes_delay', - 'unit_of_measurement': None, + 'unit_of_measurement': , }) # --- # name: test_sensors[sensor.test_traffic_delay-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'duration', 'friendly_name': 'Test Traffic delay', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_traffic_delay', @@ -2419,7 +2720,10 @@ # name: test_sensors[sensor.test_traffic_delay-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'duration', 'friendly_name': 'Test Traffic delay', + 'state_class': , + 'unit_of_measurement': , }), 'context': , 'entity_id': 'sensor.test_traffic_delay', @@ -2434,7 +2738,9 @@ 'aliases': set({ }), 'area_id': None, - 'capabilities': None, + 'capabilities': dict({ + 'state_class': , + }), 'config_entry_id': , 'device_class': None, 'device_id': , @@ -2451,7 +2757,7 @@ 'name': None, 'options': dict({ }), - 'original_device_class': None, + 'original_device_class': , 'original_icon': None, 'original_name': 'Usable battery level', 'platform': 'teslemetry', @@ -2459,13 +2765,16 @@ 'supported_features': 0, 'translation_key': 'charge_state_usable_battery_level', 'unique_id': 'VINVINVIN-charge_state_usable_battery_level', - 'unit_of_measurement': None, + 'unit_of_measurement': '%', }) # --- # name: test_sensors[sensor.test_usable_battery_level-state] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'battery', 'friendly_name': 'Test Usable battery level', + 'state_class': , + 'unit_of_measurement': '%', }), 'context': , 'entity_id': 'sensor.test_usable_battery_level', @@ -2478,7 +2787,10 @@ # name: test_sensors[sensor.test_usable_battery_level-statealt] StateSnapshot({ 'attributes': ReadOnlyDict({ + 'device_class': 'battery', 'friendly_name': 'Test Usable battery level', + 'state_class': , + 'unit_of_measurement': '%', }), 'context': , 'entity_id': 'sensor.test_usable_battery_level', From 09ed0aa399443656f064bdb94c7042b6994705df Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 16 Apr 2024 10:13:47 -0500 Subject: [PATCH 12/26] Bump httpcore to 1.0.5 (#115672) Fixes missing handling of EndOfStream errors --- homeassistant/package_constraints.txt | 2 +- script/gen_requirements_all.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 13a28e34d281fc..49c7cf4a992612 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -107,7 +107,7 @@ regex==2021.8.28 # requirements so we can directly link HA versions to these library versions. anyio==4.3.0 h11==0.14.0 -httpcore==1.0.4 +httpcore==1.0.5 # Ensure we have a hyperframe version that works in Python 3.10 # 5.2.0 fixed a collections abc deprecation diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 9a9ff6821c7295..1423ce92b895fb 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -100,7 +100,7 @@ # requirements so we can directly link HA versions to these library versions. anyio==4.3.0 h11==0.14.0 -httpcore==1.0.4 +httpcore==1.0.5 # Ensure we have a hyperframe version that works in Python 3.10 # 5.2.0 fixed a collections abc deprecation From 630763ad9ee3e443d41eee1155a9c7a69980c002 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 16 Apr 2024 01:30:51 -0500 Subject: [PATCH 13/26] Bump sqlparse to 0.5.0 (#115681) fixes https://github.com/home-assistant/core/security/dependabot/54 fixes https://github.com/home-assistant/core/security/dependabot/55 --- homeassistant/components/sql/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/sql/manifest.json b/homeassistant/components/sql/manifest.json index dd44af892378cc..30d071f25af7d1 100644 --- a/homeassistant/components/sql/manifest.json +++ b/homeassistant/components/sql/manifest.json @@ -5,5 +5,5 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/sql", "iot_class": "local_polling", - "requirements": ["SQLAlchemy==2.0.29", "sqlparse==0.4.4"] + "requirements": ["SQLAlchemy==2.0.29", "sqlparse==0.5.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index 0c1725ca089c0e..cbe6ea8d74a860 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2595,7 +2595,7 @@ spiderpy==1.6.1 spotipy==2.23.0 # homeassistant.components.sql -sqlparse==0.4.4 +sqlparse==0.5.0 # homeassistant.components.srp_energy srpenergy==1.3.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index ced79b46ae8cac..930aa27bcfb7c8 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1999,7 +1999,7 @@ spiderpy==1.6.1 spotipy==2.23.0 # homeassistant.components.sql -sqlparse==0.4.4 +sqlparse==0.5.0 # homeassistant.components.srp_energy srpenergy==1.3.6 From 8207fc29d28b7ef4f9865774f87ac3cb3ac7df79 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 17 Apr 2024 02:10:06 -0500 Subject: [PATCH 14/26] Bump aiohttp to 3.9.5 (#115727) changelog: https://github.com/aio-libs/aiohttp/compare/v3.9.4...v3.9.5 --- homeassistant/package_constraints.txt | 2 +- pyproject.toml | 2 +- requirements.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 49c7cf4a992612..b2f55381f4d15f 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -4,7 +4,7 @@ aiodhcpwatcher==1.0.0 aiodiscover==2.0.0 aiohttp-fast-url-dispatcher==0.3.0 aiohttp-zlib-ng==0.3.1 -aiohttp==3.9.4 +aiohttp==3.9.5 aiohttp_cors==0.7.0 astral==2.2 async-interrupt==1.1.1 diff --git a/pyproject.toml b/pyproject.toml index 3a206a3f7fab81..3cb894e2342f10 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,7 +23,7 @@ classifiers = [ ] requires-python = ">=3.12.0" dependencies = [ - "aiohttp==3.9.4", + "aiohttp==3.9.5", "aiohttp_cors==0.7.0", "aiohttp-fast-url-dispatcher==0.3.0", "aiohttp-zlib-ng==0.3.1", diff --git a/requirements.txt b/requirements.txt index 5635c4912e9a9e..38bea26a8b67ec 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,7 +3,7 @@ -c homeassistant/package_constraints.txt # Home Assistant Core -aiohttp==3.9.4 +aiohttp==3.9.5 aiohttp_cors==0.7.0 aiohttp-fast-url-dispatcher==0.3.0 aiohttp-zlib-ng==0.3.1 From db31a526e5dcb1a90afc4fa6c605bb3c3c070e82 Mon Sep 17 00:00:00 2001 From: epenet <6771947+epenet@users.noreply.github.com> Date: Wed, 17 Apr 2024 14:23:47 +0200 Subject: [PATCH 15/26] Bump renault-api to 0.2.2 (#115738) --- homeassistant/components/renault/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/renault/manifest.json b/homeassistant/components/renault/manifest.json index 98e1c8b1e7c811..9891c838950105 100644 --- a/homeassistant/components/renault/manifest.json +++ b/homeassistant/components/renault/manifest.json @@ -8,5 +8,5 @@ "iot_class": "cloud_polling", "loggers": ["renault_api"], "quality_scale": "platinum", - "requirements": ["renault-api==0.2.1"] + "requirements": ["renault-api==0.2.2"] } diff --git a/requirements_all.txt b/requirements_all.txt index cbe6ea8d74a860..5a728ac8429e0c 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2429,7 +2429,7 @@ refoss-ha==1.2.0 regenmaschine==2024.03.0 # homeassistant.components.renault -renault-api==0.2.1 +renault-api==0.2.2 # homeassistant.components.renson renson-endura-delta==1.7.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 930aa27bcfb7c8..5faf622a9c42f5 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1875,7 +1875,7 @@ refoss-ha==1.2.0 regenmaschine==2024.03.0 # homeassistant.components.renault -renault-api==0.2.1 +renault-api==0.2.2 # homeassistant.components.renson renson-endura-delta==1.7.1 From c4b504ce395bd694ded715a19986be210ed2607e Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Wed, 17 Apr 2024 15:00:10 +0200 Subject: [PATCH 16/26] Fix homeworks import flow (#115761) --- .../components/homeworks/config_flow.py | 10 +----- .../components/homeworks/test_config_flow.py | 32 +------------------ 2 files changed, 2 insertions(+), 40 deletions(-) diff --git a/homeassistant/components/homeworks/config_flow.py b/homeassistant/components/homeworks/config_flow.py index b2fe4e0e0227cc..e54bbc61141c8f 100644 --- a/homeassistant/components/homeworks/config_flow.py +++ b/homeassistant/components/homeworks/config_flow.py @@ -565,15 +565,7 @@ async def async_step_import(self, config: dict[str, Any]) -> ConfigFlowResult: CONF_KEYPADS: [ { CONF_ADDR: keypad[CONF_ADDR], - CONF_BUTTONS: [ - { - CONF_LED: button[CONF_LED], - CONF_NAME: button[CONF_NAME], - CONF_NUMBER: button[CONF_NUMBER], - CONF_RELEASE_DELAY: button[CONF_RELEASE_DELAY], - } - for button in keypad[CONF_BUTTONS] - ], + CONF_BUTTONS: [], CONF_NAME: keypad[CONF_NAME], } for keypad in config[CONF_KEYPADS] diff --git a/tests/components/homeworks/test_config_flow.py b/tests/components/homeworks/test_config_flow.py index 4bdb5938f1c665..a4159c9b69392a 100644 --- a/tests/components/homeworks/test_config_flow.py +++ b/tests/components/homeworks/test_config_flow.py @@ -9,7 +9,6 @@ from homeassistant.components.button import DOMAIN as BUTTON_DOMAIN from homeassistant.components.homeworks.const import ( CONF_ADDR, - CONF_BUTTONS, CONF_DIMMERS, CONF_INDEX, CONF_KEYPADS, @@ -161,26 +160,6 @@ async def test_import_flow( { CONF_ADDR: "[02:08:02:01]", CONF_NAME: "Foyer Keypad", - CONF_BUTTONS: [ - { - CONF_NAME: "Morning", - CONF_NUMBER: 1, - CONF_LED: True, - CONF_RELEASE_DELAY: None, - }, - { - CONF_NAME: "Relax", - CONF_NUMBER: 2, - CONF_LED: True, - CONF_RELEASE_DELAY: None, - }, - { - CONF_NAME: "Dim up", - CONF_NUMBER: 3, - CONF_LED: False, - CONF_RELEASE_DELAY: 0.2, - }, - ], } ], }, @@ -207,16 +186,7 @@ async def test_import_flow( "keypads": [ { "addr": "[02:08:02:01]", - "buttons": [ - { - "led": True, - "name": "Morning", - "number": 1, - "release_delay": None, - }, - {"led": True, "name": "Relax", "number": 2, "release_delay": None}, - {"led": False, "name": "Dim up", "number": 3, "release_delay": 0.2}, - ], + "buttons": [], "name": "Foyer Keypad", } ], From 851a5497b4533a02081e9fc3eb5e7279ea024d3f Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Wed, 17 Apr 2024 15:04:37 +0200 Subject: [PATCH 17/26] Allow [##:##:##] type keypad address in homeworks (#115762) Allow [##:##:##] type keypad address --- homeassistant/components/homeworks/config_flow.py | 2 +- tests/components/homeworks/test_config_flow.py | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/homeworks/config_flow.py b/homeassistant/components/homeworks/config_flow.py index e54bbc61141c8f..b9515c306d6386 100644 --- a/homeassistant/components/homeworks/config_flow.py +++ b/homeassistant/components/homeworks/config_flow.py @@ -93,7 +93,7 @@ } -validate_addr = cv.matches_regex(r"\[\d\d:\d\d:\d\d:\d\d\]") +validate_addr = cv.matches_regex(r"\[(?:\d\d:)?\d\d:\d\d:\d\d\]") async def validate_add_controller( diff --git a/tests/components/homeworks/test_config_flow.py b/tests/components/homeworks/test_config_flow.py index a4159c9b69392a..a66e743fcd6825 100644 --- a/tests/components/homeworks/test_config_flow.py +++ b/tests/components/homeworks/test_config_flow.py @@ -544,8 +544,12 @@ async def test_options_add_remove_light_flow( ) +@pytest.mark.parametrize("keypad_address", ["[02:08:03:01]", "[02:08:03]"]) async def test_options_add_remove_keypad_flow( - hass: HomeAssistant, mock_config_entry: MockConfigEntry, mock_homeworks: MagicMock + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + mock_homeworks: MagicMock, + keypad_address: str, ) -> None: """Test options flow to add and remove a keypad.""" mock_config_entry.add_to_hass(hass) @@ -566,7 +570,7 @@ async def test_options_add_remove_keypad_flow( result = await hass.config_entries.options.async_configure( result["flow_id"], user_input={ - CONF_ADDR: "[02:08:03:01]", + CONF_ADDR: keypad_address, CONF_NAME: "Hall Keypad", }, ) @@ -592,7 +596,7 @@ async def test_options_add_remove_keypad_flow( ], "name": "Foyer Keypad", }, - {"addr": "[02:08:03:01]", "buttons": [], "name": "Hall Keypad"}, + {"addr": keypad_address, "buttons": [], "name": "Hall Keypad"}, ], "port": 1234, } @@ -612,7 +616,7 @@ async def test_options_add_remove_keypad_flow( assert result["step_id"] == "remove_keypad" assert result["data_schema"].schema["index"].options == { "0": "Foyer Keypad ([02:08:02:01])", - "1": "Hall Keypad ([02:08:03:01])", + "1": f"Hall Keypad ({keypad_address})", } result = await hass.config_entries.options.async_configure( @@ -625,7 +629,7 @@ async def test_options_add_remove_keypad_flow( {"addr": "[02:08:01:01]", "name": "Foyer Sconces", "rate": 1.0}, ], "host": "192.168.0.1", - "keypads": [{"addr": "[02:08:03:01]", "buttons": [], "name": "Hall Keypad"}], + "keypads": [{"addr": keypad_address, "buttons": [], "name": "Hall Keypad"}], "port": 1234, } await hass.async_block_till_done() From 40884473030cd82267dcb4678a4fca500a8274cf Mon Sep 17 00:00:00 2001 From: Simone Chemelli Date: Fri, 19 Apr 2024 16:45:19 +0200 Subject: [PATCH 18/26] Add missing media_player features to Samsung TV (#115788) * add missing features * fix snapshot --- homeassistant/components/samsungtv/media_player.py | 14 ++++++++------ .../components/samsungtv/snapshots/test_init.ambr | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/samsungtv/media_player.py b/homeassistant/components/samsungtv/media_player.py index 36715c44a9b375..ff347431a4a154 100644 --- a/homeassistant/components/samsungtv/media_player.py +++ b/homeassistant/components/samsungtv/media_player.py @@ -46,15 +46,17 @@ SOURCES = {"TV": "KEY_TV", "HDMI": "KEY_HDMI"} SUPPORT_SAMSUNGTV = ( - MediaPlayerEntityFeature.PAUSE - | MediaPlayerEntityFeature.VOLUME_STEP - | MediaPlayerEntityFeature.VOLUME_MUTE + MediaPlayerEntityFeature.NEXT_TRACK + | MediaPlayerEntityFeature.PAUSE + | MediaPlayerEntityFeature.PLAY + | MediaPlayerEntityFeature.PLAY_MEDIA | MediaPlayerEntityFeature.PREVIOUS_TRACK | MediaPlayerEntityFeature.SELECT_SOURCE - | MediaPlayerEntityFeature.NEXT_TRACK + | MediaPlayerEntityFeature.STOP | MediaPlayerEntityFeature.TURN_OFF - | MediaPlayerEntityFeature.PLAY - | MediaPlayerEntityFeature.PLAY_MEDIA + | MediaPlayerEntityFeature.VOLUME_MUTE + | MediaPlayerEntityFeature.VOLUME_SET + | MediaPlayerEntityFeature.VOLUME_STEP ) diff --git a/tests/components/samsungtv/snapshots/test_init.ambr b/tests/components/samsungtv/snapshots/test_init.ambr index 404b9a6b3afa50..1b8cf4c999d529 100644 --- a/tests/components/samsungtv/snapshots/test_init.ambr +++ b/tests/components/samsungtv/snapshots/test_init.ambr @@ -9,7 +9,7 @@ 'TV', 'HDMI', ]), - 'supported_features': , + 'supported_features': , }), 'context': , 'entity_id': 'media_player.any', @@ -51,7 +51,7 @@ 'original_name': None, 'platform': 'samsungtv', 'previous_unique_id': None, - 'supported_features': , + 'supported_features': , 'translation_key': None, 'unique_id': 'sample-entry-id', 'unit_of_measurement': None, From 6464218e5974f6c9ad276e1caae7b7a8bdad4176 Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Fri, 19 Apr 2024 06:36:43 +0200 Subject: [PATCH 19/26] Bump aiounifi to v75 (#115819) --- homeassistant/components/unifi/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/unifi/manifest.json b/homeassistant/components/unifi/manifest.json index 05dc2189908984..305400a4b9da58 100644 --- a/homeassistant/components/unifi/manifest.json +++ b/homeassistant/components/unifi/manifest.json @@ -8,7 +8,7 @@ "iot_class": "local_push", "loggers": ["aiounifi"], "quality_scale": "platinum", - "requirements": ["aiounifi==74"], + "requirements": ["aiounifi==75"], "ssdp": [ { "manufacturer": "Ubiquiti Networks", diff --git a/requirements_all.txt b/requirements_all.txt index 5a728ac8429e0c..ea29da2a8559cc 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -392,7 +392,7 @@ aiotankerkoenig==0.4.1 aiotractive==0.5.6 # homeassistant.components.unifi -aiounifi==74 +aiounifi==75 # homeassistant.components.vlc_telnet aiovlc==0.1.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 5faf622a9c42f5..8411f66e540aee 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -365,7 +365,7 @@ aiotankerkoenig==0.4.1 aiotractive==0.5.6 # homeassistant.components.unifi -aiounifi==74 +aiounifi==75 # homeassistant.components.vlc_telnet aiovlc==0.1.0 From 32f82d480f03f89355489ddc2feee38b7b0e3153 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 19 Apr 2024 11:24:54 -0500 Subject: [PATCH 20/26] Ensure scripts with timeouts of zero timeout immediately (#115830) --- homeassistant/helpers/script.py | 25 ++++- tests/helpers/test_script.py | 178 ++++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+), 5 deletions(-) diff --git a/homeassistant/helpers/script.py b/homeassistant/helpers/script.py index b4e02e0e4adf70..2b0eb90827e174 100644 --- a/homeassistant/helpers/script.py +++ b/homeassistant/helpers/script.py @@ -656,6 +656,12 @@ async def _async_wait_template_step(self): # check if condition already okay if condition.async_template(self._hass, wait_template, self._variables, False): self._variables["wait"]["completed"] = True + self._changed() + return + + if timeout == 0: + self._changed() + self._async_handle_timeout() return futures, timeout_handle, timeout_future = self._async_futures_with_timeout( @@ -1085,6 +1091,11 @@ async def _async_wait_for_trigger_step(self): self._variables["wait"] = {"remaining": timeout, "trigger": None} trace_set_result(wait=self._variables["wait"]) + if timeout == 0: + self._changed() + self._async_handle_timeout() + return + futures, timeout_handle, timeout_future = self._async_futures_with_timeout( timeout ) @@ -1115,6 +1126,14 @@ def log_cb(level, msg, **kwargs): futures, timeout_handle, timeout_future, remove_triggers ) + def _async_handle_timeout(self) -> None: + """Handle timeout.""" + self._variables["wait"]["remaining"] = 0.0 + if not self._action.get(CONF_CONTINUE_ON_TIMEOUT, True): + self._log(_TIMEOUT_MSG) + trace_set_result(wait=self._variables["wait"], timeout=True) + raise _AbortScript from TimeoutError() + async def _async_wait_with_optional_timeout( self, futures: list[asyncio.Future[None]], @@ -1125,11 +1144,7 @@ async def _async_wait_with_optional_timeout( try: await asyncio.wait(futures, return_when=asyncio.FIRST_COMPLETED) if timeout_future and timeout_future.done(): - self._variables["wait"]["remaining"] = 0.0 - if not self._action.get(CONF_CONTINUE_ON_TIMEOUT, True): - self._log(_TIMEOUT_MSG) - trace_set_result(wait=self._variables["wait"], timeout=True) - raise _AbortScript from TimeoutError() + self._async_handle_timeout() finally: if timeout_future and not timeout_future.done() and timeout_handle: timeout_handle.cancel() diff --git a/tests/helpers/test_script.py b/tests/helpers/test_script.py index 409b3639d43031..16db9fb7b0541c 100644 --- a/tests/helpers/test_script.py +++ b/tests/helpers/test_script.py @@ -1311,6 +1311,184 @@ async def test_wait_timeout( assert_action_trace(expected_trace) +@pytest.mark.parametrize( + "timeout_param", [0, "{{ 0 }}", {"minutes": 0}, {"minutes": "{{ 0 }}"}] +) +async def test_wait_trigger_with_zero_timeout( + hass: HomeAssistant, caplog: pytest.LogCaptureFixture, timeout_param: int | str +) -> None: + """Test the wait trigger with zero timeout option.""" + event = "test_event" + events = async_capture_events(hass, event) + action = { + "wait_for_trigger": { + "platform": "state", + "entity_id": "switch.test", + "to": "off", + } + } + action["timeout"] = timeout_param + action["continue_on_timeout"] = True + sequence = cv.SCRIPT_SCHEMA([action, {"event": event}]) + sequence = await script.async_validate_actions_config(hass, sequence) + script_obj = script.Script(hass, sequence, "Test Name", "test_domain") + wait_started_flag = async_watch_for_action(script_obj, "wait") + hass.states.async_set("switch.test", "on") + hass.async_create_task(script_obj.async_run(context=Context())) + + try: + await asyncio.wait_for(wait_started_flag.wait(), 1) + except (AssertionError, TimeoutError): + await script_obj.async_stop() + raise + + assert not script_obj.is_running + assert len(events) == 1 + assert "(timeout: 0:00:00)" in caplog.text + + variable_wait = {"wait": {"trigger": None, "remaining": 0.0}} + expected_trace = { + "0": [ + { + "result": variable_wait, + "variables": variable_wait, + } + ], + "1": [{"result": {"event": "test_event", "event_data": {}}}], + } + assert_action_trace(expected_trace) + + +@pytest.mark.parametrize( + "timeout_param", [0, "{{ 0 }}", {"minutes": 0}, {"minutes": "{{ 0 }}"}] +) +async def test_wait_trigger_matches_with_zero_timeout( + hass: HomeAssistant, caplog: pytest.LogCaptureFixture, timeout_param: int | str +) -> None: + """Test the wait trigger that matches with zero timeout option.""" + event = "test_event" + events = async_capture_events(hass, event) + action = { + "wait_for_trigger": { + "platform": "state", + "entity_id": "switch.test", + "to": "off", + } + } + action["timeout"] = timeout_param + action["continue_on_timeout"] = True + sequence = cv.SCRIPT_SCHEMA([action, {"event": event}]) + sequence = await script.async_validate_actions_config(hass, sequence) + script_obj = script.Script(hass, sequence, "Test Name", "test_domain") + wait_started_flag = async_watch_for_action(script_obj, "wait") + hass.states.async_set("switch.test", "off") + hass.async_create_task(script_obj.async_run(context=Context())) + + try: + await asyncio.wait_for(wait_started_flag.wait(), 1) + except (AssertionError, TimeoutError): + await script_obj.async_stop() + raise + + assert not script_obj.is_running + assert len(events) == 1 + assert "(timeout: 0:00:00)" in caplog.text + + variable_wait = {"wait": {"trigger": None, "remaining": 0.0}} + expected_trace = { + "0": [ + { + "result": variable_wait, + "variables": variable_wait, + } + ], + "1": [{"result": {"event": "test_event", "event_data": {}}}], + } + assert_action_trace(expected_trace) + + +@pytest.mark.parametrize( + "timeout_param", [0, "{{ 0 }}", {"minutes": 0}, {"minutes": "{{ 0 }}"}] +) +async def test_wait_template_with_zero_timeout( + hass: HomeAssistant, caplog: pytest.LogCaptureFixture, timeout_param: int | str +) -> None: + """Test the wait template with zero timeout option.""" + event = "test_event" + events = async_capture_events(hass, event) + action = {"wait_template": "{{ states.switch.test.state == 'off' }}"} + action["timeout"] = timeout_param + action["continue_on_timeout"] = True + sequence = cv.SCRIPT_SCHEMA([action, {"event": event}]) + sequence = await script.async_validate_actions_config(hass, sequence) + script_obj = script.Script(hass, sequence, "Test Name", "test_domain") + wait_started_flag = async_watch_for_action(script_obj, "wait") + hass.states.async_set("switch.test", "on") + hass.async_create_task(script_obj.async_run(context=Context())) + + try: + await asyncio.wait_for(wait_started_flag.wait(), 1) + except (AssertionError, TimeoutError): + await script_obj.async_stop() + raise + + assert not script_obj.is_running + assert len(events) == 1 + assert "(timeout: 0:00:00)" in caplog.text + variable_wait = {"wait": {"completed": False, "remaining": 0.0}} + expected_trace = { + "0": [ + { + "result": variable_wait, + "variables": variable_wait, + } + ], + "1": [{"result": {"event": "test_event", "event_data": {}}}], + } + assert_action_trace(expected_trace) + + +@pytest.mark.parametrize( + "timeout_param", [0, "{{ 0 }}", {"minutes": 0}, {"minutes": "{{ 0 }}"}] +) +async def test_wait_template_matches_with_zero_timeout( + hass: HomeAssistant, caplog: pytest.LogCaptureFixture, timeout_param: int | str +) -> None: + """Test the wait template that matches with zero timeout option.""" + event = "test_event" + events = async_capture_events(hass, event) + action = {"wait_template": "{{ states.switch.test.state == 'off' }}"} + action["timeout"] = timeout_param + action["continue_on_timeout"] = True + sequence = cv.SCRIPT_SCHEMA([action, {"event": event}]) + sequence = await script.async_validate_actions_config(hass, sequence) + script_obj = script.Script(hass, sequence, "Test Name", "test_domain") + wait_started_flag = async_watch_for_action(script_obj, "wait") + hass.states.async_set("switch.test", "off") + hass.async_create_task(script_obj.async_run(context=Context())) + + try: + await asyncio.wait_for(wait_started_flag.wait(), 1) + except (AssertionError, TimeoutError): + await script_obj.async_stop() + raise + + assert not script_obj.is_running + assert len(events) == 1 + assert "(timeout: 0:00:00)" in caplog.text + variable_wait = {"wait": {"completed": True, "remaining": 0.0}} + expected_trace = { + "0": [ + { + "result": variable_wait, + "variables": variable_wait, + } + ], + "1": [{"result": {"event": "test_event", "event_data": {}}}], + } + assert_action_trace(expected_trace) + + @pytest.mark.parametrize( ("continue_on_timeout", "n_events"), [(False, 0), (True, 1), (None, 1)] ) From 13ed2d291931c44bfa5116e13377a32464a237de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A5le=20Stor=C3=B8=20Hauknes?= Date: Tue, 23 Apr 2024 15:53:31 +0200 Subject: [PATCH 21/26] Fix KeyError error when fetching sensors (Airthings) (#115844) --- homeassistant/components/airthings/sensor.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/homeassistant/components/airthings/sensor.py b/homeassistant/components/airthings/sensor.py index fc91d816aca954..f0a3dc5be8fa05 100644 --- a/homeassistant/components/airthings/sensor.py +++ b/homeassistant/components/airthings/sensor.py @@ -157,3 +157,11 @@ def __init__( def native_value(self) -> StateType: """Return the value reported by the sensor.""" return self.coordinator.data[self._id].sensors[self.entity_description.key] # type: ignore[no-any-return] + + @property + def available(self) -> bool: + """Check if device and sensor is available in data.""" + return ( + super().available + and self.entity_description.key in self.coordinator.data[self._id].sensors + ) From b8b2f6427a0c841c17b320f7b79b591350ecf785 Mon Sep 17 00:00:00 2001 From: jjlawren Date: Sat, 20 Apr 2024 05:36:03 -0500 Subject: [PATCH 22/26] Bump plexapi to 4.15.12 (#115872) --- homeassistant/components/plex/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/plex/manifest.json b/homeassistant/components/plex/manifest.json index 85362371715118..ff0ab39b150d30 100644 --- a/homeassistant/components/plex/manifest.json +++ b/homeassistant/components/plex/manifest.json @@ -8,7 +8,7 @@ "iot_class": "local_push", "loggers": ["plexapi", "plexwebsocket"], "requirements": [ - "PlexAPI==4.15.11", + "PlexAPI==4.15.12", "plexauth==0.0.6", "plexwebsocket==0.0.14" ], diff --git a/requirements_all.txt b/requirements_all.txt index ea29da2a8559cc..4a4e9c94c698f5 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -45,7 +45,7 @@ Mastodon.py==1.8.1 Pillow==10.3.0 # homeassistant.components.plex -PlexAPI==4.15.11 +PlexAPI==4.15.12 # homeassistant.components.progettihwsw ProgettiHWSW==0.1.3 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 8411f66e540aee..4acfa310c94085 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -39,7 +39,7 @@ HATasmota==0.8.0 Pillow==10.3.0 # homeassistant.components.plex -PlexAPI==4.15.11 +PlexAPI==4.15.12 # homeassistant.components.progettihwsw ProgettiHWSW==0.1.3 From c9c7c7803e6097c0d555032d73e36ef34b1556e8 Mon Sep 17 00:00:00 2001 From: Allen Porter Date: Sun, 21 Apr 2024 15:52:47 -0700 Subject: [PATCH 23/26] Bump ical to 8.0.0 (#115907) Co-authored-by: J. Nick Koston --- homeassistant/components/google/manifest.json | 2 +- homeassistant/components/local_calendar/manifest.json | 2 +- homeassistant/components/local_todo/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/google/manifest.json b/homeassistant/components/google/manifest.json index 00561cb5fd6dde..ac43dc58953326 100644 --- a/homeassistant/components/google/manifest.json +++ b/homeassistant/components/google/manifest.json @@ -7,5 +7,5 @@ "documentation": "https://www.home-assistant.io/integrations/calendar.google", "iot_class": "cloud_polling", "loggers": ["googleapiclient"], - "requirements": ["gcal-sync==6.0.4", "oauth2client==4.1.3", "ical==7.0.3"] + "requirements": ["gcal-sync==6.0.4", "oauth2client==4.1.3", "ical==8.0.0"] } diff --git a/homeassistant/components/local_calendar/manifest.json b/homeassistant/components/local_calendar/manifest.json index 1c13970503d2a1..b1c7d6a3a349bc 100644 --- a/homeassistant/components/local_calendar/manifest.json +++ b/homeassistant/components/local_calendar/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/local_calendar", "iot_class": "local_polling", "loggers": ["ical"], - "requirements": ["ical==7.0.3"] + "requirements": ["ical==8.0.0"] } diff --git a/homeassistant/components/local_todo/manifest.json b/homeassistant/components/local_todo/manifest.json index 3bcb8af9f4384c..44c76a56a8f3be 100644 --- a/homeassistant/components/local_todo/manifest.json +++ b/homeassistant/components/local_todo/manifest.json @@ -5,5 +5,5 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/local_todo", "iot_class": "local_polling", - "requirements": ["ical==7.0.3"] + "requirements": ["ical==8.0.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index 4a4e9c94c698f5..2228c9d1bd6cda 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1118,7 +1118,7 @@ ibmiotf==0.3.4 # homeassistant.components.google # homeassistant.components.local_calendar # homeassistant.components.local_todo -ical==7.0.3 +ical==8.0.0 # homeassistant.components.ping icmplib==3.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 4acfa310c94085..be285822e6349e 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -908,7 +908,7 @@ ibeacon-ble==1.2.0 # homeassistant.components.google # homeassistant.components.local_calendar # homeassistant.components.local_todo -ical==7.0.3 +ical==8.0.0 # homeassistant.components.ping icmplib==3.0 From 036b6fca25d7339ae17f2285a810dea7889f0ef9 Mon Sep 17 00:00:00 2001 From: Michael <35783820+mib1185@users.noreply.github.com> Date: Sun, 21 Apr 2024 11:44:58 +0200 Subject: [PATCH 24/26] Fix geo location attributes of Tankerkoenig sensors (#115914) * geo location attributes needs to be float * make mypy happy --- homeassistant/components/tankerkoenig/sensor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/tankerkoenig/sensor.py b/homeassistant/components/tankerkoenig/sensor.py index f2fdc2c45b747c..33476e752620f6 100644 --- a/homeassistant/components/tankerkoenig/sensor.py +++ b/homeassistant/components/tankerkoenig/sensor.py @@ -91,7 +91,7 @@ def __init__( self._fuel_type = fuel_type self._attr_translation_key = fuel_type self._attr_unique_id = f"{station.id}_{fuel_type}" - attrs = { + attrs: dict[str, int | str | float | None] = { ATTR_BRAND: station.brand, ATTR_FUEL_TYPE: fuel_type, ATTR_STATION_NAME: station.name, @@ -102,8 +102,8 @@ def __init__( } if coordinator.show_on_map: - attrs[ATTR_LATITUDE] = str(station.lat) - attrs[ATTR_LONGITUDE] = str(station.lng) + attrs[ATTR_LATITUDE] = station.lat + attrs[ATTR_LONGITUDE] = station.lng self._attr_extra_state_attributes = attrs @property From b521acb72404bb57b3422978baf4d216f0ecb011 Mon Sep 17 00:00:00 2001 From: Raj Laud <50647620+rajlaud@users.noreply.github.com> Date: Mon, 22 Apr 2024 11:46:12 -0400 Subject: [PATCH 25/26] Use start helper in squeezebox for server discovery (#115978) --- homeassistant/components/squeezebox/media_player.py | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/squeezebox/media_player.py b/homeassistant/components/squeezebox/media_player.py index 007d880a2635a5..d9478b6747db7d 100644 --- a/homeassistant/components/squeezebox/media_player.py +++ b/homeassistant/components/squeezebox/media_player.py @@ -28,7 +28,6 @@ CONF_PASSWORD, CONF_PORT, CONF_USERNAME, - EVENT_HOMEASSISTANT_START, ) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers import ( @@ -44,6 +43,7 @@ ) from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.event import async_call_later +from homeassistant.helpers.start import async_at_start from homeassistant.util.dt import utcnow from .browse_media import ( @@ -207,12 +207,7 @@ async def _discovered_player(player): platform.async_register_entity_service(SERVICE_UNSYNC, None, "async_unsync") # Start server discovery task if not already running - if hass.is_running: - hass.async_create_task(start_server_discovery(hass)) - else: - hass.bus.async_listen_once( - EVENT_HOMEASSISTANT_START, start_server_discovery(hass) - ) + config_entry.async_on_unload(async_at_start(hass, start_server_discovery)) class SqueezeBoxEntity(MediaPlayerEntity): From 4d551d68c6f8e86380b91c30671d4a7d13ab9ae1 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Tue, 23 Apr 2024 20:12:21 +0200 Subject: [PATCH 26/26] Bump version to 2024.4.4 --- homeassistant/const.py | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/homeassistant/const.py b/homeassistant/const.py index ecfc1c6259ca86..892d16ba0086ee 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -18,7 +18,7 @@ APPLICATION_NAME: Final = "HomeAssistant" MAJOR_VERSION: Final = 2024 MINOR_VERSION: Final = 4 -PATCH_VERSION: Final = "3" +PATCH_VERSION: Final = "4" __short_version__: Final = f"{MAJOR_VERSION}.{MINOR_VERSION}" __version__: Final = f"{__short_version__}.{PATCH_VERSION}" REQUIRED_PYTHON_VER: Final[tuple[int, int, int]] = (3, 12, 0) diff --git a/pyproject.toml b/pyproject.toml index 3cb894e2342f10..b6206f107f7511 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "homeassistant" -version = "2024.4.3" +version = "2024.4.4" license = {text = "Apache-2.0"} description = "Open-source home automation platform running on Python 3." readme = "README.rst"