From 8c509b11b2b234c5c42df24df229d209ef045540 Mon Sep 17 00:00:00 2001 From: karwosts <32912880+karwosts@users.noreply.github.com> Date: Tue, 5 Aug 2025 09:56:34 -0700 Subject: [PATCH 1/5] Fix template sensor uom string (#150057) --- homeassistant/components/template/strings.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/homeassistant/components/template/strings.json b/homeassistant/components/template/strings.json index 96c8435c25cd24..200b323d377a12 100644 --- a/homeassistant/components/template/strings.json +++ b/homeassistant/components/template/strings.json @@ -759,7 +759,7 @@ "data_description": { "device_id": "[%key:component::template::common::device_id_description%]", "state": "[%key:component::template::config::step::sensor::data_description::state%]", - "unit_of_measurement": "[%key:component::template::config::step::sensor::data_description::state%]" + "unit_of_measurement": "[%key:component::template::config::step::sensor::data_description::unit_of_measurement%]" }, "sections": { "advanced_options": { From 12dca4b1bfbd49eada906e424e970f2f2749ae47 Mon Sep 17 00:00:00 2001 From: starkillerOG Date: Tue, 5 Aug 2025 18:58:22 +0200 Subject: [PATCH 2/5] Bump reolink-aio to 0.14.6 (#150055) --- homeassistant/components/reolink/diagnostics.py | 4 ++-- homeassistant/components/reolink/manifest.json | 2 +- homeassistant/components/reolink/sensor.py | 2 +- requirements_all.txt | 2 +- requirements_test_all.txt | 2 +- tests/components/reolink/conftest.py | 2 +- tests/components/reolink/snapshots/test_diagnostics.ambr | 2 +- tests/components/reolink/test_diagnostics.py | 2 ++ tests/components/reolink/test_sensor.py | 2 +- 9 files changed, 11 insertions(+), 9 deletions(-) diff --git a/homeassistant/components/reolink/diagnostics.py b/homeassistant/components/reolink/diagnostics.py index 48f6b709c233d7..912427fa88193c 100644 --- a/homeassistant/components/reolink/diagnostics.py +++ b/homeassistant/components/reolink/diagnostics.py @@ -24,7 +24,7 @@ async def async_get_config_entry_diagnostics( IPC_cam[ch]["hardware version"] = api.camera_hardware_version(ch) IPC_cam[ch]["firmware version"] = api.camera_sw_version(ch) IPC_cam[ch]["encoding main"] = await api.get_encoding(ch) - if (signal := api.wifi_signal(ch)) is not None: + if (signal := api.wifi_signal(ch)) is not None and api.wifi_connection(ch): IPC_cam[ch]["WiFi signal"] = signal chimes: dict[int, dict[str, Any]] = {} @@ -43,7 +43,7 @@ async def async_get_config_entry_diagnostics( "HTTP(S) port": api.port, "Baichuan port": api.baichuan.port, "Baichuan only": api.baichuan_only, - "WiFi connection": api.wifi_connection, + "WiFi connection": api.wifi_connection(), "WiFi signal": api.wifi_signal(), "RTMP enabled": api.rtmp_enabled, "RTSP enabled": api.rtsp_enabled, diff --git a/homeassistant/components/reolink/manifest.json b/homeassistant/components/reolink/manifest.json index efd9f1121b6904..4ad80dda8073c4 100644 --- a/homeassistant/components/reolink/manifest.json +++ b/homeassistant/components/reolink/manifest.json @@ -19,5 +19,5 @@ "iot_class": "local_push", "loggers": ["reolink_aio"], "quality_scale": "platinum", - "requirements": ["reolink-aio==0.14.5"] + "requirements": ["reolink-aio==0.14.6"] } diff --git a/homeassistant/components/reolink/sensor.py b/homeassistant/components/reolink/sensor.py index cd03f2b59b5c12..9b9a78c8ce7771 100644 --- a/homeassistant/components/reolink/sensor.py +++ b/homeassistant/components/reolink/sensor.py @@ -148,7 +148,7 @@ class ReolinkHostSensorEntityDescription( native_unit_of_measurement=SIGNAL_STRENGTH_DECIBELS_MILLIWATT, entity_registry_enabled_default=False, value=lambda api: api.wifi_signal(), - supported=lambda api: api.supported(None, "wifi") and api.wifi_connection, + supported=lambda api: api.supported(None, "wifi") and api.wifi_connection(), ), ReolinkHostSensorEntityDescription( key="cpu_usage", diff --git a/requirements_all.txt b/requirements_all.txt index 446d3f4c76894c..dae69131cc6495 100644 --- a/requirements_all.txt +++ b/requirements_all.txt @@ -2666,7 +2666,7 @@ renault-api==0.3.1 renson-endura-delta==1.7.2 # homeassistant.components.reolink -reolink-aio==0.14.5 +reolink-aio==0.14.6 # homeassistant.components.idteck_prox rfk101py==0.0.1 diff --git a/requirements_test_all.txt b/requirements_test_all.txt index 3c0564e4100bcb..35bc76f3cfe208 100644 --- a/requirements_test_all.txt +++ b/requirements_test_all.txt @@ -2212,7 +2212,7 @@ renault-api==0.3.1 renson-endura-delta==1.7.2 # homeassistant.components.reolink -reolink-aio==0.14.5 +reolink-aio==0.14.6 # homeassistant.components.rflink rflink==0.0.67 diff --git a/tests/components/reolink/conftest.py b/tests/components/reolink/conftest.py index fa4cac6fff342d..48b024e0b10688 100644 --- a/tests/components/reolink/conftest.py +++ b/tests/components/reolink/conftest.py @@ -128,7 +128,7 @@ def _init_host_mock(host_mock: MagicMock) -> None: host_mock.session_active = True host_mock.timeout = 60 host_mock.renewtimer.return_value = 600 - host_mock.wifi_connection = False + host_mock.wifi_connection.return_value = False host_mock.wifi_signal.return_value = -45 host_mock.whiteled_mode_list.return_value = [] host_mock.post_recording_time_list.return_value = [] diff --git a/tests/components/reolink/snapshots/test_diagnostics.ambr b/tests/components/reolink/snapshots/test_diagnostics.ambr index 99df90340d27b2..ca35d7eb70fad1 100644 --- a/tests/components/reolink/snapshots/test_diagnostics.ambr +++ b/tests/components/reolink/snapshots/test_diagnostics.ambr @@ -38,7 +38,7 @@ 'ONVIF enabled': True, 'RTMP enabled': True, 'RTSP enabled': True, - 'WiFi connection': False, + 'WiFi connection': True, 'WiFi signal': -45, 'abilities': dict({ 'abilityChn': list([ diff --git a/tests/components/reolink/test_diagnostics.py b/tests/components/reolink/test_diagnostics.py index b347bae9ec074f..3e8ab4d0b2b958 100644 --- a/tests/components/reolink/test_diagnostics.py +++ b/tests/components/reolink/test_diagnostics.py @@ -21,6 +21,8 @@ async def test_entry_diagnostics( snapshot: SnapshotAssertion, ) -> None: """Test Reolink diagnostics.""" + reolink_host.wifi_connection.return_value = True + assert await hass.config_entries.async_setup(config_entry.entry_id) await hass.async_block_till_done() diag = await get_diagnostics_for_config_entry(hass, hass_client, config_entry) diff --git a/tests/components/reolink/test_sensor.py b/tests/components/reolink/test_sensor.py index b30f0c2a61af16..9b32f70a9bd62c 100644 --- a/tests/components/reolink/test_sensor.py +++ b/tests/components/reolink/test_sensor.py @@ -21,7 +21,7 @@ async def test_sensors( ) -> None: """Test sensor entities.""" reolink_host.ptz_pan_position.return_value = 1200 - reolink_host.wifi_connection = True + reolink_host.wifi_connection.return_value = True reolink_host.wifi_signal.return_value = -55 reolink_host.hdd_list = [0] reolink_host.hdd_storage.return_value = 95 From 2b0cda0ad1236e8c0163158dbc7d06c433d37b79 Mon Sep 17 00:00:00 2001 From: Artur Pragacz <49985303+arturpragacz@users.noreply.github.com> Date: Tue, 5 Aug 2025 20:46:03 +0200 Subject: [PATCH 3/5] Adjust condition and trigger method names (#150060) --- .../components/device_automation/condition.py | 4 ++-- homeassistant/components/sun/condition.py | 4 ++-- homeassistant/components/zone/condition.py | 4 ++-- homeassistant/components/zwave_js/triggers/event.py | 4 ++-- .../components/zwave_js/triggers/value_updated.py | 4 ++-- homeassistant/helpers/condition.py | 10 +++++----- homeassistant/helpers/trigger.py | 10 +++++----- tests/components/zwave_js/test_trigger.py | 8 ++++---- tests/helpers/test_condition.py | 6 +++--- tests/helpers/test_trigger.py | 6 +++--- 10 files changed, 30 insertions(+), 30 deletions(-) diff --git a/homeassistant/components/device_automation/condition.py b/homeassistant/components/device_automation/condition.py index 5e2146a533c2ec..426cc45a895951 100644 --- a/homeassistant/components/device_automation/condition.py +++ b/homeassistant/components/device_automation/condition.py @@ -61,7 +61,7 @@ def __init__(self, hass: HomeAssistant, config: ConfigType) -> None: self._hass = hass @classmethod - async def async_validate_condition_config( + async def async_validate_config( cls, hass: HomeAssistant, config: ConfigType ) -> ConfigType: """Validate device condition config.""" @@ -69,7 +69,7 @@ async def async_validate_condition_config( hass, config, cv.DEVICE_CONDITION_SCHEMA, DeviceAutomationType.CONDITION ) - async def async_condition_from_config(self) -> condition.ConditionCheckerType: + async def async_get_checker(self) -> condition.ConditionCheckerType: """Test a device condition.""" platform = await async_get_device_automation_platform( self._hass, self._config[CONF_DOMAIN], DeviceAutomationType.CONDITION diff --git a/homeassistant/components/sun/condition.py b/homeassistant/components/sun/condition.py index f48505b49932ee..15f3ea90c7382e 100644 --- a/homeassistant/components/sun/condition.py +++ b/homeassistant/components/sun/condition.py @@ -131,13 +131,13 @@ def __init__(self, hass: HomeAssistant, config: ConfigType) -> None: self._hass = hass @classmethod - async def async_validate_condition_config( + async def async_validate_config( cls, hass: HomeAssistant, config: ConfigType ) -> ConfigType: """Validate config.""" return _CONDITION_SCHEMA(config) # type: ignore[no-any-return] - async def async_condition_from_config(self) -> ConditionCheckerType: + async def async_get_checker(self) -> ConditionCheckerType: """Wrap action method with sun based condition.""" before = self._config.get("before") after = self._config.get("after") diff --git a/homeassistant/components/zone/condition.py b/homeassistant/components/zone/condition.py index 0fb30eeda9cdbd..b0fe30b26fd40d 100644 --- a/homeassistant/components/zone/condition.py +++ b/homeassistant/components/zone/condition.py @@ -100,13 +100,13 @@ def __init__(self, hass: HomeAssistant, config: ConfigType) -> None: self._config = config @classmethod - async def async_validate_condition_config( + async def async_validate_config( cls, hass: HomeAssistant, config: ConfigType ) -> ConfigType: """Validate config.""" return _CONDITION_SCHEMA(config) # type: ignore[no-any-return] - async def async_condition_from_config(self) -> ConditionCheckerType: + async def async_get_checker(self) -> ConditionCheckerType: """Wrap action method with zone based condition.""" entity_ids = self._config.get(CONF_ENTITY_ID, []) zone_entity_ids = self._config.get(CONF_ZONE, []) diff --git a/homeassistant/components/zwave_js/triggers/event.py b/homeassistant/components/zwave_js/triggers/event.py index a9e37a8efa26bc..77449af3e363f6 100644 --- a/homeassistant/components/zwave_js/triggers/event.py +++ b/homeassistant/components/zwave_js/triggers/event.py @@ -263,13 +263,13 @@ def __init__(self, hass: HomeAssistant, config: ConfigType) -> None: self._hass = hass @classmethod - async def async_validate_trigger_config( + async def async_validate_config( cls, hass: HomeAssistant, config: ConfigType ) -> ConfigType: """Validate config.""" return await async_validate_trigger_config(hass, config) - async def async_attach_trigger( + async def async_attach( self, action: TriggerActionType, trigger_info: TriggerInfo, diff --git a/homeassistant/components/zwave_js/triggers/value_updated.py b/homeassistant/components/zwave_js/triggers/value_updated.py index abd231ea56854c..f46592769cbe2a 100644 --- a/homeassistant/components/zwave_js/triggers/value_updated.py +++ b/homeassistant/components/zwave_js/triggers/value_updated.py @@ -216,13 +216,13 @@ def __init__(self, hass: HomeAssistant, config: ConfigType) -> None: self._hass = hass @classmethod - async def async_validate_trigger_config( + async def async_validate_config( cls, hass: HomeAssistant, config: ConfigType ) -> ConfigType: """Validate config.""" return await async_validate_trigger_config(hass, config) - async def async_attach_trigger( + async def async_attach( self, action: TriggerActionType, trigger_info: TriggerInfo, diff --git a/homeassistant/helpers/condition.py b/homeassistant/helpers/condition.py index 3c6120f523f7b9..5aa39e731668e8 100644 --- a/homeassistant/helpers/condition.py +++ b/homeassistant/helpers/condition.py @@ -199,14 +199,14 @@ def __init__(self, hass: HomeAssistant, config: ConfigType) -> None: @classmethod @abc.abstractmethod - async def async_validate_condition_config( + async def async_validate_config( cls, hass: HomeAssistant, config: ConfigType ) -> ConfigType: """Validate config.""" @abc.abstractmethod - async def async_condition_from_config(self) -> ConditionCheckerType: - """Evaluate state based on configuration.""" + async def async_get_checker(self) -> ConditionCheckerType: + """Get the condition checker.""" class ConditionProtocol(Protocol): @@ -346,7 +346,7 @@ def disabled_condition( if platform is not None: condition_descriptors = await platform.async_get_conditions(hass) condition_instance = condition_descriptors[condition](hass, config) - return await condition_instance.async_condition_from_config() + return await condition_instance.async_get_checker() for fmt in (ASYNC_FROM_CONFIG_FORMAT, FROM_CONFIG_FORMAT): factory = getattr(sys.modules[__name__], fmt.format(condition), None) @@ -974,7 +974,7 @@ async def async_validate_condition_config( condition_descriptors = await platform.async_get_conditions(hass) if not (condition_class := condition_descriptors.get(condition)): raise vol.Invalid(f"Invalid condition '{condition}' specified") - return await condition_class.async_validate_condition_config(hass, config) + return await condition_class.async_validate_config(hass, config) if platform is None and condition in ("numeric_state", "state"): validator = cast( Callable[[HomeAssistant, ConfigType], ConfigType], diff --git a/homeassistant/helpers/trigger.py b/homeassistant/helpers/trigger.py index e9c4a3d5b02eab..741fac3fcf7a21 100644 --- a/homeassistant/helpers/trigger.py +++ b/homeassistant/helpers/trigger.py @@ -173,18 +173,18 @@ def __init__(self, hass: HomeAssistant, config: ConfigType) -> None: @classmethod @abc.abstractmethod - async def async_validate_trigger_config( + async def async_validate_config( cls, hass: HomeAssistant, config: ConfigType ) -> ConfigType: """Validate config.""" @abc.abstractmethod - async def async_attach_trigger( + async def async_attach( self, action: TriggerActionType, trigger_info: TriggerInfo, ) -> CALLBACK_TYPE: - """Attach a trigger.""" + """Attach the trigger.""" class TriggerProtocol(Protocol): @@ -390,7 +390,7 @@ async def async_validate_trigger_config( ) if not (trigger := trigger_descriptors.get(relative_trigger_key)): raise vol.Invalid(f"Invalid trigger '{trigger_key}' specified") - conf = await trigger.async_validate_trigger_config(hass, conf) + conf = await trigger.async_validate_config(hass, conf) elif hasattr(platform, "async_validate_trigger_config"): conf = await platform.async_validate_trigger_config(hass, conf) else: @@ -495,7 +495,7 @@ async def async_initialize_triggers( platform_domain, trigger_key ) trigger = trigger_descriptors[relative_trigger_key](hass, conf) - coro = trigger.async_attach_trigger(action_wrapper, info) + coro = trigger.async_attach(action_wrapper, info) else: coro = platform.async_attach_trigger(hass, conf, action_wrapper, info) diff --git a/tests/components/zwave_js/test_trigger.py b/tests/components/zwave_js/test_trigger.py index 4186f1a778e80a..7b00a9d0eef68b 100644 --- a/tests/components/zwave_js/test_trigger.py +++ b/tests/components/zwave_js/test_trigger.py @@ -977,7 +977,7 @@ async def test_zwave_js_event_invalid_config_entry_id( async def test_invalid_trigger_configs(hass: HomeAssistant) -> None: """Test invalid trigger configs.""" with pytest.raises(vol.Invalid): - await TRIGGERS["event"].async_validate_trigger_config( + await TRIGGERS["event"].async_validate_config( hass, { "platform": f"{DOMAIN}.event", @@ -988,7 +988,7 @@ async def test_invalid_trigger_configs(hass: HomeAssistant) -> None: ) with pytest.raises(vol.Invalid): - await TRIGGERS["value_updated"].async_validate_trigger_config( + await TRIGGERS["value_updated"].async_validate_config( hass, { "platform": f"{DOMAIN}.value_updated", @@ -1026,7 +1026,7 @@ async def test_zwave_js_trigger_config_entry_unloaded( await hass.config_entries.async_unload(integration.entry_id) # Test full validation for both events - assert await TRIGGERS["value_updated"].async_validate_trigger_config( + assert await TRIGGERS["value_updated"].async_validate_config( hass, { "platform": f"{DOMAIN}.value_updated", @@ -1036,7 +1036,7 @@ async def test_zwave_js_trigger_config_entry_unloaded( }, ) - assert await TRIGGERS["event"].async_validate_trigger_config( + assert await TRIGGERS["event"].async_validate_config( hass, { "platform": f"{DOMAIN}.event", diff --git a/tests/helpers/test_condition.py b/tests/helpers/test_condition.py index 86aab3cb681bff..94e7169627084f 100644 --- a/tests/helpers/test_condition.py +++ b/tests/helpers/test_condition.py @@ -2089,7 +2089,7 @@ def __init__(self, hass: HomeAssistant, config: ConfigType) -> None: """Initialize condition.""" @classmethod - async def async_validate_condition_config( + async def async_validate_config( cls, hass: HomeAssistant, config: ConfigType ) -> ConfigType: """Validate config.""" @@ -2098,14 +2098,14 @@ async def async_validate_condition_config( class MockCondition1(MockCondition): """Mock condition 1.""" - async def async_condition_from_config(self) -> condition.ConditionCheckerType: + async def async_get_checker(self) -> condition.ConditionCheckerType: """Evaluate state based on configuration.""" return lambda hass, vars: True class MockCondition2(MockCondition): """Mock condition 2.""" - async def async_condition_from_config(self) -> condition.ConditionCheckerType: + async def async_get_checker(self) -> condition.ConditionCheckerType: """Evaluate state based on configuration.""" return lambda hass, vars: False diff --git a/tests/helpers/test_trigger.py b/tests/helpers/test_trigger.py index 134410656915ef..d5621a1ae616b2 100644 --- a/tests/helpers/test_trigger.py +++ b/tests/helpers/test_trigger.py @@ -461,7 +461,7 @@ def __init__(self, hass: HomeAssistant, config: ConfigType) -> None: """Initialize trigger.""" @classmethod - async def async_validate_trigger_config( + async def async_validate_config( cls, hass: HomeAssistant, config: ConfigType ) -> ConfigType: """Validate config.""" @@ -470,7 +470,7 @@ async def async_validate_trigger_config( class MockTrigger1(MockTrigger): """Mock trigger 1.""" - async def async_attach_trigger( + async def async_attach( self, action: TriggerActionType, trigger_info: TriggerInfo, @@ -481,7 +481,7 @@ async def async_attach_trigger( class MockTrigger2(MockTrigger): """Mock trigger 2.""" - async def async_attach_trigger( + async def async_attach( self, action: TriggerActionType, trigger_info: TriggerInfo, From 7b45798e306b8af2846cf195551ba473f4ea6ee4 Mon Sep 17 00:00:00 2001 From: Martin Hjelmare Date: Tue, 5 Aug 2025 22:40:42 +0200 Subject: [PATCH 4/5] Remove matter vacuum battery level attribute (#150061) --- homeassistant/components/matter/vacuum.py | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/homeassistant/components/matter/vacuum.py b/homeassistant/components/matter/vacuum.py index 6ab687e060a721..cf9f26adecb4d7 100644 --- a/homeassistant/components/matter/vacuum.py +++ b/homeassistant/components/matter/vacuum.py @@ -140,11 +140,6 @@ async def async_pause(self) -> None: def _update_from_device(self) -> None: """Update from device.""" self._calculate_features() - # optional battery level - if VacuumEntityFeature.BATTERY & self._attr_supported_features: - self._attr_battery_level = self.get_matter_attribute_value( - clusters.PowerSource.Attributes.BatPercentRemaining - ) # derive state from the run mode + operational state run_mode_raw: int = self.get_matter_attribute_value( clusters.RvcRunMode.Attributes.CurrentMode @@ -188,11 +183,6 @@ def _calculate_features(self) -> None: supported_features |= VacuumEntityFeature.STATE supported_features |= VacuumEntityFeature.STOP - # optional battery attribute = battery feature - if self.get_matter_attribute_value( - clusters.PowerSource.Attributes.BatPercentRemaining - ): - supported_features |= VacuumEntityFeature.BATTERY # optional identify cluster = locate feature (value must be not None or 0) if self.get_matter_attribute_value(clusters.Identify.Attributes.IdentifyType): supported_features |= VacuumEntityFeature.LOCATE @@ -230,7 +220,6 @@ def _calculate_features(self) -> None: clusters.RvcRunMode.Attributes.CurrentMode, clusters.RvcOperationalState.Attributes.OperationalState, ), - optional_attributes=(clusters.PowerSource.Attributes.BatPercentRemaining,), device_type=(device_types.RoboticVacuumCleaner,), allow_none_value=True, ), From a24f027923a4d9621a162362c866ddde2a85f3b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20BOU=C3=89?= Date: Tue, 5 Aug 2025 23:18:48 +0200 Subject: [PATCH 5/5] Add icon for esa_state in Matter integration (#149075) --- homeassistant/components/matter/icons.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/homeassistant/components/matter/icons.json b/homeassistant/components/matter/icons.json index 2b9ca2cc3e24d5..475504d5aebcaf 100644 --- a/homeassistant/components/matter/icons.json +++ b/homeassistant/components/matter/icons.json @@ -99,6 +99,9 @@ "esa_opt_out_state": { "default": "mdi:home-lightning-bolt" }, + "esa_state": { + "default": "mdi:home-lightning-bolt" + }, "evse_state": { "default": "mdi:ev-station" },