mirror of
https://github.com/home-assistant/core.git
synced 2025-07-29 16:17:20 +00:00
Matter MicrowaveOven device (#148219)
Co-authored-by: Martin Hjelmare <marhje52@gmail.com>
This commit is contained in:
parent
05935bbc01
commit
a68e722c92
@ -40,6 +40,9 @@
|
||||
"laundry_washer_spin_speed": {
|
||||
"default": "mdi:reload"
|
||||
},
|
||||
"power_level": {
|
||||
"default": "mdi:power-settings"
|
||||
},
|
||||
"temperature_level": {
|
||||
"default": "mdi:thermometer"
|
||||
}
|
||||
@ -115,6 +118,11 @@
|
||||
"default": "mdi:pump"
|
||||
}
|
||||
},
|
||||
"number": {
|
||||
"cook_time": {
|
||||
"default": "mdi:microwave"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
"child_lock": {
|
||||
"default": "mdi:lock",
|
||||
|
@ -4,7 +4,7 @@ from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from typing import Any, cast
|
||||
from typing import Any
|
||||
|
||||
from chip.clusters import Objects as clusters
|
||||
from chip.clusters.ClusterObjects import ClusterAttributeDescriptor, ClusterCommand
|
||||
@ -55,12 +55,16 @@ class MatterRangeNumberEntityDescription(
|
||||
):
|
||||
"""Describe Matter Number Input entities with min and max values."""
|
||||
|
||||
ha_to_device: Callable[[Any], Any]
|
||||
ha_to_device: Callable[[Any], Any] = lambda x: x
|
||||
|
||||
# attribute descriptors to get the min and max value
|
||||
min_attribute: type[ClusterAttributeDescriptor]
|
||||
min_attribute: type[ClusterAttributeDescriptor] | None = None
|
||||
max_attribute: type[ClusterAttributeDescriptor]
|
||||
|
||||
# Functions to format the min and max values for display or conversion
|
||||
format_min_value: Callable[[float], float] = lambda x: x
|
||||
format_max_value: Callable[[float], float] = lambda x: x
|
||||
|
||||
# command: a custom callback to create the command to send to the device
|
||||
# the callback's argument will be the index of the selected list value
|
||||
command: Callable[[int], ClusterCommand]
|
||||
@ -105,24 +109,29 @@ class MatterRangeNumber(MatterEntity, NumberEntity):
|
||||
@callback
|
||||
def _update_from_device(self) -> None:
|
||||
"""Update from device."""
|
||||
# get the value from the primary attribute and convert it to the HA value if needed
|
||||
value = self.get_matter_attribute_value(self._entity_info.primary_attribute)
|
||||
if value_convert := self.entity_description.device_to_ha:
|
||||
value = value_convert(value)
|
||||
self._attr_native_value = value
|
||||
self._attr_native_min_value = (
|
||||
cast(
|
||||
int,
|
||||
self.get_matter_attribute_value(self.entity_description.min_attribute),
|
||||
|
||||
# min case 1: get min from the attribute and convert it
|
||||
if self.entity_description.min_attribute:
|
||||
min_value = self.get_matter_attribute_value(
|
||||
self.entity_description.min_attribute
|
||||
)
|
||||
/ 100
|
||||
)
|
||||
self._attr_native_max_value = (
|
||||
cast(
|
||||
int,
|
||||
self.get_matter_attribute_value(self.entity_description.max_attribute),
|
||||
)
|
||||
/ 100
|
||||
min_convert = self.entity_description.format_min_value
|
||||
self._attr_native_min_value = min_convert(min_value)
|
||||
# min case 2: get the min from entity_description
|
||||
elif self.entity_description.native_min_value is not None:
|
||||
self._attr_native_min_value = self.entity_description.native_min_value
|
||||
|
||||
# get max from the attribute and convert it
|
||||
max_value = self.get_matter_attribute_value(
|
||||
self.entity_description.max_attribute
|
||||
)
|
||||
max_convert = self.entity_description.format_max_value
|
||||
self._attr_native_max_value = max_convert(max_value)
|
||||
|
||||
|
||||
class MatterLevelControlNumber(MatterEntity, NumberEntity):
|
||||
@ -302,6 +311,27 @@ DISCOVERY_SCHEMAS = [
|
||||
clusters.OccupancySensing.Attributes.PIROccupiedToUnoccupiedDelay,
|
||||
),
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.NUMBER,
|
||||
entity_description=MatterRangeNumberEntityDescription(
|
||||
key="MicrowaveOvenControlCookTime",
|
||||
translation_key="cook_time",
|
||||
device_class=NumberDeviceClass.DURATION,
|
||||
command=lambda value: clusters.MicrowaveOvenControl.Commands.SetCookingParameters(
|
||||
cookTime=int(value)
|
||||
),
|
||||
native_min_value=1, # 1 second minimum cook time
|
||||
native_step=1, # 1 second
|
||||
native_unit_of_measurement=UnitOfTime.SECONDS,
|
||||
max_attribute=clusters.MicrowaveOvenControl.Attributes.MaxCookTime,
|
||||
mode=NumberMode.SLIDER,
|
||||
),
|
||||
entity_class=MatterRangeNumber,
|
||||
required_attributes=(
|
||||
clusters.MicrowaveOvenControl.Attributes.CookTime,
|
||||
clusters.MicrowaveOvenControl.Attributes.MaxCookTime,
|
||||
),
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.NUMBER,
|
||||
entity_description=MatterNumberEntityDescription(
|
||||
@ -328,6 +358,8 @@ DISCOVERY_SCHEMAS = [
|
||||
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
|
||||
device_to_ha=lambda x: None if x is None else x / 100,
|
||||
ha_to_device=lambda x: round(x * 100),
|
||||
format_min_value=lambda x: x / 100,
|
||||
format_max_value=lambda x: x / 100,
|
||||
min_attribute=clusters.TemperatureControl.Attributes.MinTemperature,
|
||||
max_attribute=clusters.TemperatureControl.Attributes.MaxTemperature,
|
||||
mode=NumberMode.SLIDER,
|
||||
|
@ -197,10 +197,14 @@ class MatterListSelectEntity(MatterEntity, SelectEntity):
|
||||
@callback
|
||||
def _update_from_device(self) -> None:
|
||||
"""Update from device."""
|
||||
list_values = cast(
|
||||
list[str],
|
||||
self.get_matter_attribute_value(self.entity_description.list_attribute),
|
||||
list_values_raw = self.get_matter_attribute_value(
|
||||
self.entity_description.list_attribute
|
||||
)
|
||||
if TYPE_CHECKING:
|
||||
assert list_values_raw is not None
|
||||
|
||||
# Accept both list[str] and list[int], convert to str
|
||||
list_values = [str(v) for v in list_values_raw]
|
||||
self._attr_options = list_values
|
||||
current_option_idx: int = self.get_matter_attribute_value(
|
||||
self._entity_info.primary_attribute
|
||||
@ -443,6 +447,24 @@ DISCOVERY_SCHEMAS = [
|
||||
# don't discover this entry if the supported rinses list is empty
|
||||
secondary_value_is_not=[],
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.SELECT,
|
||||
entity_description=MatterListSelectEntityDescription(
|
||||
key="MicrowaveOvenControlSelectedWattIndex",
|
||||
translation_key="power_level",
|
||||
command=lambda selected_index: clusters.MicrowaveOvenControl.Commands.SetCookingParameters(
|
||||
wattSettingIndex=selected_index
|
||||
),
|
||||
list_attribute=clusters.MicrowaveOvenControl.Attributes.SupportedWatts,
|
||||
),
|
||||
entity_class=MatterListSelectEntity,
|
||||
required_attributes=(
|
||||
clusters.MicrowaveOvenControl.Attributes.SelectedWattIndex,
|
||||
clusters.MicrowaveOvenControl.Attributes.SupportedWatts,
|
||||
),
|
||||
# don't discover this entry if the supported state list is empty
|
||||
secondary_value_is_not=[],
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.SELECT,
|
||||
entity_description=MatterSelectEntityDescription(
|
||||
|
@ -180,6 +180,9 @@
|
||||
"altitude": {
|
||||
"name": "Altitude above sea level"
|
||||
},
|
||||
"cook_time": {
|
||||
"name": "Cook time"
|
||||
},
|
||||
"pump_setpoint": {
|
||||
"name": "Setpoint"
|
||||
},
|
||||
@ -222,6 +225,9 @@
|
||||
"device_energy_management_mode": {
|
||||
"name": "Energy management mode"
|
||||
},
|
||||
"power_level": {
|
||||
"name": "Power level (W)"
|
||||
},
|
||||
"sensitivity_level": {
|
||||
"name": "Sensitivity",
|
||||
"state": {
|
||||
|
@ -397,6 +397,8 @@
|
||||
"1/96/5": {
|
||||
"0": 0
|
||||
},
|
||||
"1/96/6": [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000],
|
||||
"1/96/7": 5,
|
||||
"1/96/65532": 2,
|
||||
"1/96/65533": 2,
|
||||
"1/96/65528": [4],
|
||||
|
@ -693,6 +693,65 @@
|
||||
'state': '255',
|
||||
})
|
||||
# ---
|
||||
# name: test_numbers[microwave_oven][number.microwave_oven_cook_time-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'max': 86400,
|
||||
'min': 1,
|
||||
'mode': <NumberMode.SLIDER: 'slider'>,
|
||||
'step': 1,
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'number',
|
||||
'entity_category': None,
|
||||
'entity_id': 'number.microwave_oven_cook_time',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': <NumberDeviceClass.DURATION: 'duration'>,
|
||||
'original_icon': None,
|
||||
'original_name': 'Cook time',
|
||||
'platform': 'matter',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'cook_time',
|
||||
'unique_id': '00000000000004D2-000000000000009D-MatterNodeDevice-1-MicrowaveOvenControlCookTime-95-0',
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
})
|
||||
# ---
|
||||
# name: test_numbers[microwave_oven][number.microwave_oven_cook_time-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'device_class': 'duration',
|
||||
'friendly_name': 'Microwave Oven Cook time',
|
||||
'max': 86400,
|
||||
'min': 1,
|
||||
'mode': <NumberMode.SLIDER: 'slider'>,
|
||||
'step': 1,
|
||||
'unit_of_measurement': <UnitOfTime.SECONDS: 's'>,
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'number.microwave_oven_cook_time',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '30',
|
||||
})
|
||||
# ---
|
||||
# name: test_numbers[mounted_dimmable_load_control_fixture][number.mock_mounted_dimmable_load_control_on_level-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
@ -981,6 +981,79 @@
|
||||
'state': 'Low',
|
||||
})
|
||||
# ---
|
||||
# name: test_selects[microwave_oven][select.microwave_oven_power_level_w-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
}),
|
||||
'area_id': None,
|
||||
'capabilities': dict({
|
||||
'options': list([
|
||||
'100',
|
||||
'200',
|
||||
'300',
|
||||
'400',
|
||||
'500',
|
||||
'600',
|
||||
'700',
|
||||
'800',
|
||||
'900',
|
||||
'1000',
|
||||
]),
|
||||
}),
|
||||
'config_entry_id': <ANY>,
|
||||
'config_subentry_id': <ANY>,
|
||||
'device_class': None,
|
||||
'device_id': <ANY>,
|
||||
'disabled_by': None,
|
||||
'domain': 'select',
|
||||
'entity_category': None,
|
||||
'entity_id': 'select.microwave_oven_power_level_w',
|
||||
'has_entity_name': True,
|
||||
'hidden_by': None,
|
||||
'icon': None,
|
||||
'id': <ANY>,
|
||||
'labels': set({
|
||||
}),
|
||||
'name': None,
|
||||
'options': dict({
|
||||
}),
|
||||
'original_device_class': None,
|
||||
'original_icon': None,
|
||||
'original_name': 'Power level (W)',
|
||||
'platform': 'matter',
|
||||
'previous_unique_id': None,
|
||||
'suggested_object_id': None,
|
||||
'supported_features': 0,
|
||||
'translation_key': 'power_level',
|
||||
'unique_id': '00000000000004D2-000000000000009D-MatterNodeDevice-1-MicrowaveOvenControlSelectedWattIndex-95-7',
|
||||
'unit_of_measurement': None,
|
||||
})
|
||||
# ---
|
||||
# name: test_selects[microwave_oven][select.microwave_oven_power_level_w-state]
|
||||
StateSnapshot({
|
||||
'attributes': ReadOnlyDict({
|
||||
'friendly_name': 'Microwave Oven Power level (W)',
|
||||
'options': list([
|
||||
'100',
|
||||
'200',
|
||||
'300',
|
||||
'400',
|
||||
'500',
|
||||
'600',
|
||||
'700',
|
||||
'800',
|
||||
'900',
|
||||
'1000',
|
||||
]),
|
||||
}),
|
||||
'context': <ANY>,
|
||||
'entity_id': 'select.microwave_oven_power_level_w',
|
||||
'last_changed': <ANY>,
|
||||
'last_reported': <ANY>,
|
||||
'last_updated': <ANY>,
|
||||
'state': '1000',
|
||||
})
|
||||
# ---
|
||||
# name: test_selects[mounted_dimmable_load_control_fixture][select.mock_mounted_dimmable_load_control_power_on_behavior_on_startup-entry]
|
||||
EntityRegistryEntrySnapshot({
|
||||
'aliases': set({
|
||||
|
@ -201,3 +201,36 @@ async def test_pump_level(
|
||||
), # 75 * 2 = 150, as the value is multiplied by 2 in the HA to native value conversion
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("node_fixture", ["microwave_oven"])
|
||||
async def test_microwave_oven(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
matter_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test Cooktime for microwave oven."""
|
||||
|
||||
# Cooktime on MicrowaveOvenControl cluster (1/96/2)
|
||||
state = hass.states.get("number.microwave_oven_cook_time")
|
||||
assert state
|
||||
assert state.state == "30"
|
||||
|
||||
# test set value
|
||||
await hass.services.async_call(
|
||||
"number",
|
||||
"set_value",
|
||||
{
|
||||
"entity_id": "number.microwave_oven_cook_time",
|
||||
"value": 60, # 60 seconds
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
assert matter_client.send_device_command.call_count == 1
|
||||
assert matter_client.send_device_command.call_args == call(
|
||||
node_id=matter_node.node_id,
|
||||
endpoint_id=1,
|
||||
command=clusters.MicrowaveOvenControl.Commands.SetCookingParameters(
|
||||
cookTime=60, # 60 seconds
|
||||
),
|
||||
)
|
||||
|
@ -235,3 +235,50 @@ async def test_pump(
|
||||
await trigger_subscription_callback(hass, matter_client)
|
||||
state = hass.states.get("select.mock_pump_mode")
|
||||
assert state.state == "local"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("node_fixture", ["microwave_oven"])
|
||||
async def test_microwave_oven(
|
||||
hass: HomeAssistant,
|
||||
matter_client: MagicMock,
|
||||
matter_node: MatterNode,
|
||||
) -> None:
|
||||
"""Test ListSelect entity is discovered and working from a microwave oven fixture."""
|
||||
|
||||
# SupportedWatts from MicrowaveOvenControl cluster (1/96/6)
|
||||
# SelectedWattIndex from MicrowaveOvenControl cluster (1/96/7)
|
||||
matter_client.write_attribute.reset_mock()
|
||||
state = hass.states.get("select.microwave_oven_power_level_w")
|
||||
assert state
|
||||
assert state.state == "1000"
|
||||
assert state.attributes["options"] == [
|
||||
"100",
|
||||
"200",
|
||||
"300",
|
||||
"400",
|
||||
"500",
|
||||
"600",
|
||||
"700",
|
||||
"800",
|
||||
"900",
|
||||
"1000",
|
||||
]
|
||||
|
||||
# test select option
|
||||
await hass.services.async_call(
|
||||
"select",
|
||||
"select_option",
|
||||
{
|
||||
"entity_id": "select.microwave_oven_power_level_w",
|
||||
"option": "900",
|
||||
},
|
||||
blocking=True,
|
||||
)
|
||||
assert matter_client.send_device_command.call_count == 1
|
||||
assert matter_client.send_device_command.call_args == call(
|
||||
node_id=matter_node.node_id,
|
||||
endpoint_id=1,
|
||||
command=clusters.MicrowaveOvenControl.Commands.SetCookingParameters(
|
||||
wattSettingIndex=8
|
||||
),
|
||||
)
|
||||
|
Loading…
x
Reference in New Issue
Block a user