From 94800cb11e8c29d1284cf32c6781201996316ebf Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Fri, 21 Jun 2024 10:55:21 +0200 Subject: [PATCH 01/26] UniFi temp fix to handle runtime data (#120031) Co-authored-by: Franck Nijhof --- homeassistant/components/unifi/config_flow.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/unifi/config_flow.py b/homeassistant/components/unifi/config_flow.py index e703f393d683..af4e0fde1371 100644 --- a/homeassistant/components/unifi/config_flow.py +++ b/homeassistant/components/unifi/config_flow.py @@ -164,10 +164,14 @@ class UnifiFlowHandler(ConfigFlow, domain=UNIFI_DOMAIN): abort_reason = "reauth_successful" if config_entry: - hub = config_entry.runtime_data + try: + hub = config_entry.runtime_data - if hub and hub.available: - return self.async_abort(reason="already_configured") + if hub and hub.available: + return self.async_abort(reason="already_configured") + + except AttributeError: + pass return self.async_update_reload_and_abort( config_entry, data=self.config, reason=abort_reason From ddec6d04e1b7b03b3d5535d4f92ddc5b82fc8f9f Mon Sep 17 00:00:00 2001 From: Lode Smets <31108717+lodesmets@users.noreply.github.com> Date: Sun, 16 Jun 2024 00:48:08 +0200 Subject: [PATCH 02/26] Fix for Synology DSM shared images (#117695) * Fix for shared images * - FIX: Synology shared photos * - changes after review * Added test * added test * fix test --- .../components/synology_dsm/const.py | 2 ++ .../components/synology_dsm/media_source.py | 21 +++++++++++---- .../synology_dsm/test_media_source.py | 26 ++++++++++++++++--- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/homeassistant/components/synology_dsm/const.py b/homeassistant/components/synology_dsm/const.py index 11839caf8bef..e63674585788 100644 --- a/homeassistant/components/synology_dsm/const.py +++ b/homeassistant/components/synology_dsm/const.py @@ -46,6 +46,8 @@ DEFAULT_SNAPSHOT_QUALITY = SNAPSHOT_PROFILE_BALANCED ENTITY_UNIT_LOAD = "load" +SHARED_SUFFIX = "_shared" + # Signals SIGNAL_CAMERA_SOURCE_CHANGED = "synology_dsm.camera_stream_source_changed" diff --git a/homeassistant/components/synology_dsm/media_source.py b/homeassistant/components/synology_dsm/media_source.py index 4b0c19b2b55a..ace5733c2222 100644 --- a/homeassistant/components/synology_dsm/media_source.py +++ b/homeassistant/components/synology_dsm/media_source.py @@ -21,7 +21,7 @@ from homeassistant.components.media_source import ( from homeassistant.config_entries import ConfigEntry from homeassistant.core import HomeAssistant -from .const import DOMAIN +from .const import DOMAIN, SHARED_SUFFIX from .models import SynologyDSMData @@ -45,6 +45,7 @@ class SynologyPhotosMediaSourceIdentifier: self.album_id = None self.cache_key = None self.file_name = None + self.is_shared = False if parts: self.unique_id = parts[0] @@ -54,6 +55,9 @@ class SynologyPhotosMediaSourceIdentifier: self.cache_key = parts[2] if len(parts) > 3: self.file_name = parts[3] + if self.file_name.endswith(SHARED_SUFFIX): + self.is_shared = True + self.file_name = self.file_name.removesuffix(SHARED_SUFFIX) class SynologyPhotosMediaSource(MediaSource): @@ -160,10 +164,13 @@ class SynologyPhotosMediaSource(MediaSource): if isinstance(mime_type, str) and mime_type.startswith("image/"): # Force small small thumbnails album_item.thumbnail_size = "sm" + suffix = "" + if album_item.is_shared: + suffix = SHARED_SUFFIX ret.append( BrowseMediaSource( domain=DOMAIN, - identifier=f"{identifier.unique_id}/{identifier.album_id}/{album_item.thumbnail_cache_key}/{album_item.file_name}", + identifier=f"{identifier.unique_id}/{identifier.album_id}/{album_item.thumbnail_cache_key}/{album_item.file_name}{suffix}", media_class=MediaClass.IMAGE, media_content_type=mime_type, title=album_item.file_name, @@ -186,8 +193,11 @@ class SynologyPhotosMediaSource(MediaSource): mime_type, _ = mimetypes.guess_type(identifier.file_name) if not isinstance(mime_type, str): raise Unresolvable("No file extension") + suffix = "" + if identifier.is_shared: + suffix = SHARED_SUFFIX return PlayMedia( - f"/synology_dsm/{identifier.unique_id}/{identifier.cache_key}/{identifier.file_name}", + f"/synology_dsm/{identifier.unique_id}/{identifier.cache_key}/{identifier.file_name}{suffix}", mime_type, ) @@ -223,13 +233,14 @@ class SynologyDsmMediaView(http.HomeAssistantView): # location: {cache_key}/{filename} cache_key, file_name = location.split("/") image_id = int(cache_key.split("_")[0]) + if shared := file_name.endswith(SHARED_SUFFIX): + file_name = file_name.removesuffix(SHARED_SUFFIX) mime_type, _ = mimetypes.guess_type(file_name) if not isinstance(mime_type, str): raise web.HTTPNotFound diskstation: SynologyDSMData = self.hass.data[DOMAIN][source_dir_id] - assert diskstation.api.photos is not None - item = SynoPhotosItem(image_id, "", "", "", cache_key, "", False) + item = SynoPhotosItem(image_id, "", "", "", cache_key, "", shared) try: image = await diskstation.api.photos.download_item(item) except SynologyDSMException as exc: diff --git a/tests/components/synology_dsm/test_media_source.py b/tests/components/synology_dsm/test_media_source.py index 2a792d174f81..433a4b15c23f 100644 --- a/tests/components/synology_dsm/test_media_source.py +++ b/tests/components/synology_dsm/test_media_source.py @@ -50,7 +50,8 @@ def dsm_with_photos() -> MagicMock: dsm.photos.get_albums = AsyncMock(return_value=[SynoPhotosAlbum(1, "Album 1", 10)]) dsm.photos.get_items_from_album = AsyncMock( return_value=[ - SynoPhotosItem(10, "", "filename.jpg", 12345, "10_1298753", "sm", False) + SynoPhotosItem(10, "", "filename.jpg", 12345, "10_1298753", "sm", False), + SynoPhotosItem(10, "", "filename.jpg", 12345, "10_1298753", "sm", True), ] ) dsm.photos.get_item_thumbnail_url = AsyncMock( @@ -102,6 +103,11 @@ async def test_resolve_media_bad_identifier( "/synology_dsm/ABC012345/12631_47189/filename.png", "image/png", ), + ( + "ABC012345/12/12631_47189/filename.png_shared", + "/synology_dsm/ABC012345/12631_47189/filename.png_shared", + "image/png", + ), ], ) async def test_resolve_media_success( @@ -333,7 +339,7 @@ async def test_browse_media_get_items_thumbnail_error( result = await source.async_browse_media(item) assert result - assert len(result.children) == 1 + assert len(result.children) == 2 item = result.children[0] assert isinstance(item, BrowseMedia) assert item.thumbnail is None @@ -372,7 +378,7 @@ async def test_browse_media_get_items( result = await source.async_browse_media(item) assert result - assert len(result.children) == 1 + assert len(result.children) == 2 item = result.children[0] assert isinstance(item, BrowseMedia) assert item.identifier == "mocked_syno_dsm_entry/1/10_1298753/filename.jpg" @@ -382,6 +388,15 @@ async def test_browse_media_get_items( assert item.can_play assert not item.can_expand assert item.thumbnail == "http://my.thumbnail.url" + item = result.children[1] + assert isinstance(item, BrowseMedia) + assert item.identifier == "mocked_syno_dsm_entry/1/10_1298753/filename.jpg_shared" + assert item.title == "filename.jpg" + assert item.media_class == MediaClass.IMAGE + assert item.media_content_type == "image/jpeg" + assert item.can_play + assert not item.can_expand + assert item.thumbnail == "http://my.thumbnail.url" @pytest.mark.usefixtures("setup_media_source") @@ -435,3 +450,8 @@ async def test_media_view( request, "mocked_syno_dsm_entry", "10_1298753/filename.jpg" ) assert isinstance(result, web.Response) + with patch.object(tempfile, "tempdir", tmp_path): + result = await view.get( + request, "mocked_syno_dsm_entry", "10_1298753/filename.jpg_shared" + ) + assert isinstance(result, web.Response) From 8e63bd3ac09ee8426639c1c82b9b415b83e40a5e Mon Sep 17 00:00:00 2001 From: Tsvi Mostovicz Date: Mon, 17 Jun 2024 13:37:30 +0300 Subject: [PATCH 03/26] Fix Jewish Calendar unique id migration (#119683) * Implement correct passing fix * Keep the test as is, as it simulates the current behavior * Last minor change --- homeassistant/components/jewish_calendar/__init__.py | 5 ++++- tests/components/jewish_calendar/test_init.py | 1 - 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/jewish_calendar/__init__.py b/homeassistant/components/jewish_calendar/__init__.py index 8383f9181fc1..81fe6cb5377d 100644 --- a/homeassistant/components/jewish_calendar/__init__.py +++ b/homeassistant/components/jewish_calendar/__init__.py @@ -72,11 +72,14 @@ def get_unique_prefix( havdalah_offset: int | None, ) -> str: """Create a prefix for unique ids.""" + # location.altitude was unset before 2024.6 when this method + # was used to create the unique id. As such it would always + # use the default altitude of 754. config_properties = [ location.latitude, location.longitude, location.timezone, - location.altitude, + 754, location.diaspora, language, candle_lighting_offset, diff --git a/tests/components/jewish_calendar/test_init.py b/tests/components/jewish_calendar/test_init.py index f052d4e7f462..b8454b41a603 100644 --- a/tests/components/jewish_calendar/test_init.py +++ b/tests/components/jewish_calendar/test_init.py @@ -38,7 +38,6 @@ async def test_import_unique_id_migration(hass: HomeAssistant) -> None: latitude=yaml_conf[DOMAIN][CONF_LATITUDE], longitude=yaml_conf[DOMAIN][CONF_LONGITUDE], timezone=hass.config.time_zone, - altitude=hass.config.elevation, diaspora=DEFAULT_DIASPORA, ) old_prefix = get_unique_prefix(location, DEFAULT_LANGUAGE, 20, 50) From 7a9537dcc93b62e47e1ab54aac1184769cf215ee Mon Sep 17 00:00:00 2001 From: jjlawren Date: Sat, 15 Jun 2024 17:47:47 -0500 Subject: [PATCH 04/26] Fix model import in Spotify (#119747) * Always import HomeAssistantSpotifyData in spotify.media_browser Relocate HomeAssistantSpotifyData to avoid circular import * Fix moved import * Rename module to 'models' * Adjust docstring --- homeassistant/components/spotify/__init__.py | 12 +----------- .../components/spotify/browse_media.py | 6 ++---- .../components/spotify/media_player.py | 3 ++- homeassistant/components/spotify/models.py | 19 +++++++++++++++++++ 4 files changed, 24 insertions(+), 16 deletions(-) create mode 100644 homeassistant/components/spotify/models.py diff --git a/homeassistant/components/spotify/__init__.py b/homeassistant/components/spotify/__init__.py index 632871ba36eb..becf90b04cdf 100644 --- a/homeassistant/components/spotify/__init__.py +++ b/homeassistant/components/spotify/__init__.py @@ -2,7 +2,6 @@ from __future__ import annotations -from dataclasses import dataclass from datetime import timedelta from typing import Any @@ -22,6 +21,7 @@ from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, Upda from .browse_media import async_browse_media from .const import DOMAIN, LOGGER, SPOTIFY_SCOPES +from .models import HomeAssistantSpotifyData from .util import ( is_spotify_media_type, resolve_spotify_media_type, @@ -39,16 +39,6 @@ __all__ = [ ] -@dataclass -class HomeAssistantSpotifyData: - """Spotify data stored in the Home Assistant data object.""" - - client: Spotify - current_user: dict[str, Any] - devices: DataUpdateCoordinator[list[dict[str, Any]]] - session: OAuth2Session - - type SpotifyConfigEntry = ConfigEntry[HomeAssistantSpotifyData] diff --git a/homeassistant/components/spotify/browse_media.py b/homeassistant/components/spotify/browse_media.py index a1d3d9c804a9..cff7cae5ebdd 100644 --- a/homeassistant/components/spotify/browse_media.py +++ b/homeassistant/components/spotify/browse_media.py @@ -5,7 +5,7 @@ from __future__ import annotations from enum import StrEnum from functools import partial import logging -from typing import TYPE_CHECKING, Any +from typing import Any from spotipy import Spotify import yarl @@ -20,11 +20,9 @@ from homeassistant.core import HomeAssistant from homeassistant.helpers.config_entry_oauth2_flow import OAuth2Session from .const import DOMAIN, MEDIA_PLAYER_PREFIX, MEDIA_TYPE_SHOW, PLAYABLE_MEDIA_TYPES +from .models import HomeAssistantSpotifyData from .util import fetch_image_url -if TYPE_CHECKING: - from . import HomeAssistantSpotifyData - BROWSE_LIMIT = 48 diff --git a/homeassistant/components/spotify/media_player.py b/homeassistant/components/spotify/media_player.py index fe9614374f79..bd1bcdfd43ed 100644 --- a/homeassistant/components/spotify/media_player.py +++ b/homeassistant/components/spotify/media_player.py @@ -29,9 +29,10 @@ from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.util.dt import utcnow -from . import HomeAssistantSpotifyData, SpotifyConfigEntry +from . import SpotifyConfigEntry from .browse_media import async_browse_media_internal from .const import DOMAIN, MEDIA_PLAYER_PREFIX, PLAYABLE_MEDIA_TYPES, SPOTIFY_SCOPES +from .models import HomeAssistantSpotifyData from .util import fetch_image_url _LOGGER = logging.getLogger(__name__) diff --git a/homeassistant/components/spotify/models.py b/homeassistant/components/spotify/models.py new file mode 100644 index 000000000000..bbec134d89d5 --- /dev/null +++ b/homeassistant/components/spotify/models.py @@ -0,0 +1,19 @@ +"""Models for use in Spotify integration.""" + +from dataclasses import dataclass +from typing import Any + +from spotipy import Spotify + +from homeassistant.helpers.config_entry_oauth2_flow import OAuth2Session +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator + + +@dataclass +class HomeAssistantSpotifyData: + """Spotify data stored in the Home Assistant data object.""" + + client: Spotify + current_user: dict[str, Any] + devices: DataUpdateCoordinator[list[dict[str, Any]]] + session: OAuth2Session From 98aeb0b034b295b380c1039911ece99a16601d3f Mon Sep 17 00:00:00 2001 From: dubstomp <156379311+dubstomp@users.noreply.github.com> Date: Mon, 17 Jun 2024 02:31:18 -0700 Subject: [PATCH 05/26] Add Kasa Dimmer to Matter TRANSITION_BLOCKLIST (#119751) --- homeassistant/components/matter/light.py | 1 + 1 file changed, 1 insertion(+) diff --git a/homeassistant/components/matter/light.py b/homeassistant/components/matter/light.py index 89400c98989c..007bcd1a33a5 100644 --- a/homeassistant/components/matter/light.py +++ b/homeassistant/components/matter/light.py @@ -56,6 +56,7 @@ TRANSITION_BLOCKLIST = ( (5010, 769, "3.0", "1.0.0"), (4999, 25057, "1.0", "27.0"), (4448, 36866, "V1", "V1.0.0.5"), + (5009, 514, "1.0", "1.0.0"), ) From 0b4bbbffc8ab3be7be6a4c7d21664f53ecf0d4b9 Mon Sep 17 00:00:00 2001 From: 0bmay <57501269+0bmay@users.noreply.github.com> Date: Mon, 17 Jun 2024 01:02:42 -0700 Subject: [PATCH 06/26] Bump py-canary to v0.5.4 (#119793) fix gathering data from Canary sensors --- homeassistant/components/canary/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/canary/manifest.json b/homeassistant/components/canary/manifest.json index e6bc52540d57..4d5adf4a32be 100644 --- a/homeassistant/components/canary/manifest.json +++ b/homeassistant/components/canary/manifest.json @@ -7,5 +7,5 @@ "documentation": "https://www.home-assistant.io/integrations/canary", "iot_class": "cloud_polling", "loggers": ["canary"], - "requirements": ["py-canary==0.5.3"] + "requirements": ["py-canary==0.5.4"] } diff --git a/requirements_all.txt b/requirements_all.txt index 289a4eead5d2..f6b135167ba4 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1619,7 +1619,7 @@ pvo==2.1.1 py-aosmith==1.0.8 # homeassistant.components.canary -py-canary==0.5.3 +py-canary==0.5.4 # homeassistant.components.ccm15 py-ccm15==0.0.9 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 6bf487f7ef9d..9cb5481b9a9a 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1284,7 +1284,7 @@ pvo==2.1.1 py-aosmith==1.0.8 # homeassistant.components.canary -py-canary==0.5.3 +py-canary==0.5.4 # homeassistant.components.ccm15 py-ccm15==0.0.9 From 08578147f505b2c85c8cf37be9ecd1850957060b Mon Sep 17 00:00:00 2001 From: Marc Mueller <30130371+cdce8p@users.noreply.github.com> Date: Mon, 17 Jun 2024 11:17:35 +0200 Subject: [PATCH 07/26] Pin tenacity to 8.3.0 (#119815) --- homeassistant/package_constraints.txt | 3 +++ script/gen_requirements_all.py | 3 +++ 2 files changed, 6 insertions(+) diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 94f030c61045..ac1db19684c7 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -197,3 +197,6 @@ scapy>=2.5.0 # Only tuf>=4 includes a constraint to <1.0. # https://github.com/theupdateframework/python-tuf/releases/tag/v4.0.0 tuf>=4.0.0 + +# https://github.com/jd/tenacity/issues/471 +tenacity<8.4.0 diff --git a/script/gen_requirements_all.py b/script/gen_requirements_all.py index 1f2f4bcab66c..a12decd5b2cc 100755 --- a/script/gen_requirements_all.py +++ b/script/gen_requirements_all.py @@ -219,6 +219,9 @@ scapy>=2.5.0 # Only tuf>=4 includes a constraint to <1.0. # https://github.com/theupdateframework/python-tuf/releases/tag/v4.0.0 tuf>=4.0.0 + +# https://github.com/jd/tenacity/issues/471 +tenacity<8.4.0 """ GENERATED_MESSAGE = ( From 99d1de901ee85146638e17ec113ef0f537c1bf5d Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 17 Jun 2024 12:05:44 -0500 Subject: [PATCH 08/26] Bump aiozoneinfo to 0.2.0 (#119845) --- 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 ac1db19684c7..8a64a42cc9dc 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -7,7 +7,7 @@ aiohttp-fast-url-dispatcher==0.3.0 aiohttp-fast-zlib==0.1.0 aiohttp==3.9.5 aiohttp_cors==0.7.0 -aiozoneinfo==0.1.0 +aiozoneinfo==0.2.0 astral==2.2 async-interrupt==1.1.1 async-upnp-client==0.38.3 diff --git a/pyproject.toml b/pyproject.toml index 1ca2b5cb40ea..a03f3533a808 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ dependencies = [ "aiohttp_cors==0.7.0", "aiohttp-fast-url-dispatcher==0.3.0", "aiohttp-fast-zlib==0.1.0", - "aiozoneinfo==0.1.0", + "aiozoneinfo==0.2.0", "astral==2.2", "async-interrupt==1.1.1", "attrs==23.2.0", diff --git a/requirements.txt b/requirements.txt index 05b0eb35c1e6..4790de4d064a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,7 +8,7 @@ aiohttp==3.9.5 aiohttp_cors==0.7.0 aiohttp-fast-url-dispatcher==0.3.0 aiohttp-fast-zlib==0.1.0 -aiozoneinfo==0.1.0 +aiozoneinfo==0.2.0 astral==2.2 async-interrupt==1.1.1 attrs==23.2.0 From e1225d3f565ca4548e884a525edbfb359e51f464 Mon Sep 17 00:00:00 2001 From: Brent Petit Date: Tue, 18 Jun 2024 00:58:00 -0500 Subject: [PATCH 09/26] Fix up ecobee windspeed unit (#119870) --- homeassistant/components/ecobee/weather.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/ecobee/weather.py b/homeassistant/components/ecobee/weather.py index b7961f956eb4..b6378504c65a 100644 --- a/homeassistant/components/ecobee/weather.py +++ b/homeassistant/components/ecobee/weather.py @@ -59,7 +59,7 @@ class EcobeeWeather(WeatherEntity): _attr_native_pressure_unit = UnitOfPressure.HPA _attr_native_temperature_unit = UnitOfTemperature.FAHRENHEIT _attr_native_visibility_unit = UnitOfLength.METERS - _attr_native_wind_speed_unit = UnitOfSpeed.METERS_PER_SECOND + _attr_native_wind_speed_unit = UnitOfSpeed.MILES_PER_HOUR _attr_has_entity_name = True _attr_name = None _attr_supported_features = WeatherEntityFeature.FORECAST_DAILY From 5b1b137fd2f954b5093ac5390c2eee4665439dcd Mon Sep 17 00:00:00 2001 From: Tsvi Mostovicz Date: Wed, 19 Jun 2024 17:21:43 +0300 Subject: [PATCH 10/26] Bump hdate to 0.10.9 (#119887) --- homeassistant/components/jewish_calendar/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/jewish_calendar/manifest.json b/homeassistant/components/jewish_calendar/manifest.json index 20eb28929bd6..6d2fe8ecfa1e 100644 --- a/homeassistant/components/jewish_calendar/manifest.json +++ b/homeassistant/components/jewish_calendar/manifest.json @@ -6,6 +6,6 @@ "documentation": "https://www.home-assistant.io/integrations/jewish_calendar", "iot_class": "calculated", "loggers": ["hdate"], - "requirements": ["hdate==0.10.8"], + "requirements": ["hdate==0.10.9"], "single_config_entry": true } diff --git a/requirements_all.txt b/requirements_all.txt index f6b135167ba4..91e5557f06d4 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1056,7 +1056,7 @@ hass-splunk==0.1.1 hassil==1.7.1 # homeassistant.components.jewish_calendar -hdate==0.10.8 +hdate==0.10.9 # homeassistant.components.heatmiser heatmiserV3==1.1.18 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 9cb5481b9a9a..6acad0b2132e 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -867,7 +867,7 @@ hass-nabucasa==0.81.1 hassil==1.7.1 # homeassistant.components.jewish_calendar -hdate==0.10.8 +hdate==0.10.9 # homeassistant.components.here_travel_time here-routing==0.2.0 From 91064697b53fec6433eb03e3e82e1f0c4cf2a451 Mon Sep 17 00:00:00 2001 From: Jeef Date: Tue, 18 Jun 2024 14:31:59 -0600 Subject: [PATCH 11/26] Bump weatherflow4py to 0.2.21 (#119889) --- homeassistant/components/weatherflow_cloud/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/weatherflow_cloud/manifest.json b/homeassistant/components/weatherflow_cloud/manifest.json index 361349dcbe88..93df04d833c6 100644 --- a/homeassistant/components/weatherflow_cloud/manifest.json +++ b/homeassistant/components/weatherflow_cloud/manifest.json @@ -5,5 +5,5 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/weatherflow_cloud", "iot_class": "cloud_polling", - "requirements": ["weatherflow4py==0.2.20"] + "requirements": ["weatherflow4py==0.2.21"] } diff --git a/requirements_all.txt b/requirements_all.txt index 91e5557f06d4..58a7e9a0aa0c 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2867,7 +2867,7 @@ watchdog==2.3.1 waterfurnace==1.1.0 # homeassistant.components.weatherflow_cloud -weatherflow4py==0.2.20 +weatherflow4py==0.2.21 # homeassistant.components.webmin webmin-xmlrpc==0.0.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 6acad0b2132e..2a41ba11b626 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2226,7 +2226,7 @@ wallbox==0.6.0 watchdog==2.3.1 # homeassistant.components.weatherflow_cloud -weatherflow4py==0.2.20 +weatherflow4py==0.2.21 # homeassistant.components.webmin webmin-xmlrpc==0.0.2 From 16314c5c7c8cede70999c416aee760735d0b623d Mon Sep 17 00:00:00 2001 From: G Johansson Date: Fri, 7 Jun 2024 10:53:54 +0200 Subject: [PATCH 12/26] Bump babel to 2.15.0 (#119006) --- homeassistant/components/holiday/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/holiday/manifest.json b/homeassistant/components/holiday/manifest.json index bc7ce0e8dd14..c026c3e63636 100644 --- a/homeassistant/components/holiday/manifest.json +++ b/homeassistant/components/holiday/manifest.json @@ -5,5 +5,5 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/holiday", "iot_class": "local_polling", - "requirements": ["holidays==0.50", "babel==2.13.1"] + "requirements": ["holidays==0.50", "babel==2.15.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index 58a7e9a0aa0c..72889580c334 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -526,7 +526,7 @@ azure-kusto-ingest==3.1.0 azure-servicebus==7.10.0 # homeassistant.components.holiday -babel==2.13.1 +babel==2.15.0 # homeassistant.components.baidu baidu-aip==1.6.6 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 2a41ba11b626..d6abb87bc0f8 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -463,7 +463,7 @@ azure-kusto-data[aio]==3.1.0 azure-kusto-ingest==3.1.0 # homeassistant.components.holiday -babel==2.13.1 +babel==2.15.0 # homeassistant.components.homekit base36==0.1.1 From c3607bd6d50389f1ed5aca86c543f49ff09c84a4 Mon Sep 17 00:00:00 2001 From: G Johansson Date: Tue, 18 Jun 2024 22:05:11 +0200 Subject: [PATCH 13/26] Bump python-holidays to 0.51 (#119918) --- homeassistant/components/holiday/manifest.json | 2 +- homeassistant/components/workday/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/holiday/manifest.json b/homeassistant/components/holiday/manifest.json index c026c3e63636..cb67039f374c 100644 --- a/homeassistant/components/holiday/manifest.json +++ b/homeassistant/components/holiday/manifest.json @@ -5,5 +5,5 @@ "config_flow": true, "documentation": "https://www.home-assistant.io/integrations/holiday", "iot_class": "local_polling", - "requirements": ["holidays==0.50", "babel==2.15.0"] + "requirements": ["holidays==0.51", "babel==2.15.0"] } diff --git a/homeassistant/components/workday/manifest.json b/homeassistant/components/workday/manifest.json index 71c26a30e947..1148f46e2d10 100644 --- a/homeassistant/components/workday/manifest.json +++ b/homeassistant/components/workday/manifest.json @@ -7,5 +7,5 @@ "iot_class": "local_polling", "loggers": ["holidays"], "quality_scale": "internal", - "requirements": ["holidays==0.50"] + "requirements": ["holidays==0.51"] } diff --git a/requirements_all.txt b/requirements_all.txt index 72889580c334..be954357eb7a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1084,7 +1084,7 @@ hole==0.8.0 # homeassistant.components.holiday # homeassistant.components.workday -holidays==0.50 +holidays==0.51 # homeassistant.components.frontend home-assistant-frontend==20240610.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index d6abb87bc0f8..4b3c08a2e24c 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -886,7 +886,7 @@ hole==0.8.0 # homeassistant.components.holiday # homeassistant.components.workday -holidays==0.50 +holidays==0.51 # homeassistant.components.frontend home-assistant-frontend==20240610.1 From a55e82366ad269f291cab909efdfda8fd661c751 Mon Sep 17 00:00:00 2001 From: Artur Pragacz <49985303+arturpragacz@users.noreply.github.com> Date: Wed, 19 Jun 2024 22:48:34 +0200 Subject: [PATCH 14/26] Fix Onkyo zone volume (#119949) --- homeassistant/components/onkyo/media_player.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/onkyo/media_player.py b/homeassistant/components/onkyo/media_player.py index 7575443c7935..97e0b3e36317 100644 --- a/homeassistant/components/onkyo/media_player.py +++ b/homeassistant/components/onkyo/media_player.py @@ -341,7 +341,7 @@ class OnkyoDevice(MediaPlayerEntity): del self._attr_extra_state_attributes[ATTR_PRESET] self._attr_is_volume_muted = bool(mute_raw[1] == "on") - # AMP_VOL/MAX_RECEIVER_VOL*(MAX_VOL/100) + # AMP_VOL / (MAX_RECEIVER_VOL * (MAX_VOL / 100)) self._attr_volume_level = volume_raw[1] / ( self._receiver_max_volume * self._max_volume / 100 ) @@ -511,9 +511,9 @@ class OnkyoDeviceZone(OnkyoDevice): elif ATTR_PRESET in self._attr_extra_state_attributes: del self._attr_extra_state_attributes[ATTR_PRESET] if self._supports_volume: - # AMP_VOL/MAX_RECEIVER_VOL*(MAX_VOL/100) - self._attr_volume_level = ( - volume_raw[1] / self._receiver_max_volume * (self._max_volume / 100) + # AMP_VOL / (MAX_RECEIVER_VOL * (MAX_VOL / 100)) + self._attr_volume_level = volume_raw[1] / ( + self._receiver_max_volume * self._max_volume / 100 ) @property From 500ef94ad4b304576ee80f998a19d5fdaa3dca80 Mon Sep 17 00:00:00 2001 From: Bouwe Westerdijk <11290930+bouwew@users.noreply.github.com> Date: Wed, 19 Jun 2024 19:23:14 +0200 Subject: [PATCH 15/26] Bump plugwise to v0.37.4.1 (#119963) * Bump plugwise to v0.37.4 * bump plugwise to v0.37.4.1 --- homeassistant/components/plugwise/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/plugwise/manifest.json b/homeassistant/components/plugwise/manifest.json index ada7d2d25339..b1937ee219dc 100644 --- a/homeassistant/components/plugwise/manifest.json +++ b/homeassistant/components/plugwise/manifest.json @@ -7,6 +7,6 @@ "integration_type": "hub", "iot_class": "local_polling", "loggers": ["plugwise"], - "requirements": ["plugwise==0.37.3"], + "requirements": ["plugwise==0.37.4.1"], "zeroconf": ["_plugwise._tcp.local."] } diff --git a/requirements_all.txt b/requirements_all.txt index be954357eb7a..0a97310fdd5e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1566,7 +1566,7 @@ plexauth==0.0.6 plexwebsocket==0.0.14 # homeassistant.components.plugwise -plugwise==0.37.3 +plugwise==0.37.4.1 # homeassistant.components.plum_lightpad plumlightpad==0.0.11 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 4b3c08a2e24c..ace048b35ba1 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1243,7 +1243,7 @@ plexauth==0.0.6 plexwebsocket==0.0.14 # homeassistant.components.plugwise -plugwise==0.37.3 +plugwise==0.37.4.1 # homeassistant.components.plum_lightpad plumlightpad==0.0.11 From 96adf986255efa53b24743a0be9a13af66740e2d Mon Sep 17 00:00:00 2001 From: Erik Montnemery Date: Wed, 19 Jun 2024 22:45:59 +0200 Subject: [PATCH 16/26] Always create a new HomeAssistant object when falling back to recovery mode (#119969) --- homeassistant/bootstrap.py | 59 ++++++++++++++++++++++++-------------- 1 file changed, 38 insertions(+), 21 deletions(-) diff --git a/homeassistant/bootstrap.py b/homeassistant/bootstrap.py index 74196cdc6256..8435fe73d406 100644 --- a/homeassistant/bootstrap.py +++ b/homeassistant/bootstrap.py @@ -256,22 +256,39 @@ async def async_setup_hass( runtime_config: RuntimeConfig, ) -> core.HomeAssistant | None: """Set up Home Assistant.""" - hass = core.HomeAssistant(runtime_config.config_dir) - async_enable_logging( - hass, - runtime_config.verbose, - runtime_config.log_rotate_days, - runtime_config.log_file, - runtime_config.log_no_color, - ) + def create_hass() -> core.HomeAssistant: + """Create the hass object and do basic setup.""" + hass = core.HomeAssistant(runtime_config.config_dir) + loader.async_setup(hass) - if runtime_config.debug or hass.loop.get_debug(): - hass.config.debug = True + async_enable_logging( + hass, + runtime_config.verbose, + runtime_config.log_rotate_days, + runtime_config.log_file, + runtime_config.log_no_color, + ) + + if runtime_config.debug or hass.loop.get_debug(): + hass.config.debug = True + + hass.config.safe_mode = runtime_config.safe_mode + hass.config.skip_pip = runtime_config.skip_pip + hass.config.skip_pip_packages = runtime_config.skip_pip_packages + + return hass + + async def stop_hass(hass: core.HomeAssistant) -> None: + """Stop hass.""" + # Ask integrations to shut down. It's messy but we can't + # do a clean stop without knowing what is broken + with contextlib.suppress(TimeoutError): + async with hass.timeout.async_timeout(10): + await hass.async_stop() + + hass = create_hass() - hass.config.safe_mode = runtime_config.safe_mode - hass.config.skip_pip = runtime_config.skip_pip - hass.config.skip_pip_packages = runtime_config.skip_pip_packages if runtime_config.skip_pip or runtime_config.skip_pip_packages: _LOGGER.warning( "Skipping pip installation of required modules. This may cause issues" @@ -283,7 +300,6 @@ async def async_setup_hass( _LOGGER.info("Config directory: %s", runtime_config.config_dir) - loader.async_setup(hass) block_async_io.enable() config_dict = None @@ -309,27 +325,28 @@ async def async_setup_hass( if config_dict is None: recovery_mode = True + await stop_hass(hass) + hass = create_hass() elif not basic_setup_success: _LOGGER.warning("Unable to set up core integrations. Activating recovery mode") recovery_mode = True + await stop_hass(hass) + hass = create_hass() elif any(domain not in hass.config.components for domain in CRITICAL_INTEGRATIONS): _LOGGER.warning( "Detected that %s did not load. Activating recovery mode", ",".join(CRITICAL_INTEGRATIONS), ) - # Ask integrations to shut down. It's messy but we can't - # do a clean stop without knowing what is broken - with contextlib.suppress(TimeoutError): - async with hass.timeout.async_timeout(10): - await hass.async_stop() - recovery_mode = True old_config = hass.config old_logging = hass.data.get(DATA_LOGGING) - hass = core.HomeAssistant(old_config.config_dir) + recovery_mode = True + await stop_hass(hass) + hass = create_hass() + if old_logging: hass.data[DATA_LOGGING] = old_logging hass.config.debug = old_config.debug From 5edf480a151da520aaff38195db08700fdb0519a Mon Sep 17 00:00:00 2001 From: Thomas Kistler Date: Fri, 21 Jun 2024 00:07:14 -0700 Subject: [PATCH 17/26] Fix Hydrawise volume unit bug (#119988) --- homeassistant/components/hydrawise/sensor.py | 15 +++++--- tests/components/hydrawise/conftest.py | 7 +++- tests/components/hydrawise/test_sensor.py | 36 ++++++++++++++++++-- 3 files changed, 51 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/hydrawise/sensor.py b/homeassistant/components/hydrawise/sensor.py index 87dc5e73afe1..4b377108b169 100644 --- a/homeassistant/components/hydrawise/sensor.py +++ b/homeassistant/components/hydrawise/sensor.py @@ -71,7 +71,6 @@ FLOW_CONTROLLER_SENSORS: tuple[HydrawiseSensorEntityDescription, ...] = ( key="daily_total_water_use", translation_key="daily_total_water_use", device_class=SensorDeviceClass.VOLUME, - native_unit_of_measurement=UnitOfVolume.GALLONS, suggested_display_precision=1, value_fn=_get_controller_daily_total_water_use, ), @@ -79,7 +78,6 @@ FLOW_CONTROLLER_SENSORS: tuple[HydrawiseSensorEntityDescription, ...] = ( key="daily_active_water_use", translation_key="daily_active_water_use", device_class=SensorDeviceClass.VOLUME, - native_unit_of_measurement=UnitOfVolume.GALLONS, suggested_display_precision=1, value_fn=_get_controller_daily_active_water_use, ), @@ -87,7 +85,6 @@ FLOW_CONTROLLER_SENSORS: tuple[HydrawiseSensorEntityDescription, ...] = ( key="daily_inactive_water_use", translation_key="daily_inactive_water_use", device_class=SensorDeviceClass.VOLUME, - native_unit_of_measurement=UnitOfVolume.GALLONS, suggested_display_precision=1, value_fn=_get_controller_daily_inactive_water_use, ), @@ -98,7 +95,6 @@ FLOW_ZONE_SENSORS: tuple[SensorEntityDescription, ...] = ( key="daily_active_water_use", translation_key="daily_active_water_use", device_class=SensorDeviceClass.VOLUME, - native_unit_of_measurement=UnitOfVolume.GALLONS, suggested_display_precision=1, value_fn=_get_zone_daily_active_water_use, ), @@ -165,6 +161,17 @@ class HydrawiseSensor(HydrawiseEntity, SensorEntity): entity_description: HydrawiseSensorEntityDescription + @property + def native_unit_of_measurement(self) -> str | None: + """Return the unit_of_measurement of the sensor.""" + if self.entity_description.device_class != SensorDeviceClass.VOLUME: + return self.entity_description.native_unit_of_measurement + return ( + UnitOfVolume.GALLONS + if self.coordinator.data.user.units.units_name == "imperial" + else UnitOfVolume.LITERS + ) + @property def icon(self) -> str | None: """Icon of the entity based on the value.""" diff --git a/tests/components/hydrawise/conftest.py b/tests/components/hydrawise/conftest.py index 550e944db36f..e1d0db47ebcf 100644 --- a/tests/components/hydrawise/conftest.py +++ b/tests/components/hydrawise/conftest.py @@ -15,6 +15,7 @@ from pydrawise.schema import ( Sensor, SensorModel, SensorStatus, + UnitsSummary, User, Zone, ) @@ -84,7 +85,11 @@ def mock_auth() -> Generator[AsyncMock, None, None]: @pytest.fixture def user() -> User: """Hydrawise User fixture.""" - return User(customer_id=12345, email="asdf@asdf.com") + return User( + customer_id=12345, + email="asdf@asdf.com", + units=UnitsSummary(units_name="imperial"), + ) @pytest.fixture diff --git a/tests/components/hydrawise/test_sensor.py b/tests/components/hydrawise/test_sensor.py index fcbc47c41f43..af75ad69ade8 100644 --- a/tests/components/hydrawise/test_sensor.py +++ b/tests/components/hydrawise/test_sensor.py @@ -3,13 +3,18 @@ from collections.abc import Awaitable, Callable from unittest.mock import patch -from pydrawise.schema import Controller, Zone +from pydrawise.schema import Controller, User, Zone import pytest from syrupy.assertion import SnapshotAssertion from homeassistant.const import Platform from homeassistant.core import HomeAssistant from homeassistant.helpers import entity_registry as er +from homeassistant.util.unit_system import ( + METRIC_SYSTEM, + US_CUSTOMARY_SYSTEM, + UnitSystem, +) from tests.common import MockConfigEntry, snapshot_platform @@ -45,7 +50,7 @@ async def test_suspended_state( assert next_cycle.state == "unknown" -async def test_no_sensor_and_water_state2( +async def test_no_sensor_and_water_state( hass: HomeAssistant, controller: Controller, mock_add_config_entry: Callable[[], Awaitable[MockConfigEntry]], @@ -63,3 +68,30 @@ async def test_no_sensor_and_water_state2( sensor = hass.states.get("binary_sensor.home_controller_connectivity") assert sensor is not None assert sensor.state == "on" + + +@pytest.mark.parametrize( + ("hydrawise_unit_system", "unit_system", "expected_state"), + [ + ("imperial", METRIC_SYSTEM, "454.6279552584"), + ("imperial", US_CUSTOMARY_SYSTEM, "120.1"), + ("metric", METRIC_SYSTEM, "120.1"), + ("metric", US_CUSTOMARY_SYSTEM, "31.7270634882136"), + ], +) +async def test_volume_unit_conversion( + hass: HomeAssistant, + unit_system: UnitSystem, + hydrawise_unit_system: str, + expected_state: str, + user: User, + mock_add_config_entry: Callable[[], Awaitable[MockConfigEntry]], +) -> None: + """Test volume unit conversion.""" + hass.config.units = unit_system + user.units.units_name = hydrawise_unit_system + await mock_add_config_entry() + + daily_active_water_use = hass.states.get("sensor.zone_one_daily_active_water_use") + assert daily_active_water_use is not None + assert daily_active_water_use.state == expected_state From 5b322f1af530b55b1e625f27fb07cc18a7824a56 Mon Sep 17 00:00:00 2001 From: BestPig Date: Thu, 20 Jun 2024 13:06:30 +0200 Subject: [PATCH 18/26] Fix songpal crash for soundbars without sound modes (#119999) Getting soundField on soundbar that doesn't support it crash raise an exception, so it make the whole components unavailable. As there is no simple way to know if soundField is supported, I just get all sound settings, and then pick soundField one if present. If not present, then return None to make it continue, it will just have to effect to display no sound mode and not able to select one (Exactly what we want). --- .../components/songpal/media_player.py | 7 +++- tests/components/songpal/__init__.py | 13 ++++++- tests/components/songpal/test_media_player.py | 37 +++++++++++++++++++ 3 files changed, 54 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/songpal/media_player.py b/homeassistant/components/songpal/media_player.py index c6d6524cefb3..9f828591a08a 100644 --- a/homeassistant/components/songpal/media_player.py +++ b/homeassistant/components/songpal/media_player.py @@ -140,7 +140,12 @@ class SongpalEntity(MediaPlayerEntity): async def _get_sound_modes_info(self): """Get available sound modes and the active one.""" - settings = await self._dev.get_sound_settings("soundField") + for settings in await self._dev.get_sound_settings(): + if settings.target == "soundField": + break + else: + return None, {} + if isinstance(settings, Setting): settings = [settings] diff --git a/tests/components/songpal/__init__.py b/tests/components/songpal/__init__.py index ab585c5a6d51..15bf0c530d3d 100644 --- a/tests/components/songpal/__init__.py +++ b/tests/components/songpal/__init__.py @@ -23,7 +23,9 @@ CONF_DATA = { } -def _create_mocked_device(throw_exception=False, wired_mac=MAC, wireless_mac=None): +def _create_mocked_device( + throw_exception=False, wired_mac=MAC, wireless_mac=None, no_soundfield=False +): mocked_device = MagicMock() type(mocked_device).get_supported_methods = AsyncMock( @@ -101,7 +103,14 @@ def _create_mocked_device(throw_exception=False, wired_mac=MAC, wireless_mac=Non soundField = MagicMock() soundField.currentValue = "sound_mode2" soundField.candidate = [sound_mode1, sound_mode2, sound_mode3] - type(mocked_device).get_sound_settings = AsyncMock(return_value=[soundField]) + + settings = MagicMock() + settings.target = "soundField" + settings.__iter__.return_value = [soundField] + + type(mocked_device).get_sound_settings = AsyncMock( + return_value=[] if no_soundfield else [settings] + ) type(mocked_device).set_power = AsyncMock() type(mocked_device).set_sound_settings = AsyncMock() diff --git a/tests/components/songpal/test_media_player.py b/tests/components/songpal/test_media_player.py index 2393a5a90863..8f56170b8398 100644 --- a/tests/components/songpal/test_media_player.py +++ b/tests/components/songpal/test_media_player.py @@ -159,6 +159,43 @@ async def test_state( assert entity.unique_id == MAC +async def test_state_nosoundmode( + hass: HomeAssistant, + device_registry: dr.DeviceRegistry, + entity_registry: er.EntityRegistry, +) -> None: + """Test state of the entity with no soundField in sound settings.""" + mocked_device = _create_mocked_device(no_soundfield=True) + entry = MockConfigEntry(domain=songpal.DOMAIN, data=CONF_DATA) + entry.add_to_hass(hass) + + with _patch_media_player_device(mocked_device): + await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + state = hass.states.get(ENTITY_ID) + assert state.name == FRIENDLY_NAME + assert state.state == STATE_ON + attributes = state.as_dict()["attributes"] + assert attributes["volume_level"] == 0.5 + assert attributes["is_volume_muted"] is False + assert attributes["source_list"] == ["title1", "title2"] + assert attributes["source"] == "title2" + assert "sound_mode_list" not in attributes + assert "sound_mode" not in attributes + assert attributes["supported_features"] == SUPPORT_SONGPAL + + device = device_registry.async_get_device(identifiers={(songpal.DOMAIN, MAC)}) + assert device.connections == {(dr.CONNECTION_NETWORK_MAC, MAC)} + assert device.manufacturer == "Sony Corporation" + assert device.name == FRIENDLY_NAME + assert device.sw_version == SW_VERSION + assert device.model == MODEL + + entity = entity_registry.async_get(ENTITY_ID) + assert entity.unique_id == MAC + + async def test_state_wireless( hass: HomeAssistant, device_registry: dr.DeviceRegistry, From 39f67afa64621e9a783212ba3d15a11e0efe24da Mon Sep 17 00:00:00 2001 From: Robert Svensson Date: Fri, 21 Jun 2024 10:36:52 +0200 Subject: [PATCH 19/26] Make UniFi services handle unloaded config entry (#120028) --- homeassistant/components/unifi/services.py | 15 +++++--- tests/components/unifi/test_services.py | 41 ++++++++++++++++++++++ 2 files changed, 51 insertions(+), 5 deletions(-) diff --git a/homeassistant/components/unifi/services.py b/homeassistant/components/unifi/services.py index 5dcc0e9719c9..ce726a0f5d02 100644 --- a/homeassistant/components/unifi/services.py +++ b/homeassistant/components/unifi/services.py @@ -6,6 +6,7 @@ from typing import Any from aiounifi.models.client import ClientReconnectRequest, ClientRemoveRequest import voluptuous as vol +from homeassistant.config_entries import ConfigEntryState from homeassistant.const import ATTR_DEVICE_ID from homeassistant.core import HomeAssistant, ServiceCall, callback from homeassistant.helpers import device_registry as dr @@ -66,9 +67,9 @@ async def async_reconnect_client(hass: HomeAssistant, data: Mapping[str, Any]) - if mac == "": return - for entry in hass.config_entries.async_entries(UNIFI_DOMAIN): - if ( - (hub := entry.runtime_data) + for config_entry in hass.config_entries.async_entries(UNIFI_DOMAIN): + if config_entry.state is not ConfigEntryState.LOADED or ( + (hub := config_entry.runtime_data) and not hub.available or (client := hub.api.clients.get(mac)) is None or client.is_wired @@ -85,8 +86,12 @@ async def async_remove_clients(hass: HomeAssistant, data: Mapping[str, Any]) -> - Total time between first seen and last seen is less than 15 minutes. - Neither IP, hostname nor name is configured. """ - for entry in hass.config_entries.async_entries(UNIFI_DOMAIN): - if (hub := entry.runtime_data) and not hub.available: + for config_entry in hass.config_entries.async_entries(UNIFI_DOMAIN): + if ( + config_entry.state is not ConfigEntryState.LOADED + or (hub := config_entry.runtime_data) + and not hub.available + ): continue clients_to_remove = [] diff --git a/tests/components/unifi/test_services.py b/tests/components/unifi/test_services.py index 8cd029b1cf5c..c4ccdc8b902d 100644 --- a/tests/components/unifi/test_services.py +++ b/tests/components/unifi/test_services.py @@ -281,3 +281,44 @@ async def test_remove_clients_no_call_on_empty_list( await hass.services.async_call(UNIFI_DOMAIN, SERVICE_REMOVE_CLIENTS, blocking=True) assert aioclient_mock.call_count == 0 + + +@pytest.mark.parametrize( + "clients_all_payload", + [ + [ + { + "first_seen": 100, + "last_seen": 500, + "mac": "00:00:00:00:00:01", + } + ] + ], +) +async def test_services_handle_unloaded_config_entry( + hass: HomeAssistant, + aioclient_mock: AiohttpClientMocker, + device_registry: dr.DeviceRegistry, + config_entry_setup: ConfigEntry, + clients_all_payload, +) -> None: + """Verify no call is made if config entry is unloaded.""" + await hass.config_entries.async_unload(config_entry_setup.entry_id) + await hass.async_block_till_done() + + aioclient_mock.clear_requests() + + await hass.services.async_call(UNIFI_DOMAIN, SERVICE_REMOVE_CLIENTS, blocking=True) + assert aioclient_mock.call_count == 0 + + device_entry = device_registry.async_get_or_create( + config_entry_id=config_entry_setup.entry_id, + connections={(dr.CONNECTION_NETWORK_MAC, clients_all_payload[0]["mac"])}, + ) + await hass.services.async_call( + UNIFI_DOMAIN, + SERVICE_RECONNECT_CLIENT, + service_data={ATTR_DEVICE_ID: device_entry.id}, + blocking=True, + ) + assert aioclient_mock.call_count == 0 From 75a469f4d6862b1b575d24817e01d236da8bb440 Mon Sep 17 00:00:00 2001 From: Glenn Waters Date: Fri, 21 Jun 2024 04:37:51 -0400 Subject: [PATCH 20/26] Bump env-canada to 0.6.3 (#120035) Co-authored-by: J. Nick Koston --- homeassistant/components/environment_canada/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/environment_canada/manifest.json b/homeassistant/components/environment_canada/manifest.json index f29c8177dfd3..a0bdd5d49191 100644 --- a/homeassistant/components/environment_canada/manifest.json +++ b/homeassistant/components/environment_canada/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/environment_canada", "iot_class": "cloud_polling", "loggers": ["env_canada"], - "requirements": ["env-canada==0.6.2"] + "requirements": ["env-canada==0.6.3"] } diff --git a/requirements_all.txt b/requirements_all.txt index 0a97310fdd5e..7b5d02fb9c48 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -810,7 +810,7 @@ enocean==0.50 enturclient==0.2.4 # homeassistant.components.environment_canada -env-canada==0.6.2 +env-canada==0.6.3 # homeassistant.components.season ephem==4.1.5 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index ace048b35ba1..1f37062bfaa9 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -664,7 +664,7 @@ energyzero==2.1.0 enocean==0.50 # homeassistant.components.environment_canada -env-canada==0.6.2 +env-canada==0.6.3 # homeassistant.components.season ephem==4.1.5 From 59b2f4e56fd3b9f5bfa7e69b669a05a3522cc11b Mon Sep 17 00:00:00 2001 From: Jan Bouwhuis Date: Fri, 21 Jun 2024 08:47:50 +0200 Subject: [PATCH 21/26] Bump aioimaplib to 1.1.0 (#120045) --- homeassistant/components/imap/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/imap/manifest.json b/homeassistant/components/imap/manifest.json index 3c35d00f7146..b058a3d50f4a 100644 --- a/homeassistant/components/imap/manifest.json +++ b/homeassistant/components/imap/manifest.json @@ -7,5 +7,5 @@ "documentation": "https://www.home-assistant.io/integrations/imap", "iot_class": "cloud_push", "loggers": ["aioimaplib"], - "requirements": ["aioimaplib==1.0.1"] + "requirements": ["aioimaplib==1.1.0"] } diff --git a/requirements_all.txt b/requirements_all.txt index 7b5d02fb9c48..66dd81ff9afd 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -261,7 +261,7 @@ aiohomekit==3.1.5 aiohue==4.7.1 # homeassistant.components.imap -aioimaplib==1.0.1 +aioimaplib==1.1.0 # homeassistant.components.apache_kafka aiokafka==0.10.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 1f37062bfaa9..15cbe079531e 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -237,7 +237,7 @@ aiohomekit==3.1.5 aiohue==4.7.1 # homeassistant.components.imap -aioimaplib==1.0.1 +aioimaplib==1.1.0 # homeassistant.components.apache_kafka aiokafka==0.10.0 From 53a21dcb6b6c3c7c266c9906725094a099147c67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= Date: Fri, 21 Jun 2024 10:34:39 +0200 Subject: [PATCH 22/26] Update AEMET-OpenData to v0.5.2 (#120065) --- homeassistant/components/aemet/manifest.json | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/homeassistant/components/aemet/manifest.json b/homeassistant/components/aemet/manifest.json index b8a19bcd27af..8a22385f82bb 100644 --- a/homeassistant/components/aemet/manifest.json +++ b/homeassistant/components/aemet/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/aemet", "iot_class": "cloud_polling", "loggers": ["aemet_opendata"], - "requirements": ["AEMET-OpenData==0.5.1"] + "requirements": ["AEMET-OpenData==0.5.2"] } diff --git a/requirements_all.txt b/requirements_all.txt index 66dd81ff9afd..0a63d43b593a 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -4,7 +4,7 @@ -r requirements.txt # homeassistant.components.aemet -AEMET-OpenData==0.5.1 +AEMET-OpenData==0.5.2 # homeassistant.components.honeywell AIOSomecomfort==0.0.25 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 15cbe079531e..02d2f23d61a7 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -4,7 +4,7 @@ -r requirements_test.txt # homeassistant.components.aemet -AEMET-OpenData==0.5.1 +AEMET-OpenData==0.5.2 # homeassistant.components.honeywell AIOSomecomfort==0.0.25 From 92c12fdf0ac0f87acf10800ffb7ed8c6358e1d78 Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Fri, 21 Jun 2024 11:19:52 -0500 Subject: [PATCH 23/26] Bump intents to 2024.6.21 (#120106) --- homeassistant/components/conversation/manifest.json | 2 +- homeassistant/package_constraints.txt | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- .../components/conversation/snapshots/test_init.ambr | 12 ++++++------ 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/homeassistant/components/conversation/manifest.json b/homeassistant/components/conversation/manifest.json index a3af6607abac..ee0b29f22fcf 100644 --- a/homeassistant/components/conversation/manifest.json +++ b/homeassistant/components/conversation/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/conversation", "integration_type": "system", "quality_scale": "internal", - "requirements": ["hassil==1.7.1", "home-assistant-intents==2024.6.5"] + "requirements": ["hassil==1.7.1", "home-assistant-intents==2024.6.21"] } diff --git a/homeassistant/package_constraints.txt b/homeassistant/package_constraints.txt index 8a64a42cc9dc..5a64438116fe 100644 --- a/homeassistant/package_constraints.txt +++ b/homeassistant/package_constraints.txt @@ -33,7 +33,7 @@ hass-nabucasa==0.81.1 hassil==1.7.1 home-assistant-bluetooth==1.12.0 home-assistant-frontend==20240610.1 -home-assistant-intents==2024.6.5 +home-assistant-intents==2024.6.21 httpx==0.27.0 ifaddr==0.2.0 Jinja2==3.1.4 diff --git a/requirements_all.txt b/requirements_all.txt index 0a63d43b593a..4ee7c3518b16 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1090,7 +1090,7 @@ holidays==0.51 home-assistant-frontend==20240610.1 # homeassistant.components.conversation -home-assistant-intents==2024.6.5 +home-assistant-intents==2024.6.21 # homeassistant.components.home_connect homeconnect==0.7.2 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 02d2f23d61a7..495aec2eec04 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -892,7 +892,7 @@ holidays==0.51 home-assistant-frontend==20240610.1 # homeassistant.components.conversation -home-assistant-intents==2024.6.5 +home-assistant-intents==2024.6.21 # homeassistant.components.home_connect homeconnect==0.7.2 diff --git a/tests/components/conversation/snapshots/test_init.ambr b/tests/components/conversation/snapshots/test_init.ambr index 6264e61863f3..403c72aaa106 100644 --- a/tests/components/conversation/snapshots/test_init.ambr +++ b/tests/components/conversation/snapshots/test_init.ambr @@ -563,7 +563,7 @@ 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'Sorry, I am not aware of any device called kitchen light', + 'speech': 'Sorry, I am not aware of any device called kitchen', }), }), }), @@ -703,7 +703,7 @@ 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'Sorry, I am not aware of any device called late added light', + 'speech': 'Sorry, I am not aware of any device called late added', }), }), }), @@ -783,7 +783,7 @@ 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'Sorry, I am not aware of any device called kitchen light', + 'speech': 'Sorry, I am not aware of any device called kitchen', }), }), }), @@ -803,7 +803,7 @@ 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'Sorry, I am not aware of any device called my cool light', + 'speech': 'Sorry, I am not aware of any device called my cool', }), }), }), @@ -943,7 +943,7 @@ 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'Sorry, I am not aware of any device called kitchen light', + 'speech': 'Sorry, I am not aware of any device called kitchen', }), }), }), @@ -993,7 +993,7 @@ 'speech': dict({ 'plain': dict({ 'extra_data': None, - 'speech': 'Sorry, I am not aware of any device called renamed light', + 'speech': 'Sorry, I am not aware of any device called renamed', }), }), }), From c1dc6fd51155d71b3fe4f04def01066b5ba98e3f Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Fri, 21 Jun 2024 18:42:30 +0200 Subject: [PATCH 24/26] Bump version to 2024.6.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 cd340cd50798..25c5df8a1363 100644 --- a/homeassistant/const.py +++ b/homeassistant/const.py @@ -24,7 +24,7 @@ if TYPE_CHECKING: APPLICATION_NAME: Final = "HomeAssistant" MAJOR_VERSION: Final = 2024 MINOR_VERSION: Final = 6 -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 a03f3533a808..4c11317242e4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "homeassistant" -version = "2024.6.3" +version = "2024.6.4" license = {text = "Apache-2.0"} description = "Open-source home automation platform running on Python 3." readme = "README.rst" From e62268d5eac922597eb19e6fb4408172c8db7803 Mon Sep 17 00:00:00 2001 From: Franck Nijhof Date: Fri, 21 Jun 2024 19:59:25 +0200 Subject: [PATCH 25/26] Revert "Make UniFi services handle unloaded config entry (#120028)" This reverts commit 39f67afa64621e9a783212ba3d15a11e0efe24da. --- homeassistant/components/unifi/services.py | 15 +++----- tests/components/unifi/test_services.py | 41 ---------------------- 2 files changed, 5 insertions(+), 51 deletions(-) diff --git a/homeassistant/components/unifi/services.py b/homeassistant/components/unifi/services.py index ce726a0f5d02..5dcc0e9719c9 100644 --- a/homeassistant/components/unifi/services.py +++ b/homeassistant/components/unifi/services.py @@ -6,7 +6,6 @@ from typing import Any from aiounifi.models.client import ClientReconnectRequest, ClientRemoveRequest import voluptuous as vol -from homeassistant.config_entries import ConfigEntryState from homeassistant.const import ATTR_DEVICE_ID from homeassistant.core import HomeAssistant, ServiceCall, callback from homeassistant.helpers import device_registry as dr @@ -67,9 +66,9 @@ async def async_reconnect_client(hass: HomeAssistant, data: Mapping[str, Any]) - if mac == "": return - for config_entry in hass.config_entries.async_entries(UNIFI_DOMAIN): - if config_entry.state is not ConfigEntryState.LOADED or ( - (hub := config_entry.runtime_data) + for entry in hass.config_entries.async_entries(UNIFI_DOMAIN): + if ( + (hub := entry.runtime_data) and not hub.available or (client := hub.api.clients.get(mac)) is None or client.is_wired @@ -86,12 +85,8 @@ async def async_remove_clients(hass: HomeAssistant, data: Mapping[str, Any]) -> - Total time between first seen and last seen is less than 15 minutes. - Neither IP, hostname nor name is configured. """ - for config_entry in hass.config_entries.async_entries(UNIFI_DOMAIN): - if ( - config_entry.state is not ConfigEntryState.LOADED - or (hub := config_entry.runtime_data) - and not hub.available - ): + for entry in hass.config_entries.async_entries(UNIFI_DOMAIN): + if (hub := entry.runtime_data) and not hub.available: continue clients_to_remove = [] diff --git a/tests/components/unifi/test_services.py b/tests/components/unifi/test_services.py index c4ccdc8b902d..8cd029b1cf5c 100644 --- a/tests/components/unifi/test_services.py +++ b/tests/components/unifi/test_services.py @@ -281,44 +281,3 @@ async def test_remove_clients_no_call_on_empty_list( await hass.services.async_call(UNIFI_DOMAIN, SERVICE_REMOVE_CLIENTS, blocking=True) assert aioclient_mock.call_count == 0 - - -@pytest.mark.parametrize( - "clients_all_payload", - [ - [ - { - "first_seen": 100, - "last_seen": 500, - "mac": "00:00:00:00:00:01", - } - ] - ], -) -async def test_services_handle_unloaded_config_entry( - hass: HomeAssistant, - aioclient_mock: AiohttpClientMocker, - device_registry: dr.DeviceRegistry, - config_entry_setup: ConfigEntry, - clients_all_payload, -) -> None: - """Verify no call is made if config entry is unloaded.""" - await hass.config_entries.async_unload(config_entry_setup.entry_id) - await hass.async_block_till_done() - - aioclient_mock.clear_requests() - - await hass.services.async_call(UNIFI_DOMAIN, SERVICE_REMOVE_CLIENTS, blocking=True) - assert aioclient_mock.call_count == 0 - - device_entry = device_registry.async_get_or_create( - config_entry_id=config_entry_setup.entry_id, - connections={(dr.CONNECTION_NETWORK_MAC, clients_all_payload[0]["mac"])}, - ) - await hass.services.async_call( - UNIFI_DOMAIN, - SERVICE_RECONNECT_CLIENT, - service_data={ATTR_DEVICE_ID: device_entry.id}, - blocking=True, - ) - assert aioclient_mock.call_count == 0 From febcb335457526bce4b1115d31a551842140c92a Mon Sep 17 00:00:00 2001 From: Thomas Kistler Date: Tue, 18 Jun 2024 01:26:31 -0700 Subject: [PATCH 26/26] Update pydrawise to 2024.6.4 (#119868) --- homeassistant/components/hydrawise/manifest.json | 2 +- homeassistant/components/hydrawise/sensor.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/homeassistant/components/hydrawise/manifest.json b/homeassistant/components/hydrawise/manifest.json index dc6408407e78..b85ddca042ec 100644 --- a/homeassistant/components/hydrawise/manifest.json +++ b/homeassistant/components/hydrawise/manifest.json @@ -6,5 +6,5 @@ "documentation": "https://www.home-assistant.io/integrations/hydrawise", "iot_class": "cloud_polling", "loggers": ["pydrawise"], - "requirements": ["pydrawise==2024.6.3"] + "requirements": ["pydrawise==2024.6.4"] } diff --git a/homeassistant/components/hydrawise/sensor.py b/homeassistant/components/hydrawise/sensor.py index 4b377108b169..fe4b33d58514 100644 --- a/homeassistant/components/hydrawise/sensor.py +++ b/homeassistant/components/hydrawise/sensor.py @@ -48,7 +48,7 @@ def _get_zone_daily_active_water_use(sensor: HydrawiseSensor) -> float: return float(daily_water_summary.active_use_by_zone_id.get(sensor.zone.id, 0.0)) -def _get_controller_daily_active_water_use(sensor: HydrawiseSensor) -> float: +def _get_controller_daily_active_water_use(sensor: HydrawiseSensor) -> float | None: """Get active water use for the controller.""" daily_water_summary = sensor.coordinator.data.daily_water_use[sensor.controller.id] return daily_water_summary.total_active_use diff --git a/requirements_all.txt b/requirements_all.txt index 4ee7c3518b16..1ccf5efbdc98 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -1794,7 +1794,7 @@ pydiscovergy==3.0.1 pydoods==1.0.2 # homeassistant.components.hydrawise -pydrawise==2024.6.3 +pydrawise==2024.6.4 # homeassistant.components.android_ip_webcam pydroid-ipcam==2.0.0 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 495aec2eec04..328f660547f5 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -1405,7 +1405,7 @@ pydexcom==0.2.3 pydiscovergy==3.0.1 # homeassistant.components.hydrawise -pydrawise==2024.6.3 +pydrawise==2024.6.4 # homeassistant.components.android_ip_webcam pydroid-ipcam==2.0.0