From 41f783f14d3e2e7363a71b9bf78a7565abbca1f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20BOU=C3=89?= Date: Thu, 28 May 2026 11:03:58 +0200 Subject: [PATCH] Add Matter soil moisture sensor (#172372) --- homeassistant/components/matter/sensor.py | 13 +++ tests/components/matter/common.py | 1 + .../fixtures/nodes/mock_soil_sensor.json | 87 +++++++++++++++++++ .../matter/snapshots/test_sensor.ambr | 55 ++++++++++++ tests/components/matter/test_sensor.py | 19 ++++ 5 files changed, 175 insertions(+) create mode 100644 tests/components/matter/fixtures/nodes/mock_soil_sensor.json diff --git a/homeassistant/components/matter/sensor.py b/homeassistant/components/matter/sensor.py index fadf4b794470..788fabac7635 100644 --- a/homeassistant/components/matter/sensor.py +++ b/homeassistant/components/matter/sensor.py @@ -439,6 +439,19 @@ DISCOVERY_SCHEMAS = [ ), allow_multi=True, # also used for climate entity ), + MatterDiscoverySchema( + platform=Platform.SENSOR, + entity_description=MatterSensorEntityDescription( + key="SoilMoistureSensor", + native_unit_of_measurement=PERCENTAGE, + device_class=SensorDeviceClass.MOISTURE, + state_class=SensorStateClass.MEASUREMENT, + ), + entity_class=MatterSensor, + required_attributes=( + clusters.SoilMeasurement.Attributes.SoilMoistureMeasuredValue, + ), + ), MatterDiscoverySchema( platform=Platform.SENSOR, entity_description=MatterSensorEntityDescription( diff --git a/tests/components/matter/common.py b/tests/components/matter/common.py index adf14c7b8f5f..02823c8b9d31 100644 --- a/tests/components/matter/common.py +++ b/tests/components/matter/common.py @@ -78,6 +78,7 @@ FIXTURES = [ "mock_pressure_sensor", "mock_pump", "mock_room_airconditioner", + "mock_soil_sensor", "mock_solar_inverter", "mock_speaker", "mock_switch_unit", diff --git a/tests/components/matter/fixtures/nodes/mock_soil_sensor.json b/tests/components/matter/fixtures/nodes/mock_soil_sensor.json new file mode 100644 index 000000000000..f8a9905d4113 --- /dev/null +++ b/tests/components/matter/fixtures/nodes/mock_soil_sensor.json @@ -0,0 +1,87 @@ +{ + "node_id": 101, + "date_commissioned": "2024-11-27T00:00:00.000000", + "last_interview": "2024-11-27T00:00:00.000000", + "interview_version": 2, + "attributes": { + "0/29/0": [ + { + "0": 22, + "1": 1 + } + ], + "0/29/1": [ + 4, 29, 31, 40, 42, 43, 44, 48, 49, 50, 51, 52, 53, 54, 55, 59, 60, 62, 63, + 64, 65 + ], + "0/29/2": [41], + "0/29/3": [1], + "0/29/65532": 0, + "0/29/65533": 1, + "0/29/65528": [], + "0/29/65529": [], + "0/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "0/40/0": 1, + "0/40/1": "Nabu Casa", + "0/40/2": 65521, + "0/40/3": "Mock SoilSensor", + "0/40/4": 32768, + "0/40/5": "Mock Soil Sensor", + "0/40/6": "XX", + "0/40/7": 0, + "0/40/8": "v1.0", + "0/40/9": 1, + "0/40/10": "v1.0", + "0/40/11": "20241127", + "0/40/12": "", + "0/40/13": "", + "0/40/14": "", + "0/40/15": "TEST_SN", + "0/40/16": false, + "0/40/17": true, + "0/40/18": "mock-soil-sensor", + "0/40/19": { + "0": 3, + "1": 3 + }, + "0/40/65532": 0, + "0/40/65533": 1, + "0/40/65528": [], + "0/40/65529": [], + "0/40/65531": [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 65528, 65529, 65531, 65532, 65533 + ], + "1/3/65529": [0, 64], + "1/3/65531": [0, 1, 65528, 65529, 65531, 65532, 65533], + "1/29/0": [ + { + "0": 69, + "1": 1 + } + ], + "1/29/1": [3, 29, 57, 1072, 40], + "1/29/2": [], + "1/29/3": [9, 10], + "1/29/65532": null, + "1/29/65533": 1, + "1/29/65528": [], + "1/29/65529": [], + "1/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "1/1072/0": { + "0": 17, + "1": true, + "2": 0, + "3": 100, + "4": [] + }, + "1/1072/1": 50, + "1/1072/65532": 0, + "1/1072/65533": 1, + "1/1072/65528": [], + "1/1072/65529": [], + "1/1072/65531": [0, 1, 65528, 65529, 65531, 65532, 65533] + }, + "available": true, + "attribute_subscriptions": [] +} diff --git a/tests/components/matter/snapshots/test_sensor.ambr b/tests/components/matter/snapshots/test_sensor.ambr index 5cec98f04190..3c71f793c574 100644 --- a/tests/components/matter/snapshots/test_sensor.ambr +++ b/tests/components/matter/snapshots/test_sensor.ambr @@ -18619,6 +18619,61 @@ 'state': '0.0', }) # --- +# name: test_sensors[mock_soil_sensor][sensor.mock_soil_sensor_moisture-entry] + EntityRegistryEntrySnapshot({ + 'aliases': list([ + None, + ]), + 'area_id': None, + 'capabilities': dict({ + 'state_class': , + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': None, + 'entity_id': 'sensor.mock_soil_sensor_moisture', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'object_id_base': 'Moisture', + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Moisture', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': None, + 'unique_id': '00000000000004D2-0000000000000065-MatterNodeDevice-1-SoilMoistureSensor-1072-1', + 'unit_of_measurement': '%', + }) +# --- +# name: test_sensors[mock_soil_sensor][sensor.mock_soil_sensor_moisture-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'moisture', + 'friendly_name': 'Mock Soil Sensor Moisture', + 'state_class': , + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'sensor.mock_soil_sensor_moisture', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '50', + }) +# --- # name: test_sensors[mock_solar_inverter][sensor.mock_solar_inverter_active_current-entry] EntityRegistryEntrySnapshot({ 'aliases': list([ diff --git a/tests/components/matter/test_sensor.py b/tests/components/matter/test_sensor.py index b6eefb08d514..e03e6ab153e0 100644 --- a/tests/components/matter/test_sensor.py +++ b/tests/components/matter/test_sensor.py @@ -85,6 +85,25 @@ async def test_humidity_sensor( assert state.state == "40.0" +@pytest.mark.parametrize("node_fixture", ["mock_soil_sensor"]) +async def test_soil_moisture_sensor( + hass: HomeAssistant, + matter_client: MagicMock, + matter_node: MatterNode, +) -> None: + """Test soil moisture sensor.""" + state = hass.states.get("sensor.mock_soil_sensor_moisture") + assert state + assert state.state == "50" + + set_node_attribute(matter_node, 1, 1072, 1, 75) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get("sensor.mock_soil_sensor_moisture") + assert state + assert state.state == "75" + + @pytest.mark.parametrize("node_fixture", ["mock_light_sensor"]) async def test_light_sensor( hass: HomeAssistant,