diff --git a/homeassistant/components/matter/sensor.py b/homeassistant/components/matter/sensor.py index 62c70f777e7..f563c246186 100644 --- a/homeassistant/components/matter/sensor.py +++ b/homeassistant/components/matter/sensor.py @@ -3,7 +3,7 @@ from __future__ import annotations from dataclasses import dataclass, field -from datetime import datetime +from datetime import datetime, timedelta from typing import TYPE_CHECKING, cast from chip.clusters import Objects as clusters @@ -44,7 +44,7 @@ from homeassistant.const import ( ) from homeassistant.core import HomeAssistant, callback from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback -from homeassistant.util import slugify +from homeassistant.util import dt as dt_util, slugify from .entity import MatterEntity, MatterEntityDescription from .helpers import get_matter @@ -942,6 +942,21 @@ DISCOVERY_SCHEMAS = [ # don't discover this entry if the supported state list is empty secondary_value_is_not=[], ), + MatterDiscoverySchema( + platform=Platform.SENSOR, + entity_description=MatterSensorEntityDescription( + key="OperationalStateCountdownTime", + translation_key="estimated_end_time", + device_class=SensorDeviceClass.TIMESTAMP, + state_class=None, + # Add countdown to current datetime to get the estimated end time + device_to_ha=( + lambda x: dt_util.utcnow() + timedelta(seconds=x) if x > 0 else None + ), + ), + entity_class=MatterSensor, + required_attributes=(clusters.OperationalState.Attributes.CountdownTime,), + ), MatterDiscoverySchema( platform=Platform.SENSOR, entity_description=MatterListSensorEntityDescription( diff --git a/homeassistant/components/matter/strings.json b/homeassistant/components/matter/strings.json index 0ac44c006ab..2534dd6aa6e 100644 --- a/homeassistant/components/matter/strings.json +++ b/homeassistant/components/matter/strings.json @@ -318,6 +318,9 @@ "docked": "Docked" } }, + "estimated_end_time": { + "name": "Estimated end time" + }, "switch_current_position": { "name": "Current switch position" }, diff --git a/tests/components/matter/snapshots/test_sensor.ambr b/tests/components/matter/snapshots/test_sensor.ambr index 8e459c0f573..472799b80ae 100644 --- a/tests/components/matter/snapshots/test_sensor.ambr +++ b/tests/components/matter/snapshots/test_sensor.ambr @@ -3443,6 +3443,55 @@ 'state': '1.3', }) # --- +# name: test_sensors[microwave_oven][sensor.microwave_oven_estimated_end_time-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.microwave_oven_estimated_end_time', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Estimated end time', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'estimated_end_time', + 'unique_id': '00000000000004D2-000000000000009D-MatterNodeDevice-1-OperationalStateCountdownTime-96-2', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[microwave_oven][sensor.microwave_oven_estimated_end_time-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'timestamp', + 'friendly_name': 'Microwave Oven Estimated end time', + }), + 'context': , + 'entity_id': 'sensor.microwave_oven_estimated_end_time', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2025-01-01T14:00:30+00:00', + }) +# --- # name: test_sensors[microwave_oven][sensor.microwave_oven_operational_state-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/matter/test_sensor.py b/tests/components/matter/test_sensor.py index 3e9af4a6e4b..883a976284e 100644 --- a/tests/components/matter/test_sensor.py +++ b/tests/components/matter/test_sensor.py @@ -17,6 +17,7 @@ from .common import ( ) +@pytest.mark.freeze_time("2025-01-01T14:00:00+00:00") @pytest.mark.usefixtures("entity_registry_enabled_by_default", "matter_devices") async def test_sensors( hass: HomeAssistant, @@ -381,6 +382,21 @@ async def test_draft_electrical_measurement_sensor( assert state.state == "unknown" +@pytest.mark.freeze_time("2025-01-01T14:00:00+00:00") +@pytest.mark.parametrize("node_fixture", ["microwave_oven"]) +async def test_countdown_time_sensor( + hass: HomeAssistant, + matter_client: MagicMock, + matter_node: MatterNode, +) -> None: + """Test CountdownTime sensor.""" + # OperationalState Cluster / CountdownTime (1/96/2) + state = hass.states.get("sensor.microwave_oven_estimated_end_time") + assert state + # 1/96/2 = 30 seconds, so 30 s should be added to the current time. + assert state.state == "2025-01-01T14:00:30+00:00" + + @pytest.mark.parametrize("node_fixture", ["silabs_laundrywasher"]) async def test_list_sensor( hass: HomeAssistant,