From 624baebbaa2c4de2f636f61d17597c6f7270f1fc Mon Sep 17 00:00:00 2001 From: Pete Sage <76050312+PeteRager@users.noreply.github.com> Date: Tue, 7 May 2024 04:08:12 -0400 Subject: [PATCH 01/19] Fix Sonos select_source timeout error (#115640) --- .../components/sonos/media_player.py | 12 +- homeassistant/components/sonos/strings.json | 5 + tests/components/sonos/conftest.py | 15 +- .../sonos/fixtures/sonos_favorites.json | 38 +++++ tests/components/sonos/test_media_player.py | 159 +++++++++++++++++- 5 files changed, 222 insertions(+), 7 deletions(-) create mode 100644 tests/components/sonos/fixtures/sonos_favorites.json diff --git a/homeassistant/components/sonos/media_player.py b/homeassistant/components/sonos/media_player.py index 35c6be3fa6b45f..e9fbb152b7a141 100644 --- a/homeassistant/components/sonos/media_player.py +++ b/homeassistant/components/sonos/media_player.py @@ -39,7 +39,7 @@ from homeassistant.config_entries import ConfigEntry from homeassistant.const import ATTR_TIME from homeassistant.core import HomeAssistant, ServiceCall, callback -from homeassistant.exceptions import HomeAssistantError +from homeassistant.exceptions import HomeAssistantError, ServiceValidationError from homeassistant.helpers import config_validation as cv, entity_platform, service from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_platform import AddEntitiesCallback @@ -432,7 +432,13 @@ def _play_favorite_by_name(self, name: str) -> None: fav = [fav for fav in self.speaker.favorites if fav.title == name] if len(fav) != 1: - return + raise ServiceValidationError( + translation_domain=SONOS_DOMAIN, + translation_key="invalid_favorite", + translation_placeholders={ + "name": name, + }, + ) src = fav.pop() self._play_favorite(src) @@ -445,7 +451,7 @@ def _play_favorite(self, favorite: DidlFavorite) -> None: MUSIC_SRC_RADIO, MUSIC_SRC_LINE_IN, ]: - soco.play_uri(uri, title=favorite.title) + soco.play_uri(uri, title=favorite.title, timeout=LONG_SERVICE_TIMEOUT) else: soco.clear_queue() soco.add_to_queue(favorite.reference, timeout=LONG_SERVICE_TIMEOUT) diff --git a/homeassistant/components/sonos/strings.json b/homeassistant/components/sonos/strings.json index 6f45195c46bec8..6521302b0077ef 100644 --- a/homeassistant/components/sonos/strings.json +++ b/homeassistant/components/sonos/strings.json @@ -173,5 +173,10 @@ } } } + }, + "exceptions": { + "invalid_favorite": { + "message": "Could not find a Sonos favorite: {name}" + } } } diff --git a/tests/components/sonos/conftest.py b/tests/components/sonos/conftest.py index 0eb9b497fbd479..15f371f272c9d4 100644 --- a/tests/components/sonos/conftest.py +++ b/tests/components/sonos/conftest.py @@ -9,6 +9,7 @@ import pytest from soco import SoCo from soco.alarms import Alarms +from soco.data_structures import DidlFavorite, SearchResult from soco.events_base import Event as SonosEvent from homeassistant.components import ssdp, zeroconf @@ -17,7 +18,7 @@ from homeassistant.const import CONF_HOSTS from homeassistant.core import HomeAssistant -from tests.common import MockConfigEntry, load_fixture +from tests.common import MockConfigEntry, load_fixture, load_json_value_fixture class SonosMockEventListener: @@ -304,6 +305,14 @@ def config_fixture(): return {DOMAIN: {MP_DOMAIN: {CONF_HOSTS: ["192.168.42.2"]}}} +@pytest.fixture(name="sonos_favorites") +def sonos_favorites_fixture() -> SearchResult: + """Create sonos favorites fixture.""" + favorites = load_json_value_fixture("sonos_favorites.json", "sonos") + favorite_list = [DidlFavorite.from_dict(fav) for fav in favorites] + return SearchResult(favorite_list, "favorites", 3, 3, 1) + + class MockMusicServiceItem: """Mocks a Soco MusicServiceItem.""" @@ -408,10 +417,10 @@ def mock_get_music_library_information( @pytest.fixture(name="music_library") -def music_library_fixture(): +def music_library_fixture(sonos_favorites: SearchResult) -> Mock: """Create music_library fixture.""" music_library = MagicMock() - music_library.get_sonos_favorites.return_value.update_id = 1 + music_library.get_sonos_favorites.return_value = sonos_favorites music_library.browse_by_idstring = mock_browse_by_idstring music_library.get_music_library_information = mock_get_music_library_information return music_library diff --git a/tests/components/sonos/fixtures/sonos_favorites.json b/tests/components/sonos/fixtures/sonos_favorites.json new file mode 100644 index 00000000000000..21ee68f4872aa6 --- /dev/null +++ b/tests/components/sonos/fixtures/sonos_favorites.json @@ -0,0 +1,38 @@ +[ + { + "title": "66 - Watercolors", + "parent_id": "FV:2", + "item_id": "FV:2/4", + "resource_meta_data": "66 - Watercolorsobject.item.audioItem.audioBroadcastSA_RINCON9479_X_#Svc9479-99999999-Token", + "resources": [ + { + "uri": "x-sonosapi-hls:Api%3atune%3aliveAudio%3ajazzcafe%3aetc", + "protocol_info": "a:b:c:d" + } + ] + }, + { + "title": "James Taylor Radio", + "parent_id": "FV:2", + "item_id": "FV:2/13", + "resource_meta_data": "James Taylor Radioobject.item.audioItem.audioBroadcast.#stationSA_RINCON60423_X_#Svc60423-99999999-Token", + "resources": [ + { + "uri": "x-sonosapi-radio:ST%3aetc", + "protocol_info": "a:b:c:d" + } + ] + }, + { + "title": "1984", + "parent_id": "FV:2", + "item_id": "FV:2/8", + "resource_meta_data": "1984object.container.album.musicAlbumRINCON_AssociatedZPUDN", + "resources": [ + { + "uri": "x-rincon-playlist:RINCON_test#A:ALBUMARTIST/Aerosmith/1984", + "protocol_info": "a:b:c:d" + } + ] + } +] diff --git a/tests/components/sonos/test_media_player.py b/tests/components/sonos/test_media_player.py index 976d3480429359..9fb8444a6963fb 100644 --- a/tests/components/sonos/test_media_player.py +++ b/tests/components/sonos/test_media_player.py @@ -1,6 +1,7 @@ """Tests for the Sonos Media Player platform.""" import logging +from typing import Any import pytest @@ -9,10 +10,15 @@ SERVICE_PLAY_MEDIA, MediaPlayerEnqueue, ) -from homeassistant.components.media_player.const import ATTR_MEDIA_ENQUEUE +from homeassistant.components.media_player.const import ( + ATTR_MEDIA_ENQUEUE, + SERVICE_SELECT_SOURCE, +) +from homeassistant.components.sonos.const import SOURCE_LINEIN, SOURCE_TV from homeassistant.components.sonos.media_player import LONG_SERVICE_TIMEOUT from homeassistant.const import STATE_IDLE from homeassistant.core import HomeAssistant +from homeassistant.exceptions import ServiceValidationError from homeassistant.helpers.device_registry import ( CONNECTION_NETWORK_MAC, CONNECTION_UPNP, @@ -272,3 +278,154 @@ async def test_play_media_music_library_playlist_dne( assert soco_mock.play_uri.call_count == 0 assert media_content_id in caplog.text assert "playlist" in caplog.text + + +@pytest.mark.parametrize( + ("source", "result"), + [ + ( + SOURCE_LINEIN, + { + "switch_to_line_in": 1, + }, + ), + ( + SOURCE_TV, + { + "switch_to_tv": 1, + }, + ), + ], +) +async def test_select_source_line_in_tv( + hass: HomeAssistant, + soco_factory: SoCoMockFactory, + async_autosetup_sonos, + source: str, + result: dict[str, Any], +) -> None: + """Test the select_source method with a variety of inputs.""" + soco_mock = soco_factory.mock_list.get("192.168.42.2") + await hass.services.async_call( + MP_DOMAIN, + SERVICE_SELECT_SOURCE, + { + "entity_id": "media_player.zone_a", + "source": source, + }, + blocking=True, + ) + assert soco_mock.switch_to_line_in.call_count == result.get("switch_to_line_in", 0) + assert soco_mock.switch_to_tv.call_count == result.get("switch_to_tv", 0) + + +@pytest.mark.parametrize( + ("source", "result"), + [ + ( + "James Taylor Radio", + { + "play_uri": 1, + "play_uri_uri": "x-sonosapi-radio:ST%3aetc", + "play_uri_title": "James Taylor Radio", + }, + ), + ( + "66 - Watercolors", + { + "play_uri": 1, + "play_uri_uri": "x-sonosapi-hls:Api%3atune%3aliveAudio%3ajazzcafe%3aetc", + "play_uri_title": "66 - Watercolors", + }, + ), + ], +) +async def test_select_source_play_uri( + hass: HomeAssistant, + soco_factory: SoCoMockFactory, + async_autosetup_sonos, + source: str, + result: dict[str, Any], +) -> None: + """Test the select_source method with a variety of inputs.""" + soco_mock = soco_factory.mock_list.get("192.168.42.2") + await hass.services.async_call( + MP_DOMAIN, + SERVICE_SELECT_SOURCE, + { + "entity_id": "media_player.zone_a", + "source": source, + }, + blocking=True, + ) + assert soco_mock.play_uri.call_count == result.get("play_uri") + soco_mock.play_uri.assert_called_with( + result.get("play_uri_uri"), + title=result.get("play_uri_title"), + timeout=LONG_SERVICE_TIMEOUT, + ) + + +@pytest.mark.parametrize( + ("source", "result"), + [ + ( + "1984", + { + "add_to_queue": 1, + "add_to_queue_item_id": "A:ALBUMARTIST/Aerosmith/1984", + "clear_queue": 1, + "play_from_queue": 1, + }, + ), + ], +) +async def test_select_source_play_queue( + hass: HomeAssistant, + soco_factory: SoCoMockFactory, + async_autosetup_sonos, + source: str, + result: dict[str, Any], +) -> None: + """Test the select_source method with a variety of inputs.""" + soco_mock = soco_factory.mock_list.get("192.168.42.2") + await hass.services.async_call( + MP_DOMAIN, + SERVICE_SELECT_SOURCE, + { + "entity_id": "media_player.zone_a", + "source": source, + }, + blocking=True, + ) + assert soco_mock.clear_queue.call_count == result.get("clear_queue") + assert soco_mock.add_to_queue.call_count == result.get("add_to_queue") + assert soco_mock.add_to_queue.call_args_list[0].args[0].item_id == result.get( + "add_to_queue_item_id" + ) + assert ( + soco_mock.add_to_queue.call_args_list[0].kwargs["timeout"] + == LONG_SERVICE_TIMEOUT + ) + assert soco_mock.play_from_queue.call_count == result.get("play_from_queue") + soco_mock.play_from_queue.assert_called_with(0) + + +async def test_select_source_error( + hass: HomeAssistant, + soco_factory: SoCoMockFactory, + async_autosetup_sonos, +) -> None: + """Test the select_source method with a variety of inputs.""" + with pytest.raises(ServiceValidationError) as sve: + await hass.services.async_call( + MP_DOMAIN, + SERVICE_SELECT_SOURCE, + { + "entity_id": "media_player.zone_a", + "source": "invalid_source", + }, + blocking=True, + ) + assert "invalid_source" in str(sve.value) + assert "Could not find a Sonos favorite" in str(sve.value) From 57861dc091ec3c5aab0096f53a8461f25d7ada1e Mon Sep 17 00:00:00 2001 From: "Mr. Bubbles" Date: Tue, 7 May 2024 21:10:04 +0200 Subject: [PATCH 02/19] Update strings for Bring notification service (#116181) update translations --- homeassistant/components/bring/strings.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/bring/strings.json b/homeassistant/components/bring/strings.json index e6df885cbbc21c..5deb0759c174ff 100644 --- a/homeassistant/components/bring/strings.json +++ b/homeassistant/components/bring/strings.json @@ -60,8 +60,8 @@ "description": "Type of push notification to send to list members." }, "item": { - "name": "Item (Required if message type `Breaking news` selected)", - "description": "Item name to include in a breaking news message e.g. `Breaking news - Please get cilantro!`" + "name": "Article (Required if message type `Urgent Message` selected)", + "description": "Article name to include in an urgent message e.g. `Urgent Message - Please buy Cilantro urgently`" } } } @@ -69,10 +69,10 @@ "selector": { "notification_type_selector": { "options": { - "going_shopping": "I'm going shopping! - Last chance for adjustments", - "changed_list": "List changed - Check it out", - "shopping_done": "Shopping done - you can relax", - "urgent_message": "Breaking news - Please get `item`!" + "going_shopping": "I'm going shopping! - Last chance to make changes", + "changed_list": "List updated - Take a look at the articles", + "shopping_done": "Shopping done - The fridge is well stocked", + "urgent_message": "Urgent Message - Please buy `Article name` urgently" } } } From fdc59547e0f02a7799657dffecd12df969f44d01 Mon Sep 17 00:00:00 2001 From: Matrix Date: Tue, 7 May 2024 13:51:10 +0800 Subject: [PATCH 03/19] Bump Yolink api to 0.4.4 (#116967) --- homeassistant/components/yolink/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/yolink/manifest.json b/homeassistant/components/yolink/manifest.json index b7bd1d4784f9ae..5353d5d5b8c9d5 100644 --- a/homeassistant/components/yolink/manifest.json +++ b/homeassistant/components/yolink/manifest.json @@ -6,5 +6,5 @@ "dependencies": ["auth", "application_credentials"], "documentation": "https://www.home-assistant.io/integrations/yolink", "iot_class": "cloud_push", - "requirements": ["yolink-api==0.4.3"] + "requirements": ["yolink-api==0.4.4"] } diff --git a/requirements_all.txt b/requirements_all.txt index e4c84b11ab82f6..f188c7ea248011 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2914,7 +2914,7 @@ yeelight==0.7.14 yeelightsunflower==0.0.10 # homeassistant.components.yolink -yolink-api==0.4.3 +yolink-api==0.4.4 # homeassistant.components.youless youless-api==1.0.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index e9dc44b3765c9b..9bec4e50de4929 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2264,7 +2264,7 @@ yalexs==3.0.1 yeelight==0.7.14 # homeassistant.components.yolink -yolink-api==0.4.3 +yolink-api==0.4.4 # homeassistant.components.youless youless-api==1.0.1 From bee518dc78cb7c1588e9c54df71bdcae18b86d82 Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Tue, 7 May 2024 13:56:11 +0200 Subject: [PATCH 04/19] Update jinja2 to 3.1.4 (#116986) --- 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 0f69f7d63c9682..13ac6119f66c6b 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -36,7 +36,7 @@ home-assistant-frontend==20240501.1 home-assistant-intents==2024.4.24 httpx==0.27.0 ifaddr==0.2.0 -Jinja2==3.1.3 +Jinja2==3.1.4 lru-dict==1.3.0 mutagen==1.47.0 orjson==3.9.15 diff --git a/pyproject.toml b/pyproject.toml index 887083304cf8da..8fb7839c628196 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,7 +46,7 @@ dependencies = [ "httpx==0.27.0", "home-assistant-bluetooth==1.12.0", "ifaddr==0.2.0", - "Jinja2==3.1.3", + "Jinja2==3.1.4", "lru-dict==1.3.0", "PyJWT==2.8.0", # PyJWT has loose dependency. We want the latest one. diff --git a/requirements.txt b/requirements.txt index df001251a04849..9d0cd618b2eeee 100644 --- a/requirements.txt +++ b/requirements.txt @@ -22,7 +22,7 @@ hass-nabucasa==0.78.0 httpx==0.27.0 home-assistant-bluetooth==1.12.0 ifaddr==0.2.0 -Jinja2==3.1.3 +Jinja2==3.1.4 lru-dict==1.3.0 PyJWT==2.8.0 cryptography==42.0.5 From 1a13e1d024aca7bdf1ca95ce9356217310896300 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Tue, 7 May 2024 14:41:31 -0500 Subject: [PATCH 05/19] Simplify MQTT subscribe debouncer execution (#117006) --- homeassistant/components/mqtt/client.py | 19 +++++++------------ tests/components/mqtt/test_init.py | 22 +++++++++++----------- tests/components/mqtt/test_mixins.py | 3 +++ 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/homeassistant/components/mqtt/client.py b/homeassistant/components/mqtt/client.py index 4b05442d71b13d..2ca17f012e4ae9 100644 --- a/homeassistant/components/mqtt/client.py +++ b/homeassistant/components/mqtt/client.py @@ -317,7 +317,7 @@ def __init__( self._loop = asyncio.get_running_loop() self._timeout = timeout self._callback = callback_job - self._task: asyncio.Future | None = None + self._task: asyncio.Task | None = None self._timer: asyncio.TimerHandle | None = None def set_timeout(self, timeout: float) -> None: @@ -332,28 +332,23 @@ async def _async_job(self) -> None: _LOGGER.error("%s", ha_error) @callback - def _async_task_done(self, task: asyncio.Future) -> None: + def _async_task_done(self, task: asyncio.Task) -> None: """Handle task done.""" self._task = None @callback - def _async_execute(self) -> None: + def async_execute(self) -> asyncio.Task: """Execute the job.""" if self._task: # Task already running, # so we schedule another run self.async_schedule() - return + return self._task self._async_cancel_timer() self._task = create_eager_task(self._async_job()) self._task.add_done_callback(self._async_task_done) - - async def async_fire(self) -> None: - """Execute the job immediately.""" - if self._task: - await self._task - self._async_execute() + return self._task @callback def _async_cancel_timer(self) -> None: @@ -368,7 +363,7 @@ def async_schedule(self) -> None: # We want to reschedule the timer in the future # every time this is called. self._async_cancel_timer() - self._timer = self._loop.call_later(self._timeout, self._async_execute) + self._timer = self._loop.call_later(self._timeout, self.async_execute) async def async_cleanup(self) -> None: """Cleanup any pending task.""" @@ -883,7 +878,7 @@ async def _async_resubscribe_and_publish_birth_message( await self._discovery_cooldown() # Wait for MQTT discovery to cool down # Update subscribe cooldown period to a shorter time # and make sure we flush the debouncer - await self._subscribe_debouncer.async_fire() + await self._subscribe_debouncer.async_execute() self._subscribe_debouncer.set_timeout(SUBSCRIBE_COOLDOWN) await self.async_publish( topic=birth_message.topic, diff --git a/tests/components/mqtt/test_init.py b/tests/components/mqtt/test_init.py index a1264b52739a09..b7998274aa0c6a 100644 --- a/tests/components/mqtt/test_init.py +++ b/tests/components/mqtt/test_init.py @@ -2589,19 +2589,19 @@ def wait_birth(msg: ReceiveMessage) -> None: mqtt_client_mock.on_connect(None, None, 0, 0) await hass.async_block_till_done() hass.bus.async_fire(EVENT_HOMEASSISTANT_STARTED) + await mqtt.async_subscribe(hass, "topic/test", record_calls) # We wait until we receive a birth message await asyncio.wait_for(birth.wait(), 1) - # Assert we already have subscribed at the client - # for new config payloads at the time we the birth message is received - assert ("homeassistant/+/+/config", 0) in help_all_subscribe_calls( - mqtt_client_mock - ) - assert ("homeassistant/+/+/+/config", 0) in help_all_subscribe_calls( - mqtt_client_mock - ) - mqtt_client_mock.publish.assert_called_with( - "homeassistant/status", "online", 0, False - ) + + # Assert we already have subscribed at the client + # for new config payloads at the time we the birth message is received + subscribe_calls = help_all_subscribe_calls(mqtt_client_mock) + assert ("homeassistant/+/+/config", 0) in subscribe_calls + assert ("homeassistant/+/+/+/config", 0) in subscribe_calls + mqtt_client_mock.publish.assert_called_with( + "homeassistant/status", "online", 0, False + ) + assert ("topic/test", 0) in subscribe_calls @pytest.mark.parametrize( diff --git a/tests/components/mqtt/test_mixins.py b/tests/components/mqtt/test_mixins.py index 2bcd663c243cfe..e46f0b56c15c27 100644 --- a/tests/components/mqtt/test_mixins.py +++ b/tests/components/mqtt/test_mixins.py @@ -335,6 +335,9 @@ async def test_default_entity_and_device_name( # Assert that no issues ware registered assert len(events) == 0 + await hass.async_block_till_done() + # Assert that no issues ware registered + assert len(events) == 0 async def test_name_attribute_is_set_or_not( From f34a0dc5ce760164aa00046ace3899162a9bc995 Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Tue, 7 May 2024 21:19:46 +0200 Subject: [PATCH 06/19] Log an exception mqtt client call back throws (#117028) * Log an exception mqtt client call back throws * Supress exceptions and add test --- homeassistant/components/mqtt/client.py | 22 +++++++++++--- tests/components/mqtt/test_init.py | 39 ++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/mqtt/client.py b/homeassistant/components/mqtt/client.py index 2ca17f012e4ae9..589113d3a9e9b6 100644 --- a/homeassistant/components/mqtt/client.py +++ b/homeassistant/components/mqtt/client.py @@ -492,6 +492,9 @@ def init_client(self) -> None: mqttc.on_subscribe = self._async_mqtt_on_callback mqttc.on_unsubscribe = self._async_mqtt_on_callback + # suppress exceptions at callback + mqttc.suppress_exceptions = True + if will := self.conf.get(CONF_WILL_MESSAGE, DEFAULT_WILL): will_message = PublishMessage(**will) mqttc.will_set( @@ -988,10 +991,21 @@ def _matching_subscriptions(self, topic: str) -> list[Subscription]: def _async_mqtt_on_message( self, _mqttc: mqtt.Client, _userdata: None, msg: mqtt.MQTTMessage ) -> None: - topic = msg.topic - # msg.topic is a property that decodes the topic to a string - # every time it is accessed. Save the result to avoid - # decoding the same topic multiple times. + try: + # msg.topic is a property that decodes the topic to a string + # every time it is accessed. Save the result to avoid + # decoding the same topic multiple times. + topic = msg.topic + except UnicodeDecodeError: + bare_topic: bytes = getattr(msg, "_topic") + _LOGGER.warning( + "Skipping received%s message on invalid topic %s (qos=%s): %s", + " retained" if msg.retain else "", + bare_topic, + msg.qos, + msg.payload[0:8192], + ) + return _LOGGER.debug( "Received%s message on %s (qos=%s): %s", " retained" if msg.retain else "", diff --git a/tests/components/mqtt/test_init.py b/tests/components/mqtt/test_init.py index b7998274aa0c6a..ec7968ae46b43e 100644 --- a/tests/components/mqtt/test_init.py +++ b/tests/components/mqtt/test_init.py @@ -6,8 +6,9 @@ import json import socket import ssl +import time from typing import Any, TypedDict -from unittest.mock import ANY, MagicMock, call, mock_open, patch +from unittest.mock import ANY, MagicMock, Mock, call, mock_open, patch from freezegun.api import FrozenDateTimeFactory import paho.mqtt.client as paho_mqtt @@ -938,6 +939,42 @@ async def test_receiving_non_utf8_message_gets_logged( ) +async def test_receiving_message_with_non_utf8_topic_gets_logged( + hass: HomeAssistant, + mqtt_mock_entry: MqttMockHAClientGenerator, + record_calls: MessageCallbackType, + caplog: pytest.LogCaptureFixture, +) -> None: + """Test receiving a non utf8 encoded topic.""" + await mqtt_mock_entry() + await mqtt.async_subscribe(hass, "test-topic", record_calls) + + # Local import to avoid processing MQTT modules when running a testcase + # which does not use MQTT. + + # pylint: disable-next=import-outside-toplevel + from paho.mqtt.client import MQTTMessage + + # pylint: disable-next=import-outside-toplevel + from homeassistant.components.mqtt.models import MqttData + + msg = MQTTMessage(topic=b"tasmota/discovery/18FE34E0B760\xcc\x02") + msg.payload = b"Payload" + msg.qos = 2 + msg.retain = True + msg.timestamp = time.monotonic() + + mqtt_data: MqttData = hass.data["mqtt"] + assert mqtt_data.client + mqtt_data.client._async_mqtt_on_message(Mock(), None, msg) + + assert ( + "Skipping received retained message on invalid " + "topic b'tasmota/discovery/18FE34E0B760\\xcc\\x02' " + "(qos=2): b'Payload'" in caplog.text + ) + + async def test_all_subscriptions_run_when_decode_fails( hass: HomeAssistant, mqtt_mock_entry: MqttMockHAClientGenerator, From 08ba5304feb801211c26f68c6f3e98da43b22b18 Mon Sep 17 00:00:00 2001 From: Chris Talkington Date: Wed, 8 May 2024 08:38:44 -0500 Subject: [PATCH 07/19] Bump rokuecp to 0.19.3 (#117059) --- homeassistant/components/roku/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/roku/manifest.json b/homeassistant/components/roku/manifest.json index ce4513fb31661b..fa9823de172510 100644 --- a/homeassistant/components/roku/manifest.json +++ b/homeassistant/components/roku/manifest.json @@ -11,7 +11,7 @@ "iot_class": "local_polling", "loggers": ["rokuecp"], "quality_scale": "silver", - "requirements": ["rokuecp==0.19.2"], + "requirements": ["rokuecp==0.19.3"], "ssdp": [ { "st": "roku:ecp", diff --git a/requirements_all.txt b/requirements_all.txt index f188c7ea248011..b7147c8f8ec5d5 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2460,7 +2460,7 @@ rjpl==0.3.6 rocketchat-API==0.6.1 # homeassistant.components.roku -rokuecp==0.19.2 +rokuecp==0.19.3 # homeassistant.components.romy romy==0.0.10 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 9bec4e50de4929..2f84692c081489 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1906,7 +1906,7 @@ rflink==0.0.66 ring-doorbell[listen]==0.8.11 # homeassistant.components.roku -rokuecp==0.19.2 +rokuecp==0.19.3 # homeassistant.components.romy romy==0.0.10 From 9e7e839f03acce12c687a0701be9feac617eb847 Mon Sep 17 00:00:00 2001 From: Arie Catsman <120491684+catsmanac@users.noreply.github.com> Date: Wed, 8 May 2024 14:02:49 +0200 Subject: [PATCH 08/19] Bump pyenphase to 1.20.3 (#117061) --- homeassistant/components/enphase_envoy/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/enphase_envoy/manifest.json b/homeassistant/components/enphase_envoy/manifest.json index 597d326968d841..b3c117556bf16a 100644 --- a/homeassistant/components/enphase_envoy/manifest.json +++ b/homeassistant/components/enphase_envoy/manifest.json @@ -6,7 +6,7 @@ "documentation": "https://www.home-assistant.io/integrations/enphase_envoy", "iot_class": "local_polling", "loggers": ["pyenphase"], - "requirements": ["pyenphase==1.20.1"], + "requirements": ["pyenphase==1.20.3"], "zeroconf": [ { "type": "_enphase-envoy._tcp.local." diff --git a/requirements_all.txt b/requirements_all.txt index b7147c8f8ec5d5..e39f08d66bf49b 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1800,7 +1800,7 @@ pyefergy==22.1.1 pyegps==0.2.5 # homeassistant.components.enphase_envoy -pyenphase==1.20.1 +pyenphase==1.20.3 # homeassistant.components.envisalink pyenvisalink==4.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 2f84692c081489..2939c4e843ecff 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1405,7 +1405,7 @@ pyefergy==22.1.1 pyegps==0.2.5 # homeassistant.components.enphase_envoy -pyenphase==1.20.1 +pyenphase==1.20.3 # homeassistant.components.everlights pyeverlights==0.1.0 From d40689024a6f389134c141a52eb3f0397040f9ad Mon Sep 17 00:00:00 2001 From: puddly <32534428+puddly@users.noreply.github.com> Date: Wed, 8 May 2024 17:57:50 -0400 Subject: [PATCH 09/19] Add a missing `addon_name` placeholder to the SkyConnect config flow (#117089) --- .../components/homeassistant_sky_connect/config_flow.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/homeassistant_sky_connect/config_flow.py b/homeassistant/components/homeassistant_sky_connect/config_flow.py index 9d0aa902cc41ff..a65aefe96f2ca6 100644 --- a/homeassistant/components/homeassistant_sky_connect/config_flow.py +++ b/homeassistant/components/homeassistant_sky_connect/config_flow.py @@ -95,7 +95,10 @@ async def _async_set_addon_config( _LOGGER.error(err) raise AbortFlow( "addon_set_config_failed", - description_placeholders=self._get_translation_placeholders(), + description_placeholders={ + **self._get_translation_placeholders(), + "addon_name": addon_manager.addon_name, + }, ) from err async def _async_get_addon_info(self, addon_manager: AddonManager) -> AddonInfo: From 82fab7df399f2f8d9091575ade306d4fadc9b093 Mon Sep 17 00:00:00 2001 From: mletenay Date: Thu, 9 May 2024 00:08:08 +0200 Subject: [PATCH 10/19] Goodwe Increase max value of export limit to 200% (#117090) --- homeassistant/components/goodwe/number.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/goodwe/number.py b/homeassistant/components/goodwe/number.py index fc8b3864ae9cb5..d54fb8d8d0cb08 100644 --- a/homeassistant/components/goodwe/number.py +++ b/homeassistant/components/goodwe/number.py @@ -63,7 +63,7 @@ def _get_setting_unit(inverter: Inverter, setting: str) -> str: native_unit_of_measurement=PERCENTAGE, native_step=1, native_min_value=0, - native_max_value=100, + native_max_value=200, getter=lambda inv: inv.get_grid_export_limit(), setter=lambda inv, val: inv.set_grid_export_limit(val), filter=lambda inv: _get_setting_unit(inv, "grid_export_limit") == "%", From 11f86d9e0b0e54a9ef85e0ede2d212cb7c3ee677 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Wed, 8 May 2024 14:16:08 -0500 Subject: [PATCH 11/19] Improve config entry has already been setup error message (#117091) --- homeassistant/helpers/entity_component.py | 5 ++++- tests/helpers/test_entity_component.py | 9 ++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/homeassistant/helpers/entity_component.py b/homeassistant/helpers/entity_component.py index eb54d83e1dddfd..aae0e2058e4747 100644 --- a/homeassistant/helpers/entity_component.py +++ b/homeassistant/helpers/entity_component.py @@ -182,7 +182,10 @@ async def async_setup_entry(self, config_entry: ConfigEntry) -> bool: key = config_entry.entry_id if key in self._platforms: - raise ValueError("Config entry has already been setup!") + raise ValueError( + f"Config entry {config_entry.title} ({key}) for " + f"{platform_type}.{self.domain} has already been setup!" + ) self._platforms[key] = self._async_init_entity_platform( platform_type, diff --git a/tests/helpers/test_entity_component.py b/tests/helpers/test_entity_component.py index 60d0774b549a8b..330876aae05661 100644 --- a/tests/helpers/test_entity_component.py +++ b/tests/helpers/test_entity_component.py @@ -3,6 +3,7 @@ from collections import OrderedDict from datetime import timedelta import logging +import re from unittest.mock import AsyncMock, Mock, patch from freezegun import freeze_time @@ -365,7 +366,13 @@ async def test_setup_entry_fails_duplicate(hass: HomeAssistant) -> None: assert await component.async_setup_entry(entry) - with pytest.raises(ValueError): + with pytest.raises( + ValueError, + match=re.escape( + f"Config entry Mock Title ({entry.entry_id}) for " + "entry_domain.test_domain has already been setup!" + ), + ): await component.async_setup_entry(entry) From b9ed2dab5faa5b1ddf29015376379f0017bb095f Mon Sep 17 00:00:00 2001 From: MatthewFlamm <39341281+MatthewFlamm@users.noreply.github.com> Date: Wed, 8 May 2024 15:16:20 -0400 Subject: [PATCH 12/19] Fix nws blocking startup (#117094) Co-authored-by: J. Nick Koston --- homeassistant/components/nws/__init__.py | 70 ++++++++++++++++-------- 1 file changed, 48 insertions(+), 22 deletions(-) diff --git a/homeassistant/components/nws/__init__.py b/homeassistant/components/nws/__init__.py index 840d4d917f731d..df8cb4c329c2ac 100644 --- a/homeassistant/components/nws/__init__.py +++ b/homeassistant/components/nws/__init__.py @@ -2,8 +2,10 @@ from __future__ import annotations +from collections.abc import Awaitable, Callable from dataclasses import dataclass import datetime +from functools import partial import logging from pynws import SimpleNWS, call_with_retry @@ -58,36 +60,49 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: nws_data = SimpleNWS(latitude, longitude, api_key, client_session) await nws_data.set_station(station) - async def update_observation() -> None: - """Retrieve recent observations.""" - await call_with_retry( - nws_data.update_observation, - RETRY_INTERVAL, - RETRY_STOP, - start_time=utcnow() - UPDATE_TIME_PERIOD, - ) - - async def update_forecast() -> None: - """Retrieve twice-daily forecsat.""" - await call_with_retry( + def async_setup_update_observation( + retry_interval: datetime.timedelta | float, + retry_stop: datetime.timedelta | float, + ) -> Callable[[], Awaitable[None]]: + async def update_observation() -> None: + """Retrieve recent observations.""" + await call_with_retry( + nws_data.update_observation, + retry_interval, + retry_stop, + start_time=utcnow() - UPDATE_TIME_PERIOD, + ) + + return update_observation + + def async_setup_update_forecast( + retry_interval: datetime.timedelta | float, + retry_stop: datetime.timedelta | float, + ) -> Callable[[], Awaitable[None]]: + return partial( + call_with_retry, nws_data.update_forecast, - RETRY_INTERVAL, - RETRY_STOP, + retry_interval, + retry_stop, ) - async def update_forecast_hourly() -> None: - """Retrieve hourly forecast.""" - await call_with_retry( + def async_setup_update_forecast_hourly( + retry_interval: datetime.timedelta | float, + retry_stop: datetime.timedelta | float, + ) -> Callable[[], Awaitable[None]]: + return partial( + call_with_retry, nws_data.update_forecast_hourly, - RETRY_INTERVAL, - RETRY_STOP, + retry_interval, + retry_stop, ) + # Don't use retries in setup coordinator_observation = TimestampDataUpdateCoordinator( hass, _LOGGER, name=f"NWS observation station {station}", - update_method=update_observation, + update_method=async_setup_update_observation(0, 0), update_interval=DEFAULT_SCAN_INTERVAL, request_refresh_debouncer=debounce.Debouncer( hass, _LOGGER, cooldown=DEBOUNCE_TIME, immediate=True @@ -98,7 +113,7 @@ async def update_forecast_hourly() -> None: hass, _LOGGER, name=f"NWS forecast station {station}", - update_method=update_forecast, + update_method=async_setup_update_forecast(0, 0), update_interval=DEFAULT_SCAN_INTERVAL, request_refresh_debouncer=debounce.Debouncer( hass, _LOGGER, cooldown=DEBOUNCE_TIME, immediate=True @@ -109,7 +124,7 @@ async def update_forecast_hourly() -> None: hass, _LOGGER, name=f"NWS forecast hourly station {station}", - update_method=update_forecast_hourly, + update_method=async_setup_update_forecast_hourly(0, 0), update_interval=DEFAULT_SCAN_INTERVAL, request_refresh_debouncer=debounce.Debouncer( hass, _LOGGER, cooldown=DEBOUNCE_TIME, immediate=True @@ -128,6 +143,17 @@ async def update_forecast_hourly() -> None: await coordinator_forecast.async_refresh() await coordinator_forecast_hourly.async_refresh() + # Use retries + coordinator_observation.update_method = async_setup_update_observation( + RETRY_INTERVAL, RETRY_STOP + ) + coordinator_forecast.update_method = async_setup_update_forecast( + RETRY_INTERVAL, RETRY_STOP + ) + coordinator_forecast_hourly.update_method = async_setup_update_forecast_hourly( + RETRY_INTERVAL, RETRY_STOP + ) + await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True From c0cd76b3bfdf066e43a41b476a5381cd091ff5c7 Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Wed, 8 May 2024 21:42:11 +0200 Subject: [PATCH 13/19] Make the mqtt discovery update tasks eager and fix race (#117105) * Fix mqtt discovery race for update rapidly followed on creation * Revert unrelated renaming local var --- homeassistant/components/mqtt/mixins.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/homeassistant/components/mqtt/mixins.py b/homeassistant/components/mqtt/mixins.py index 63df7c71c09fd5..68173da7297341 100644 --- a/homeassistant/components/mqtt/mixins.py +++ b/homeassistant/components/mqtt/mixins.py @@ -1015,8 +1015,7 @@ def discovery_callback(payload: MQTTDiscoveryPayload) -> None: self.hass.async_create_task( _async_process_discovery_update_and_remove( payload, self._discovery_data - ), - eager_start=False, + ) ) elif self._discovery_update: if old_payload != self._discovery_data[ATTR_DISCOVERY_PAYLOAD]: @@ -1025,8 +1024,7 @@ def discovery_callback(payload: MQTTDiscoveryPayload) -> None: self.hass.async_create_task( _async_process_discovery_update( payload, self._discovery_update, self._discovery_data - ), - eager_start=False, + ) ) else: # Non-empty, unchanged payload: Ignore to avoid changing states @@ -1059,6 +1057,15 @@ async def async_removed_from_registry(self) -> None: # rediscovered after a restart await async_remove_discovery_payload(self.hass, self._discovery_data) + @final + async def add_to_platform_finish(self) -> None: + """Finish adding entity to platform.""" + await super().add_to_platform_finish() + # Only send the discovery done after the entity is fully added + # and the state is written to the state machine. + if self._discovery_data is not None: + send_discovery_done(self.hass, self._discovery_data) + @callback def add_to_platform_abort(self) -> None: """Abort adding an entity to a platform.""" @@ -1218,8 +1225,6 @@ async def async_added_to_hass(self) -> None: self._prepare_subscribe_topics() await self._subscribe_topics() await self.mqtt_async_added_to_hass() - if self._discovery_data is not None: - send_discovery_done(self.hass, self._discovery_data) async def mqtt_async_added_to_hass(self) -> None: """Call before the discovery message is acknowledged. From 09490d9e0a6901ca2af822f589038a198d6ee21e Mon Sep 17 00:00:00 2001 From: mletenay Date: Thu, 9 May 2024 00:17:20 +0200 Subject: [PATCH 14/19] Bump goodwe to 0.3.5 (#117115) --- homeassistant/components/goodwe/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/goodwe/manifest.json b/homeassistant/components/goodwe/manifest.json index 59c259524c8f82..8506d1fd6afcc5 100644 --- a/homeassistant/components/goodwe/manifest.json +++ b/homeassistant/components/goodwe/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/goodwe", "iot_class": "local_polling", "loggers": ["goodwe"], - "requirements": ["goodwe==0.3.4"] + "requirements": ["goodwe==0.3.5"] } diff --git a/requirements_all.txt b/requirements_all.txt index e39f08d66bf49b..1ee861f25bceb9 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -952,7 +952,7 @@ glances-api==0.6.0 goalzero==0.2.2 # homeassistant.components.goodwe -goodwe==0.3.4 +goodwe==0.3.5 # homeassistant.components.google_mail # homeassistant.components.google_tasks diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 2939c4e843ecff..189322bd545533 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -781,7 +781,7 @@ glances-api==0.6.0 goalzero==0.2.2 # homeassistant.components.goodwe -goodwe==0.3.4 +goodwe==0.3.5 # homeassistant.components.google_mail # homeassistant.components.google_tasks From 1b519a4610ed2b74420a46c85b973a5fe971b538 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Fri, 10 May 2024 00:47:13 -0500 Subject: [PATCH 15/19] Handle tilt position being None in HKC (#117141) --- .../components/homekit_controller/cover.py | 4 ++- .../homekit_controller/test_cover.py | 34 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/homekit_controller/cover.py b/homeassistant/components/homekit_controller/cover.py index ca041d49e1151c..d0944db38f8466 100644 --- a/homeassistant/components/homekit_controller/cover.py +++ b/homeassistant/components/homekit_controller/cover.py @@ -212,13 +212,15 @@ def is_vertical_tilt(self) -> bool: ) @property - def current_cover_tilt_position(self) -> int: + def current_cover_tilt_position(self) -> int | None: """Return current position of cover tilt.""" tilt_position = self.service.value(CharacteristicsTypes.VERTICAL_TILT_CURRENT) if not tilt_position: tilt_position = self.service.value( CharacteristicsTypes.HORIZONTAL_TILT_CURRENT ) + if tilt_position is None: + return None # Recalculate to convert from arcdegree scale to percentage scale. if self.is_vertical_tilt: scale = 0.9 diff --git a/tests/components/homekit_controller/test_cover.py b/tests/components/homekit_controller/test_cover.py index 671e9779d30008..2157eb5121220e 100644 --- a/tests/components/homekit_controller/test_cover.py +++ b/tests/components/homekit_controller/test_cover.py @@ -3,6 +3,7 @@ from aiohomekit.model.characteristics import CharacteristicsTypes from aiohomekit.model.services import ServicesTypes +from homeassistant.const import STATE_UNAVAILABLE from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er @@ -94,6 +95,24 @@ def create_window_covering_service_with_v_tilt_2(accessory): tilt_target.maxValue = 0 +def create_window_covering_service_with_none_tilt(accessory): + """Define a window-covering characteristics as per page 219 of HAP spec. + + This accessory uses None for the tilt value unexpectedly. + """ + service = create_window_covering_service(accessory) + + tilt_current = service.add_char(CharacteristicsTypes.VERTICAL_TILT_CURRENT) + tilt_current.value = None + tilt_current.minValue = -90 + tilt_current.maxValue = 0 + + tilt_target = service.add_char(CharacteristicsTypes.VERTICAL_TILT_TARGET) + tilt_target.value = None + tilt_target.minValue = -90 + tilt_target.maxValue = 0 + + async def test_change_window_cover_state(hass: HomeAssistant) -> None: """Test that we can turn a HomeKit alarm on and off again.""" helper = await setup_test_component(hass, create_window_covering_service) @@ -212,6 +231,21 @@ async def test_read_window_cover_tilt_vertical_2(hass: HomeAssistant) -> None: assert state.attributes["current_tilt_position"] == 83 +async def test_read_window_cover_tilt_missing_tilt(hass: HomeAssistant) -> None: + """Test that missing tilt is handled.""" + helper = await setup_test_component( + hass, create_window_covering_service_with_none_tilt + ) + + await helper.async_update( + ServicesTypes.WINDOW_COVERING, + {CharacteristicsTypes.OBSTRUCTION_DETECTED: True}, + ) + state = await helper.poll_and_get_state() + assert "current_tilt_position" not in state.attributes + assert state.state != STATE_UNAVAILABLE + + async def test_write_window_cover_tilt_horizontal(hass: HomeAssistant) -> None: """Test that horizontal tilt is written correctly.""" helper = await setup_test_component( From 56b38cd8427a2c131d61eddf35f559f9e7942d4c Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Thu, 9 May 2024 16:31:36 +0200 Subject: [PATCH 16/19] Fix typo in xiaomi_ble translation strings (#117144) --- homeassistant/components/xiaomi_ble/strings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/xiaomi_ble/strings.json b/homeassistant/components/xiaomi_ble/strings.json index 8ee8bac3feaef8..048c9bd92e2485 100644 --- a/homeassistant/components/xiaomi_ble/strings.json +++ b/homeassistant/components/xiaomi_ble/strings.json @@ -83,7 +83,7 @@ "button_fan": "Button Fan \"{subtype}\"", "button_swing": "Button Swing \"{subtype}\"", "button_decrease_speed": "Button Decrease Speed \"{subtype}\"", - "button_increase_speed": "Button Inrease Speed \"{subtype}\"", + "button_increase_speed": "Button Increase Speed \"{subtype}\"", "button_stop": "Button Stop \"{subtype}\"", "button_light": "Button Light \"{subtype}\"", "button_wind_speed": "Button Wind Speed \"{subtype}\"", From f07c00a05b24f1808a7e30d1361fff2f11d167cd Mon Sep 17 00:00:00 2001 From: Diogo Gomes Date: Fri, 10 May 2024 18:59:28 +0100 Subject: [PATCH 17/19] Bump pytrydan to 0.6.0 (#117162) --- homeassistant/components/v2c/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/v2c/manifest.json b/homeassistant/components/v2c/manifest.json index ce0e9d7b8470c8..fb234d726e867e 100644 --- a/homeassistant/components/v2c/manifest.json +++ b/homeassistant/components/v2c/manifest.json @@ -5,5 +5,5 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/v2c", "iot_class": "local_polling", - "requirements": ["pytrydan==0.4.0"] + "requirements": ["pytrydan==0.6.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index 1ee861f25bceb9..e0cc726f3e0d05 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2337,7 +2337,7 @@ pytradfri[async]==9.0.1 pytrafikverket==0.3.10 # homeassistant.components.v2c -pytrydan==0.4.0 +pytrydan==0.6.0 # homeassistant.components.usb pyudev==0.24.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 189322bd545533..6b9ce0504f511e 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1816,7 +1816,7 @@ pytradfri[async]==9.0.1 pytrafikverket==0.3.10 # homeassistant.components.v2c -pytrydan==0.4.0 +pytrydan==0.6.0 # homeassistant.components.usb pyudev==0.24.1 From 2c8b3ac8bbf76f764214b760db82990e32c915ed Mon Sep 17 00:00:00 2001 From: Robert Resch Date: Fri, 10 May 2024 13:33:18 +0200 Subject: [PATCH 18/19] Bump deebot-client to 7.2.0 (#117189) --- homeassistant/components/ecovacs/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/ecovacs/manifest.json b/homeassistant/components/ecovacs/manifest.json index aad04d9ec87907..e6bd59e3d12c94 100644 --- a/homeassistant/components/ecovacs/manifest.json +++ b/homeassistant/components/ecovacs/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/ecovacs", "iot_class": "cloud_push", "loggers": ["sleekxmppfs", "sucks", "deebot_client"], - "requirements": ["py-sucks==0.9.9", "deebot-client==7.1.0"] + "requirements": ["py-sucks==0.9.9", "deebot-client==7.2.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index e0cc726f3e0d05..f0acc214f78400 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -697,7 +697,7 @@ debugpy==1.8.1 # decora==0.6 # homeassistant.components.ecovacs -deebot-client==7.1.0 +deebot-client==7.2.0 # homeassistant.components.ihc # homeassistant.components.namecheapdns diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 6b9ce0504f511e..47f4f1baf51445 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -575,7 +575,7 @@ dbus-fast==2.21.1 debugpy==1.8.1 # homeassistant.components.ecovacs -deebot-client==7.1.0 +deebot-client==7.2.0 # homeassistant.components.ihc # homeassistant.components.namecheapdns From e2da28fbdb3c226f624dce7c18eedc62abcd8c87 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 10 May 2024 18:14:24 +0000 Subject: [PATCH 19/19] Bump version to 2024.5.3 --- 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 e9e1231712ec8d..4bab6d0f12708c 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -23,7 +23,7 @@ APPLICATION_NAME: Final = "HomeAssistant" MAJOR_VERSION: Final = 2024 MINOR_VERSION: Final = 5 -PATCH_VERSION: Final = "2" +PATCH_VERSION: Final = "3" __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 8fb7839c628196..5c24c020e82d9d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "homeassistant" -version = "2024.5.2" +version = "2024.5.3" license = {text = "Apache-2.0"} description = "Open-source home automation platform running on Python 3." readme = "README.rst"