diff --git a/homeassistant/components/accuweather/manifest.json b/homeassistant/components/accuweather/manifest.json index 07faa0cf26a1f2..79c3baeccbfb23 100644 --- a/homeassistant/components/accuweather/manifest.json +++ b/homeassistant/components/accuweather/manifest.json @@ -7,5 +7,5 @@ "integration_type": "service", "iot_class": "cloud_polling", "loggers": ["accuweather"], - "requirements": ["accuweather==5.0.0"] + "requirements": ["accuweather==5.1.0"] } diff --git a/homeassistant/components/accuweather/system_health.py b/homeassistant/components/accuweather/system_health.py index f5efaf3079fdae..99335a9dd8f9cd 100644 --- a/homeassistant/components/accuweather/system_health.py +++ b/homeassistant/components/accuweather/system_health.py @@ -30,6 +30,8 @@ async def system_health_info(hass: HomeAssistant) -> dict[str, Any]: ) return { - "can_reach_server": system_health.async_check_can_reach_url(hass, ENDPOINT), + "can_reach_server": system_health.async_check_can_reach_url( + hass, str(ENDPOINT) + ), "remaining_requests": remaining_requests, } diff --git a/homeassistant/components/aladdin_connect/diagnostics.py b/homeassistant/components/aladdin_connect/diagnostics.py new file mode 100644 index 00000000000000..804a401daf1ce7 --- /dev/null +++ b/homeassistant/components/aladdin_connect/diagnostics.py @@ -0,0 +1,32 @@ +"""Diagnostics support for Aladdin Connect.""" + +from __future__ import annotations + +from typing import Any + +from homeassistant.components.diagnostics import async_redact_data +from homeassistant.core import HomeAssistant + +from .coordinator import AladdinConnectConfigEntry + +TO_REDACT = {"access_token", "refresh_token"} + + +async def async_get_config_entry_diagnostics( + hass: HomeAssistant, config_entry: AladdinConnectConfigEntry +) -> dict[str, Any]: + """Return diagnostics for a config entry.""" + return { + "config_entry": async_redact_data(config_entry.as_dict(), TO_REDACT), + "doors": { + uid: { + "device_id": coordinator.data.device_id, + "door_number": coordinator.data.door_number, + "name": coordinator.data.name, + "status": coordinator.data.status, + "link_status": coordinator.data.link_status, + "battery_level": coordinator.data.battery_level, + } + for uid, coordinator in config_entry.runtime_data.items() + }, + } diff --git a/homeassistant/components/aladdin_connect/quality_scale.yaml b/homeassistant/components/aladdin_connect/quality_scale.yaml index 807950b31017d6..dc280b1eb00c6d 100644 --- a/homeassistant/components/aladdin_connect/quality_scale.yaml +++ b/homeassistant/components/aladdin_connect/quality_scale.yaml @@ -45,7 +45,7 @@ rules: # Gold devices: done - diagnostics: todo + diagnostics: done discovery: done discovery-update-info: status: exempt diff --git a/homeassistant/components/matter/vacuum.py b/homeassistant/components/matter/vacuum.py index 6bb0f3f0221885..2c478a5a8d2742 100644 --- a/homeassistant/components/matter/vacuum.py +++ b/homeassistant/components/matter/vacuum.py @@ -206,10 +206,11 @@ async def async_clean_segments(self, segment_ids: list[str], **kwargs: Any) -> N if ( response - and response.status != clusters.ServiceArea.Enums.SelectAreasStatus.kSuccess + and response["status"] + != clusters.ServiceArea.Enums.SelectAreasStatus.kSuccess ): raise HomeAssistantError( - f"Failed to select areas: {response.statusText or response.status.name}" + f"Failed to select areas: {response['statusText'] or response['status']}" ) await self.send_device_command( diff --git a/homeassistant/components/sonarr/__init__.py b/homeassistant/components/sonarr/__init__.py index ef1022da47e357..6d561dd9f22960 100644 --- a/homeassistant/components/sonarr/__init__.py +++ b/homeassistant/components/sonarr/__init__.py @@ -2,6 +2,8 @@ from __future__ import annotations +from dataclasses import fields + from aiopyarr.models.host_configuration import PyArrHostConfiguration from aiopyarr.sonarr_client import SonarrClient @@ -37,7 +39,6 @@ SeriesDataUpdateCoordinator, SonarrConfigEntry, SonarrData, - SonarrDataUpdateCoordinator, StatusDataUpdateCoordinator, WantedDataUpdateCoordinator, ) @@ -89,16 +90,8 @@ async def async_setup_entry(hass: HomeAssistant, entry: SonarrConfigEntry) -> bo ) # Temporary, until we add diagnostic entities _version = None - coordinators: list[SonarrDataUpdateCoordinator] = [ - data.upcoming, - data.commands, - data.diskspace, - data.queue, - data.series, - data.status, - data.wanted, - ] - for coordinator in coordinators: + for field in fields(data): + coordinator = getattr(data, field.name) await coordinator.async_config_entry_first_refresh() if isinstance(coordinator, StatusDataUpdateCoordinator): _version = coordinator.data.version diff --git a/homeassistant/components/sonarr/helpers.py b/homeassistant/components/sonarr/helpers.py index ee4e81bb78128d..522009785b1783 100644 --- a/homeassistant/components/sonarr/helpers.py +++ b/homeassistant/components/sonarr/helpers.py @@ -128,35 +128,6 @@ def format_queue( return shows -def format_episode_item( - series: SonarrSeries, episode_data: dict[str, Any], base_url: str | None = None -) -> dict[str, Any]: - """Format a single episode item.""" - result: dict[str, Any] = { - "id": episode_data.get("id"), - "episode_number": episode_data.get("episodeNumber"), - "season_number": episode_data.get("seasonNumber"), - "title": episode_data.get("title"), - "air_date": str(episode_data.get("airDate", "")), - "overview": episode_data.get("overview"), - "has_file": episode_data.get("hasFile", False), - "monitored": episode_data.get("monitored", False), - } - - # Add episode images if available - if images := episode_data.get("images"): - result["images"] = {} - for image in images: - cover_type = image.coverType - # Prefer remoteUrl (public TVDB URL) over local path - if remote_url := getattr(image, "remoteUrl", None): - result["images"][cover_type] = remote_url - elif base_url and (url := getattr(image, "url", None)): - result["images"][cover_type] = f"{base_url.rstrip('/')}{url}" - - return result - - def format_series( series_list: list[SonarrSeries], base_url: str | None = None ) -> dict[str, dict[str, Any]]: diff --git a/homeassistant/components/sonarr/services.py b/homeassistant/components/sonarr/services.py index 0bc7e3937be50b..acd0bd11e479ec 100644 --- a/homeassistant/components/sonarr/services.py +++ b/homeassistant/components/sonarr/services.py @@ -46,7 +46,7 @@ CONF_SPACE_UNIT = "space_unit" # Valid space units -SPACE_UNITS = ["bytes", "kb", "kib", "mb", "mib", "gb", "gib", "tb", "tib", "pb", "pib"] +SPACE_UNITS = ["bytes", "KB", "KiB", "MB", "MiB", "GB", "GiB", "TB", "TiB", "PB", "PiB"] DEFAULT_SPACE_UNIT = "bytes" # Default values - 0 means no limit diff --git a/homeassistant/components/sonarr/strings.json b/homeassistant/components/sonarr/strings.json index 8538f8bd7c2335..0316e034d708ea 100644 --- a/homeassistant/components/sonarr/strings.json +++ b/homeassistant/components/sonarr/strings.json @@ -78,7 +78,7 @@ "name": "Sonarr entry" }, "space_unit": { - "description": "Unit for space values. Use binary units (kib, mib, gib, tib, pib) for 1024-based values or decimal units (kb, mb, gb, tb, pb) for 1000-based values.", + "description": "Unit for space values. Use binary units (KiB, MiB, GiB, TiB, PiB) for 1024-based values or decimal units (KB, MB, GB, TB, PB) for 1000-based values. The default is bytes.", "name": "Space unit" } }, diff --git a/requirements_all.txt b/requirements_all.txt index 0d6d6f189f3980..eb335296c0f02e 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -130,7 +130,7 @@ TwitterAPI==2.7.12 WSDiscovery==2.1.2 # homeassistant.components.accuweather -accuweather==5.0.0 +accuweather==5.1.0 # homeassistant.components.actron_air actron-neo-api==0.4.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 6e9844ae516b9c..436e0c9a003ff0 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -121,7 +121,7 @@ Tami4EdgeAPI==3.0 WSDiscovery==2.1.2 # homeassistant.components.accuweather -accuweather==5.0.0 +accuweather==5.1.0 # homeassistant.components.actron_air actron-neo-api==0.4.1 diff --git a/tests/components/aladdin_connect/snapshots/test_diagnostics.ambr b/tests/components/aladdin_connect/snapshots/test_diagnostics.ambr new file mode 100644 index 00000000000000..b13a1b54488c13 --- /dev/null +++ b/tests/components/aladdin_connect/snapshots/test_diagnostics.ambr @@ -0,0 +1,40 @@ +# serializer version: 1 +# name: test_diagnostics + dict({ + 'config_entry': dict({ + 'data': dict({ + 'auth_implementation': 'aladdin_connect', + 'token': dict({ + 'access_token': '**REDACTED**', + 'expires_in': 3600, + 'refresh_token': '**REDACTED**', + }), + }), + 'disabled_by': None, + 'discovery_keys': dict({ + }), + 'domain': 'aladdin_connect', + 'minor_version': 1, + 'options': dict({ + }), + 'pref_disable_new_entities': False, + 'pref_disable_polling': False, + 'source': 'user', + 'subentries': list([ + ]), + 'title': 'Aladdin Connect', + 'unique_id': 'test_user_123', + 'version': 2, + }), + 'doors': dict({ + 'test_device_id-1': dict({ + 'battery_level': 100, + 'device_id': 'test_device_id', + 'door_number': 1, + 'link_status': 'connected', + 'name': 'Test Door', + 'status': 'closed', + }), + }), + }) +# --- diff --git a/tests/components/aladdin_connect/test_diagnostics.py b/tests/components/aladdin_connect/test_diagnostics.py new file mode 100644 index 00000000000000..406e5c17227c42 --- /dev/null +++ b/tests/components/aladdin_connect/test_diagnostics.py @@ -0,0 +1,28 @@ +"""Tests for the Aladdin Connect diagnostics.""" + +from syrupy.assertion import SnapshotAssertion +from syrupy.filters import props + +from homeassistant.core import HomeAssistant + +from . import init_integration + +from tests.common import MockConfigEntry +from tests.components.diagnostics import get_diagnostics_for_config_entry +from tests.typing import ClientSessionGenerator + + +async def test_diagnostics( + hass: HomeAssistant, + hass_client: ClientSessionGenerator, + mock_config_entry: MockConfigEntry, + snapshot: SnapshotAssertion, +) -> None: + """Test diagnostics.""" + await init_integration(hass, mock_config_entry) + result = await get_diagnostics_for_config_entry( + hass, hass_client, mock_config_entry + ) + assert result == snapshot( + exclude=props("created_at", "modified_at", "entry_id", "expires_at") + ) diff --git a/tests/components/matter/test_vacuum.py b/tests/components/matter/test_vacuum.py index b4434cfc651aea..4c866d6973bcf8 100644 --- a/tests/components/matter/test_vacuum.py +++ b/tests/components/matter/test_vacuum.py @@ -365,12 +365,11 @@ async def test_vacuum_clean_area( }, ) - # Mock a successful SelectAreasResponse - matter_client.send_device_command.return_value = ( - clusters.ServiceArea.Commands.SelectAreasResponse( - status=clusters.ServiceArea.Enums.SelectAreasStatus.kSuccess, - ) - ) + # Mock a successful SelectAreasResponse (returns as dict over websocket) + matter_client.send_device_command.return_value = { + "status": clusters.ServiceArea.Enums.SelectAreasStatus.kSuccess, + "statusText": "", + } await hass.services.async_call( VACUUM_DOMAIN, @@ -420,13 +419,11 @@ async def test_vacuum_clean_area_select_areas_failure( }, ) - # Mock a failed SelectAreasResponse - matter_client.send_device_command.return_value = ( - clusters.ServiceArea.Commands.SelectAreasResponse( - status=clusters.ServiceArea.Enums.SelectAreasStatus.kUnsupportedArea, - statusText="Area 7 not supported", - ) - ) + # Mock a failed SelectAreasResponse (returns as dict over websocket) + matter_client.send_device_command.return_value = { + "status": clusters.ServiceArea.Enums.SelectAreasStatus.kUnsupportedArea, + "statusText": "Area 7 not supported", + } with pytest.raises(HomeAssistantError, match="Failed to select areas"): await hass.services.async_call(