From 97d7e0e01eec1abe8aa80b9d9ddab3308a953270 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20BOU=C3=89?= Date: Fri, 19 Dec 2025 10:01:55 +0100 Subject: [PATCH] Matter Speaker volume LevelControl (#149490) Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- homeassistant/components/matter/icons.json | 3 + homeassistant/components/matter/number.py | 25 ++++++++ homeassistant/components/matter/strings.json | 3 + .../matter/fixtures/nodes/speaker.json | 6 +- .../matter/snapshots/test_number.ambr | 58 +++++++++++++++++++ 5 files changed, 93 insertions(+), 2 deletions(-) diff --git a/homeassistant/components/matter/icons.json b/homeassistant/components/matter/icons.json index 0e230e97da5..ec96875c06b 100644 --- a/homeassistant/components/matter/icons.json +++ b/homeassistant/components/matter/icons.json @@ -42,6 +42,9 @@ "number": { "cook_time": { "default": "mdi:microwave" + }, + "speaker_setpoint": { + "default": "mdi:speaker" } }, "select": { diff --git a/homeassistant/components/matter/number.py b/homeassistant/components/matter/number.py index 733779e19f8..a20e6b3b42a 100644 --- a/homeassistant/components/matter/number.py +++ b/homeassistant/components/matter/number.py @@ -365,6 +365,31 @@ DISCOVERY_SCHEMAS = [ clusters.MicrowaveOvenControl.Attributes.MaxCookTime, ), ), + MatterDiscoverySchema( + platform=Platform.NUMBER, + entity_description=MatterRangeNumberEntityDescription( + key="speaker_setpoint", + translation_key="speaker_setpoint", + native_unit_of_measurement=PERCENTAGE, + command=lambda value: clusters.LevelControl.Commands.MoveToLevel( + level=int(value) + ), + native_min_value=0, + native_max_value=100, + native_step=1, + device_to_ha=lambda x: None if x is None else x, + min_attribute=clusters.LevelControl.Attributes.MinLevel, + max_attribute=clusters.LevelControl.Attributes.MaxLevel, + mode=NumberMode.SLIDER, + ), + entity_class=MatterRangeNumber, + required_attributes=( + clusters.LevelControl.Attributes.CurrentLevel, + clusters.LevelControl.Attributes.MinLevel, + clusters.LevelControl.Attributes.MaxLevel, + ), + device_type=(device_types.Speaker,), + ), MatterDiscoverySchema( platform=Platform.NUMBER, entity_description=MatterNumberEntityDescription( diff --git a/homeassistant/components/matter/strings.json b/homeassistant/components/matter/strings.json index 9f8a5957779..9fa3425c4e4 100644 --- a/homeassistant/components/matter/strings.json +++ b/homeassistant/components/matter/strings.json @@ -232,6 +232,9 @@ "pump_setpoint": { "name": "Setpoint" }, + "speaker_setpoint": { + "name": "Volume" + }, "temperature_offset": { "name": "Temperature offset" }, diff --git a/tests/components/matter/fixtures/nodes/speaker.json b/tests/components/matter/fixtures/nodes/speaker.json index f28923b3b3c..a5d3316704d 100644 --- a/tests/components/matter/fixtures/nodes/speaker.json +++ b/tests/components/matter/fixtures/nodes/speaker.json @@ -46,7 +46,7 @@ "0/40/65532": 0, "0/40/0": 19, "0/40/6": "**REDACTED**", - "0/40/1": "Beep Home", + "0/40/1": "TEST_VENDOR", "0/40/2": 65521, "0/40/3": "Mock speaker", "0/40/4": 32768, @@ -54,7 +54,7 @@ "0/40/8": "1.0", "0/40/9": 1, "0/40/10": "1.0", - "0/40/18": "A576929DE6D138DC", + "0/40/18": "123456789", "0/40/19": { "0": 3, "1": 3 @@ -221,6 +221,8 @@ "1/8/65532": 0, "1/8/65533": 6, "1/8/0": 47, + "1/8/2": 0, + "1/8/3": 100, "1/8/17": null, "1/8/15": 0, "1/8/65528": [], diff --git a/tests/components/matter/snapshots/test_number.ambr b/tests/components/matter/snapshots/test_number.ambr index 770f6544e6c..b836bece869 100644 --- a/tests/components/matter/snapshots/test_number.ambr +++ b/tests/components/matter/snapshots/test_number.ambr @@ -3691,6 +3691,64 @@ 'state': '4.0', }) # --- +# name: test_numbers[speaker][number.mock_speaker_volume-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'max': 100, + 'min': 0, + 'mode': , + 'step': 1, + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'number', + 'entity_category': None, + 'entity_id': 'number.mock_speaker_volume', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': None, + 'original_icon': None, + 'original_name': 'Volume', + 'platform': 'matter', + 'previous_unique_id': None, + 'suggested_object_id': None, + 'supported_features': 0, + 'translation_key': 'speaker_setpoint', + 'unique_id': '00000000000004D2-000000000000006B-MatterNodeDevice-1-speaker_setpoint-8-0', + 'unit_of_measurement': '%', + }) +# --- +# name: test_numbers[speaker][number.mock_speaker_volume-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'Mock speaker Volume', + 'max': 100, + 'min': 0, + 'mode': , + 'step': 1, + 'unit_of_measurement': '%', + }), + 'context': , + 'entity_id': 'number.mock_speaker_volume', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '47', + }) +# --- # name: test_numbers[valve][number.valve_default_open_duration-entry] EntityRegistryEntrySnapshot({ 'aliases': set({