Skip to content

Commit

Permalink
Add support for the Select platform in Matter (#119769)
Browse files Browse the repository at this point in the history
* Add support for ModeSelect Cluster

* Update discovery.py

* Add files via upload

* refactor part 1

* Update discovery.py

* add remaining mode discovery schemas

* add test

* type alias

---------

Co-authored-by: Marcel van der Veldt <[email protected]>
  • Loading branch information
jvmahon and marcelveldt authored Jul 4, 2024
1 parent 950c72a commit d5135d4
Show file tree
Hide file tree
Showing 6 changed files with 863 additions and 3 deletions.
5 changes: 3 additions & 2 deletions homeassistant/components/matter/discovery.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@

from __future__ import annotations

from collections.abc import Generator

from chip.clusters.Objects import ClusterAttributeDescriptor
from matter_server.client.models.node import MatterEndpoint
from typing_extensions import Generator

from homeassistant.const import Platform
from homeassistant.core import callback
Expand All @@ -19,6 +18,7 @@
from .lock import DISCOVERY_SCHEMAS as LOCK_SCHEMAS
from .models import MatterDiscoverySchema, MatterEntityInfo
from .number import DISCOVERY_SCHEMAS as NUMBER_SCHEMAS
from .select import DISCOVERY_SCHEMAS as SELECT_SCHEMAS
from .sensor import DISCOVERY_SCHEMAS as SENSOR_SCHEMAS
from .switch import DISCOVERY_SCHEMAS as SWITCH_SCHEMAS

Expand All @@ -33,6 +33,7 @@
Platform.NUMBER: NUMBER_SCHEMAS,
Platform.SENSOR: SENSOR_SCHEMAS,
Platform.SWITCH: SWITCH_SCHEMAS,
Platform.SELECT: SELECT_SCHEMAS,
}
SUPPORTED_PLATFORMS = tuple(DISCOVERY_SCHEMAS)

Expand Down
199 changes: 199 additions & 0 deletions homeassistant/components/matter/select.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
"""Matter ModeSelect Cluster Support."""

from __future__ import annotations

from chip.clusters import Objects as clusters

from homeassistant.components.select import SelectEntity, SelectEntityDescription
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import EntityCategory, Platform
from homeassistant.core import HomeAssistant, callback
from homeassistant.helpers.entity_platform import AddEntitiesCallback

from .entity import MatterEntity
from .helpers import get_matter
from .models import MatterDiscoverySchema

type SelectCluster = (
clusters.ModeSelect
| clusters.OvenMode
| clusters.LaundryWasherMode
| clusters.RefrigeratorAndTemperatureControlledCabinetMode
| clusters.RvcRunMode
| clusters.RvcCleanMode
| clusters.DishwasherMode
| clusters.MicrowaveOvenMode
| clusters.EnergyEvseMode
| clusters.DeviceEnergyManagementMode
)


async def async_setup_entry(
hass: HomeAssistant,
config_entry: ConfigEntry,
async_add_entities: AddEntitiesCallback,
) -> None:
"""Set up Matter ModeSelect from Config Entry."""
matter = get_matter(hass)
matter.register_platform_handler(Platform.SELECT, async_add_entities)


class MatterModeSelectEntity(MatterEntity, SelectEntity):
"""Representation of a select entity from Matter (Mode) Cluster attribute(s)."""

async def async_select_option(self, option: str) -> None:
"""Change the selected mode."""
cluster: SelectCluster = self._endpoint.get_cluster(
self._entity_info.primary_attribute.cluster_id
)
# select the mode ID from the label string
for mode in cluster.supportedModes:
if mode.label != option:
continue
await self.matter_client.send_device_command(
node_id=self._endpoint.node.node_id,
endpoint_id=self._endpoint.endpoint_id,
command=cluster.Commands.ChangeToMode(newMode=mode.mode),
)
break

@callback
def _update_from_device(self) -> None:
"""Update from device."""
# NOTE: cluster can be ModeSelect or a variant of that,
# such as DishwasherMode. They all have the same characteristics.
cluster: SelectCluster = self._endpoint.get_cluster(
self._entity_info.primary_attribute.cluster_id
)
modes = {mode.mode: mode.label for mode in cluster.supportedModes}
self._attr_options = list(modes.values())
self._attr_current_option = modes[cluster.currentMode]
# handle optional Description attribute as descriptive name for the mode
if desc := getattr(cluster, "description", None):
self._attr_name = desc


# Discovery schema(s) to map Matter Attributes to HA entities
DISCOVERY_SCHEMAS = [
MatterDiscoverySchema(
platform=Platform.SELECT,
entity_description=SelectEntityDescription(
key="MatterModeSelect",
entity_category=EntityCategory.CONFIG,
translation_key="mode",
),
entity_class=MatterModeSelectEntity,
required_attributes=(
clusters.ModeSelect.Attributes.CurrentMode,
clusters.ModeSelect.Attributes.SupportedModes,
),
),
MatterDiscoverySchema(
platform=Platform.SELECT,
entity_description=SelectEntityDescription(
key="MatterOvenMode",
translation_key="mode",
),
entity_class=MatterModeSelectEntity,
required_attributes=(
clusters.OvenMode.Attributes.CurrentMode,
clusters.OvenMode.Attributes.SupportedModes,
),
),
MatterDiscoverySchema(
platform=Platform.SELECT,
entity_description=SelectEntityDescription(
key="MatterLaundryWasherMode",
translation_key="mode",
),
entity_class=MatterModeSelectEntity,
required_attributes=(
clusters.LaundryWasherMode.Attributes.CurrentMode,
clusters.LaundryWasherMode.Attributes.SupportedModes,
),
),
MatterDiscoverySchema(
platform=Platform.SELECT,
entity_description=SelectEntityDescription(
key="MatterRefrigeratorAndTemperatureControlledCabinetMode",
translation_key="mode",
),
entity_class=MatterModeSelectEntity,
required_attributes=(
clusters.RefrigeratorAndTemperatureControlledCabinetMode.Attributes.CurrentMode,
clusters.RefrigeratorAndTemperatureControlledCabinetMode.Attributes.SupportedModes,
),
),
MatterDiscoverySchema(
platform=Platform.SELECT,
entity_description=SelectEntityDescription(
key="MatterRvcRunMode",
translation_key="mode",
),
entity_class=MatterModeSelectEntity,
required_attributes=(
clusters.RvcRunMode.Attributes.CurrentMode,
clusters.RvcRunMode.Attributes.SupportedModes,
),
),
MatterDiscoverySchema(
platform=Platform.SELECT,
entity_description=SelectEntityDescription(
key="MatterRvcCleanMode",
translation_key="mode",
),
entity_class=MatterModeSelectEntity,
required_attributes=(
clusters.RvcCleanMode.Attributes.CurrentMode,
clusters.RvcCleanMode.Attributes.SupportedModes,
),
),
MatterDiscoverySchema(
platform=Platform.SELECT,
entity_description=SelectEntityDescription(
key="MatterDishwasherMode",
translation_key="mode",
),
entity_class=MatterModeSelectEntity,
required_attributes=(
clusters.DishwasherMode.Attributes.CurrentMode,
clusters.DishwasherMode.Attributes.SupportedModes,
),
),
MatterDiscoverySchema(
platform=Platform.SELECT,
entity_description=SelectEntityDescription(
key="MatterMicrowaveOvenMode",
translation_key="mode",
),
entity_class=MatterModeSelectEntity,
required_attributes=(
clusters.MicrowaveOvenMode.Attributes.CurrentMode,
clusters.MicrowaveOvenMode.Attributes.SupportedModes,
),
),
MatterDiscoverySchema(
platform=Platform.SELECT,
entity_description=SelectEntityDescription(
key="MatterEnergyEvseMode",
translation_key="mode",
),
entity_class=MatterModeSelectEntity,
required_attributes=(
clusters.EnergyEvseMode.Attributes.CurrentMode,
clusters.EnergyEvseMode.Attributes.SupportedModes,
),
),
MatterDiscoverySchema(
platform=Platform.SELECT,
entity_description=SelectEntityDescription(
key="MatterDeviceEnergyManagementMode",
translation_key="mode",
),
entity_class=MatterModeSelectEntity,
required_attributes=(
clusters.DeviceEnergyManagementMode.Attributes.CurrentMode,
clusters.DeviceEnergyManagementMode.Attributes.SupportedModes,
),
),
]
5 changes: 5 additions & 0 deletions homeassistant/components/matter/strings.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,11 @@
"name": "[%key:component::lock::title%]"
}
},
"select": {
"mode": {
"name": "Mode"
}
},
"sensor": {
"activated_carbon_filter_condition": {
"name": "Activated carbon filter condition"
Expand Down
143 changes: 142 additions & 1 deletion tests/components/matter/fixtures/nodes/dimmable-light.json
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,148 @@
"1/29/65533": 1,
"1/29/65528": [],
"1/29/65529": [],
"1/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533]
"1/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533],
"6/80/0": "LED Color",
"6/80/1": 0,
"6/80/2": [
{
"0": "Red",
"1": 0,
"2": [
{
"0": 0,
"1": 0
}
]
},
{
"0": "Orange",
"1": 1,
"2": [
{
"0": 0,
"1": 0
}
]
},
{
"0": "Lemon",
"1": 2,
"2": [
{
"0": 0,
"1": 0
}
]
},
{
"0": "Lime",
"1": 3,
"2": [
{
"0": 0,
"1": 0
}
]
},
{
"0": "Green",
"1": 4,
"2": [
{
"0": 0,
"1": 0
}
]
},
{
"0": "Teal",
"1": 5,
"2": [
{
"0": 0,
"1": 0
}
]
},
{
"0": "Cyan",
"1": 6,
"2": [
{
"0": 0,
"1": 0
}
]
},
{
"0": "Aqua",
"1": 7,
"2": [
{
"0": 0,
"1": 0
}
]
},
{
"0": "Blue",
"1": 8,
"2": [
{
"0": 0,
"1": 0
}
]
},
{
"0": "Violet",
"1": 9,
"2": [
{
"0": 0,
"1": 0
}
]
},
{
"0": "Magenta",
"1": 10,
"2": [
{
"0": 0,
"1": 0
}
]
},
{
"0": "Pink",
"1": 11,
"2": [
{
"0": 0,
"1": 0
}
]
},
{
"0": "White",
"1": 12,
"2": [
{
"0": 0,
"1": 0
}
]
}
],
"6/80/3": 7,
"6/80/65532": 0,
"6/80/65533": 1,
"6/80/65528": [],
"6/80/65529": [0],
"6/80/65530": [],
"6/80/65531": [0, 1, 2, 3, 65528, 65529, 65530, 65531, 65532, 65533]
},
"available": true,
"attribute_subscriptions": []
Expand Down
Loading

0 comments on commit d5135d4

Please sign in to comment.