From 3c60bff7dc737d947af995c0008f3b5e7373325f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ludovic=20BOU=C3=89?= Date: Fri, 4 Apr 2025 17:57:22 +0200 Subject: [PATCH] Add support for Matter EVSE devicetype (#137189) * Binary sensors * Add tests * Update strings * Enable testing * Add command_timeout to MatterEntityDescription * Add entities * Update strings.json * Add sensors * Add tests * Move command_timeout keyword to MatterGenericCommandSwitch * Icons * Update snapshots * Add tests for switch entity * Fix switch tests * Rename states * Update strings.json * Update snapshot * Rename charging switch * Remove MatterEntity * Update strings.json * Update snapshots * Update snaphots 2/2 * Update strings * Update test binary --- .../components/matter/binary_sensor.py | 57 ++ homeassistant/components/matter/entity.py | 1 + homeassistant/components/matter/icons.json | 12 + homeassistant/components/matter/sensor.py | 92 +++ homeassistant/components/matter/strings.json | 48 ++ homeassistant/components/matter/switch.py | 91 +++ tests/components/matter/conftest.py | 1 + .../fixtures/nodes/silabs_evse_charging.json | 580 ++++++++++++++++++ .../matter/snapshots/test_binary_sensor.ambr | 144 +++++ .../matter/snapshots/test_select.ambr | 122 ++++ .../matter/snapshots/test_sensor.ambr | 317 ++++++++++ .../matter/snapshots/test_switch.ambr | 47 ++ tests/components/matter/test_binary_sensor.py | 50 ++ tests/components/matter/test_sensor.py | 68 ++ tests/components/matter/test_switch.py | 44 ++ 15 files changed, 1674 insertions(+) create mode 100644 tests/components/matter/fixtures/nodes/silabs_evse_charging.json diff --git a/homeassistant/components/matter/binary_sensor.py b/homeassistant/components/matter/binary_sensor.py index b5665e5d47a..a55df58cac7 100644 --- a/homeassistant/components/matter/binary_sensor.py +++ b/homeassistant/components/matter/binary_sensor.py @@ -265,4 +265,61 @@ DISCOVERY_SCHEMAS = [ entity_class=MatterBinarySensor, required_attributes=(clusters.SmokeCoAlarm.Attributes.InterconnectCOAlarm,), ), + MatterDiscoverySchema( + platform=Platform.BINARY_SENSOR, + entity_description=MatterBinarySensorEntityDescription( + key="EnergyEvseChargingStatusSensor", + translation_key="evse_charging_status", + device_class=BinarySensorDeviceClass.BATTERY_CHARGING, + measurement_to_ha={ + clusters.EnergyEvse.Enums.StateEnum.kNotPluggedIn: False, + clusters.EnergyEvse.Enums.StateEnum.kPluggedInNoDemand: False, + clusters.EnergyEvse.Enums.StateEnum.kPluggedInDemand: False, + clusters.EnergyEvse.Enums.StateEnum.kPluggedInCharging: True, + clusters.EnergyEvse.Enums.StateEnum.kPluggedInDischarging: False, + clusters.EnergyEvse.Enums.StateEnum.kSessionEnding: False, + clusters.EnergyEvse.Enums.StateEnum.kFault: False, + }.get, + ), + entity_class=MatterBinarySensor, + required_attributes=(clusters.EnergyEvse.Attributes.State,), + allow_multi=True, # also used for sensor entity + ), + MatterDiscoverySchema( + platform=Platform.BINARY_SENSOR, + entity_description=MatterBinarySensorEntityDescription( + key="EnergyEvsePlugStateSensor", + translation_key="evse_plug_state", + device_class=BinarySensorDeviceClass.PLUG, + measurement_to_ha={ + clusters.EnergyEvse.Enums.StateEnum.kNotPluggedIn: False, + clusters.EnergyEvse.Enums.StateEnum.kPluggedInNoDemand: True, + clusters.EnergyEvse.Enums.StateEnum.kPluggedInDemand: True, + clusters.EnergyEvse.Enums.StateEnum.kPluggedInCharging: True, + clusters.EnergyEvse.Enums.StateEnum.kPluggedInDischarging: True, + clusters.EnergyEvse.Enums.StateEnum.kSessionEnding: False, + clusters.EnergyEvse.Enums.StateEnum.kFault: False, + }.get, + ), + entity_class=MatterBinarySensor, + required_attributes=(clusters.EnergyEvse.Attributes.State,), + allow_multi=True, # also used for sensor entity + ), + MatterDiscoverySchema( + platform=Platform.BINARY_SENSOR, + entity_description=MatterBinarySensorEntityDescription( + key="EnergyEvseSupplyStateSensor", + translation_key="evse_supply_charging_state", + device_class=BinarySensorDeviceClass.RUNNING, + measurement_to_ha={ + clusters.EnergyEvse.Enums.SupplyStateEnum.kDisabled: False, + clusters.EnergyEvse.Enums.SupplyStateEnum.kChargingEnabled: True, + clusters.EnergyEvse.Enums.SupplyStateEnum.kDischargingEnabled: False, + clusters.EnergyEvse.Enums.SupplyStateEnum.kDisabledDiagnostics: False, + }.get, + ), + entity_class=MatterBinarySensor, + required_attributes=(clusters.EnergyEvse.Attributes.SupplyState,), + allow_multi=True, # also used for sensor entity + ), ] diff --git a/homeassistant/components/matter/entity.py b/homeassistant/components/matter/entity.py index 96696193466..fded57d34f5 100644 --- a/homeassistant/components/matter/entity.py +++ b/homeassistant/components/matter/entity.py @@ -61,6 +61,7 @@ class MatterEntityDescription(EntityDescription): # convert the value from the primary attribute to the value used by HA measurement_to_ha: Callable[[Any], Any] | None = None ha_to_native_value: Callable[[Any], Any] | None = None + command_timeout: int | None = None class MatterEntity(Entity): diff --git a/homeassistant/components/matter/icons.json b/homeassistant/components/matter/icons.json index f9217cabcc4..fed51708870 100644 --- a/homeassistant/components/matter/icons.json +++ b/homeassistant/components/matter/icons.json @@ -71,6 +71,15 @@ }, "battery_replacement_description": { "default": "mdi:battery-sync-outline" + }, + "evse_state": { + "default": "mdi:ev-station" + }, + "evse_supply_state": { + "default": "mdi:ev-station" + }, + "evse_fault_state": { + "default": "mdi:ev-station" } }, "switch": { @@ -80,6 +89,9 @@ "on": "mdi:lock", "off": "mdi:lock-off" } + }, + "evse_charging_switch": { + "default": "mdi:ev-station" } } } diff --git a/homeassistant/components/matter/sensor.py b/homeassistant/components/matter/sensor.py index 10f8db275f5..82d8ec1727c 100644 --- a/homeassistant/components/matter/sensor.py +++ b/homeassistant/components/matter/sensor.py @@ -77,6 +77,25 @@ OPERATIONAL_STATE_MAP = { clusters.RvcOperationalState.Enums.OperationalStateEnum.kDocked: "docked", } +EVSE_FAULT_STATE_MAP = { + clusters.EnergyEvse.Enums.FaultStateEnum.kNoError: "no_error", + clusters.EnergyEvse.Enums.FaultStateEnum.kMeterFailure: "meter_failure", + clusters.EnergyEvse.Enums.FaultStateEnum.kOverVoltage: "over_voltage", + clusters.EnergyEvse.Enums.FaultStateEnum.kUnderVoltage: "under_voltage", + clusters.EnergyEvse.Enums.FaultStateEnum.kOverCurrent: "over_current", + clusters.EnergyEvse.Enums.FaultStateEnum.kContactWetFailure: "contact_wet_failure", + clusters.EnergyEvse.Enums.FaultStateEnum.kContactDryFailure: "contact_dry_failure", + clusters.EnergyEvse.Enums.FaultStateEnum.kPowerLoss: "power_loss", + clusters.EnergyEvse.Enums.FaultStateEnum.kPowerQuality: "power_quality", + clusters.EnergyEvse.Enums.FaultStateEnum.kPilotShortCircuit: "pilot_short_circuit", + clusters.EnergyEvse.Enums.FaultStateEnum.kEmergencyStop: "emergency_stop", + clusters.EnergyEvse.Enums.FaultStateEnum.kEVDisconnected: "ev_disconnected", + clusters.EnergyEvse.Enums.FaultStateEnum.kWrongPowerSupply: "wrong_power_supply", + clusters.EnergyEvse.Enums.FaultStateEnum.kLiveNeutralSwap: "live_neutral_swap", + clusters.EnergyEvse.Enums.FaultStateEnum.kOverTemperature: "over_temperature", + clusters.EnergyEvse.Enums.FaultStateEnum.kOther: "other", +} + async def async_setup_entry( hass: HomeAssistant, @@ -904,4 +923,77 @@ 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="EnergyEvseFaultState", + translation_key="evse_fault_state", + device_class=SensorDeviceClass.ENUM, + entity_category=EntityCategory.DIAGNOSTIC, + options=list(EVSE_FAULT_STATE_MAP.values()), + measurement_to_ha=EVSE_FAULT_STATE_MAP.get, + ), + entity_class=MatterSensor, + required_attributes=(clusters.EnergyEvse.Attributes.FaultState,), + ), + MatterDiscoverySchema( + platform=Platform.SENSOR, + entity_description=MatterSensorEntityDescription( + key="EnergyEvseCircuitCapacity", + translation_key="evse_circuit_capacity", + device_class=SensorDeviceClass.CURRENT, + entity_category=EntityCategory.DIAGNOSTIC, + native_unit_of_measurement=UnitOfElectricCurrent.MILLIAMPERE, + suggested_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + suggested_display_precision=2, + state_class=SensorStateClass.MEASUREMENT, + ), + entity_class=MatterSensor, + required_attributes=(clusters.EnergyEvse.Attributes.CircuitCapacity,), + ), + MatterDiscoverySchema( + platform=Platform.SENSOR, + entity_description=MatterSensorEntityDescription( + key="EnergyEvseMinimumChargeCurrent", + translation_key="evse_min_charge_current", + device_class=SensorDeviceClass.CURRENT, + entity_category=EntityCategory.DIAGNOSTIC, + native_unit_of_measurement=UnitOfElectricCurrent.MILLIAMPERE, + suggested_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + suggested_display_precision=2, + state_class=SensorStateClass.MEASUREMENT, + ), + entity_class=MatterSensor, + required_attributes=(clusters.EnergyEvse.Attributes.MinimumChargeCurrent,), + ), + MatterDiscoverySchema( + platform=Platform.SENSOR, + entity_description=MatterSensorEntityDescription( + key="EnergyEvseMaximumChargeCurrent", + translation_key="evse_max_charge_current", + device_class=SensorDeviceClass.CURRENT, + entity_category=EntityCategory.DIAGNOSTIC, + native_unit_of_measurement=UnitOfElectricCurrent.MILLIAMPERE, + suggested_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + suggested_display_precision=2, + state_class=SensorStateClass.MEASUREMENT, + ), + entity_class=MatterSensor, + required_attributes=(clusters.EnergyEvse.Attributes.MaximumChargeCurrent,), + ), + MatterDiscoverySchema( + platform=Platform.SENSOR, + entity_description=MatterSensorEntityDescription( + key="EnergyEvseUserMaximumChargeCurrent", + translation_key="evse_user_max_charge_current", + device_class=SensorDeviceClass.CURRENT, + entity_category=EntityCategory.DIAGNOSTIC, + native_unit_of_measurement=UnitOfElectricCurrent.MILLIAMPERE, + suggested_unit_of_measurement=UnitOfElectricCurrent.AMPERE, + suggested_display_precision=2, + state_class=SensorStateClass.MEASUREMENT, + ), + entity_class=MatterSensor, + required_attributes=(clusters.EnergyEvse.Attributes.UserMaximumChargeCurrent,), + ), ] diff --git a/homeassistant/components/matter/strings.json b/homeassistant/components/matter/strings.json index 81a9a4ba796..4fa49f887d9 100644 --- a/homeassistant/components/matter/strings.json +++ b/homeassistant/components/matter/strings.json @@ -76,6 +76,15 @@ }, "muted": { "name": "Muted" + }, + "evse_charging_status": { + "name": "Charging status" + }, + "evse_plug": { + "name": "Plug state" + }, + "evse_supply_charging_state": { + "name": "Supply charging state" } }, "button": { @@ -278,6 +287,42 @@ }, "current_phase": { "name": "Current phase" + }, + "evse_fault_state": { + "name": "Fault state", + "state": { + "no_error": "OK", + "meter_failure": "Meter failure", + "over_voltage": "Overvoltage", + "under_voltage": "Undervoltage", + "over_current": "Overcurrent", + "contact_wet_failure": "Contact wet failure", + "contact_dry_failure": "Contact dry failure", + "power_loss": "Power loss", + "power_quality": "Power quality", + "pilot_short_circuit": "Pilot short circuit", + "emergency_stop": "Emergency stop", + "ev_disconnected": "EV disconnected", + "wrong_power_supply": "Wrong power supply", + "live_neutral_swap": "Live/neutral swap", + "over_temperature": "Overtemperature", + "other": "Other fault" + } + }, + "evse_circuit_capacity": { + "name": "Circuit capacity" + }, + "evse_charge_current": { + "name": "Charge current" + }, + "evse_min_charge_current": { + "name": "Min charge current" + }, + "evse_max_charge_current": { + "name": "Max charge current" + }, + "evse_user_max_charge_current": { + "name": "User max charge current" } }, "switch": { @@ -289,6 +334,9 @@ }, "child_lock": { "name": "Child lock" + }, + "evse_charging_switch": { + "name": "Enable charging" } }, "vacuum": { diff --git a/homeassistant/components/matter/switch.py b/homeassistant/components/matter/switch.py index af4803af9a1..870a9098492 100644 --- a/homeassistant/components/matter/switch.py +++ b/homeassistant/components/matter/switch.py @@ -2,10 +2,12 @@ from __future__ import annotations +from collections.abc import Callable from dataclasses import dataclass from typing import Any from chip.clusters import Objects as clusters +from chip.clusters.Objects import ClusterCommand, NullValue from matter_server.client.models import device_types from homeassistant.components.switch import ( @@ -22,6 +24,13 @@ from .entity import MatterEntity, MatterEntityDescription from .helpers import get_matter from .models import MatterDiscoverySchema +EVSE_SUPPLY_STATE_MAP = { + clusters.EnergyEvse.Enums.SupplyStateEnum.kDisabled: False, + clusters.EnergyEvse.Enums.SupplyStateEnum.kChargingEnabled: True, + clusters.EnergyEvse.Enums.SupplyStateEnum.kDischargingEnabled: False, + clusters.EnergyEvse.Enums.SupplyStateEnum.kDisabledDiagnostics: False, +} + async def async_setup_entry( hass: HomeAssistant, @@ -58,6 +67,66 @@ class MatterSwitch(MatterEntity, SwitchEntity): ) +class MatterGenericCommandSwitch(MatterSwitch): + """Representation of a Matter switch.""" + + entity_description: MatterGenericCommandSwitchEntityDescription + + _platform_translation_key = "switch" + + async def async_turn_on(self, **kwargs: Any) -> None: + """Turn switch on.""" + if self.entity_description.on_command: + # custom command defined to set the new value + await self.send_device_command( + self.entity_description.on_command(), + self.entity_description.command_timeout, + ) + + async def async_turn_off(self, **kwargs: Any) -> None: + """Turn switch off.""" + if self.entity_description.off_command: + await self.send_device_command( + self.entity_description.off_command(), + self.entity_description.command_timeout, + ) + + @callback + def _update_from_device(self) -> None: + """Update from device.""" + value = self.get_matter_attribute_value(self._entity_info.primary_attribute) + if value_convert := self.entity_description.measurement_to_ha: + value = value_convert(value) + self._attr_is_on = value + + async def send_device_command( + self, + command: ClusterCommand, + command_timeout: int | None = None, + **kwargs: Any, + ) -> None: + """Send device command with timeout.""" + await self.matter_client.send_device_command( + node_id=self._endpoint.node.node_id, + endpoint_id=self._endpoint.endpoint_id, + command=command, + timed_request_timeout_ms=command_timeout, + **kwargs, + ) + + +@dataclass(frozen=True) +class MatterGenericCommandSwitchEntityDescription( + SwitchEntityDescription, MatterEntityDescription +): + """Describe Matter Generic command Switch entities.""" + + # command: a custom callback to create the command to send to the device + on_command: Callable[[], Any] | None = None + off_command: Callable[[], Any] | None = None + command_timeout: int | None = None + + @dataclass(frozen=True) class MatterNumericSwitchEntityDescription( SwitchEntityDescription, MatterEntityDescription @@ -194,4 +263,26 @@ DISCOVERY_SCHEMAS = [ ), vendor_id=(4874,), ), + MatterDiscoverySchema( + platform=Platform.SWITCH, + entity_description=MatterGenericCommandSwitchEntityDescription( + key="EnergyEvseChargingSwitch", + translation_key="evse_charging_switch", + on_command=lambda: clusters.EnergyEvse.Commands.EnableCharging( + chargingEnabledUntil=NullValue, + minimumChargeCurrent=0, + maximumChargeCurrent=0, + ), + off_command=clusters.EnergyEvse.Commands.Disable, + command_timeout=3000, + measurement_to_ha=EVSE_SUPPLY_STATE_MAP.get, + ), + entity_class=MatterGenericCommandSwitch, + required_attributes=( + clusters.EnergyEvse.Attributes.SupplyState, + clusters.EnergyEvse.Attributes.AcceptedCommandList, + ), + value_contains=clusters.EnergyEvse.Commands.EnableCharging.command_id, + allow_multi=True, + ), ] diff --git a/tests/components/matter/conftest.py b/tests/components/matter/conftest.py index d7429f6087d..a085a1e3540 100644 --- a/tests/components/matter/conftest.py +++ b/tests/components/matter/conftest.py @@ -104,6 +104,7 @@ async def integration_fixture( "pressure_sensor", "room_airconditioner", "silabs_dishwasher", + "silabs_evse_charging", "silabs_laundrywasher", "smoke_detector", "switch_unit", diff --git a/tests/components/matter/fixtures/nodes/silabs_evse_charging.json b/tests/components/matter/fixtures/nodes/silabs_evse_charging.json new file mode 100644 index 00000000000..3188ba81ad6 --- /dev/null +++ b/tests/components/matter/fixtures/nodes/silabs_evse_charging.json @@ -0,0 +1,580 @@ +{ + "node_id": 23, + "date_commissioned": "2024-12-17T18:14:53.210190", + "last_interview": "2024-12-17T18:14:53.211611", + "interview_version": 6, + "available": true, + "is_bridge": false, + "attributes": { + "0/29/0": [ + { + "0": 22, + "1": 1 + } + ], + "0/29/1": [29, 31, 40, 43, 44, 45, 48, 49, 51, 60, 62, 63], + "0/29/2": [], + "0/29/3": [1], + "0/29/65532": 0, + "0/29/65533": 2, + "0/29/65528": [], + "0/29/65529": [], + "0/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "0/31/0": [ + { + "1": 5, + "2": 2, + "3": [112233], + "4": null, + "254": 1 + } + ], + "0/31/2": 4, + "0/31/3": 3, + "0/31/4": 4, + "0/31/65532": 0, + "0/31/65533": 2, + "0/31/65528": [], + "0/31/65529": [], + "0/31/65531": [0, 2, 3, 4, 65528, 65529, 65531, 65532, 65533], + "0/40/0": 18, + "0/40/1": "Silabs", + "0/40/2": 65521, + "0/40/3": "evse", + "0/40/4": 32769, + "0/40/5": "evse", + "0/40/6": "**REDACTED**", + "0/40/7": 0, + "0/40/8": "TEST_VERSION", + "0/40/9": 1, + "0/40/10": "1.0", + "0/40/15": "TEST_SN", + "0/40/18": "evse", + "0/40/19": { + "0": 3, + "1": 65535 + }, + "0/40/21": 17039360, + "0/40/22": 1, + "0/40/65532": 0, + "0/40/65533": 4, + "0/40/65528": [], + "0/40/65529": [], + "0/40/65531": [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 15, 18, 19, 21, 22, 65528, 65529, 65531, + 65532, 65533 + ], + "0/43/0": "en-US", + "0/43/1": [ + "en-US", + "de-DE", + "fr-FR", + "en-GB", + "es-ES", + "zh-CN", + "it-IT", + "ja-JP" + ], + "0/43/65532": 0, + "0/43/65533": 1, + "0/43/65528": [], + "0/43/65529": [], + "0/43/65531": [0, 1, 65528, 65529, 65531, 65532, 65533], + "0/44/0": 0, + "0/44/65532": 0, + "0/44/65533": 1, + "0/44/65528": [], + "0/44/65529": [], + "0/44/65531": [0, 65528, 65529, 65531, 65532, 65533], + "0/45/65532": 0, + "0/45/65533": 1, + "0/45/65528": [], + "0/45/65529": [], + "0/45/65531": [65528, 65529, 65531, 65532, 65533], + "0/48/0": 0, + "0/48/1": { + "0": 60, + "1": 900 + }, + "0/48/2": 0, + "0/48/3": 2, + "0/48/4": true, + "0/48/65532": 0, + "0/48/65533": 2, + "0/48/65528": [1, 3, 5], + "0/48/65529": [0, 2, 4], + "0/48/65531": [0, 1, 2, 3, 4, 65528, 65529, 65531, 65532, 65533], + "0/49/0": 1, + "0/49/1": [ + { + "0": "ZW5zMzM=", + "1": true + } + ], + "0/49/4": true, + "0/49/5": null, + "0/49/6": null, + "0/49/7": null, + "0/49/8": [0], + "0/49/65532": 4, + "0/49/65533": 2, + "0/49/65528": [], + "0/49/65529": [], + "0/49/65531": [0, 1, 4, 5, 6, 7, 8, 65528, 65529, 65531, 65532, 65533], + "0/51/0": [ + { + "0": "docker0", + "1": false, + "2": null, + "3": null, + "4": "AkI9NTnB", + "5": ["rBEAAQ=="], + "6": [""], + "7": 0 + }, + { + "0": "ens33", + "1": true, + "2": null, + "3": null, + "4": "AAwp/F0T", + "5": ["wKgBpw=="], + "6": [ + "KgEOCgKzOZCNB+q+Uz0I9w==", + "KgEOCgKzOZC/O1Ew1WvS4A==", + "/oAAAAAAAADml3Ozl7GZug==" + ], + "7": 2 + }, + { + "0": "lo", + "1": true, + "2": null, + "3": null, + "4": "AAAAAAAA", + "5": ["fwAAAQ=="], + "6": ["AAAAAAAAAAAAAAAAAAAAAQ=="], + "7": 0 + } + ], + "0/51/1": 1, + "0/51/2": 10129, + "0/51/8": true, + "0/51/65532": 0, + "0/51/65533": 2, + "0/51/65528": [2], + "0/51/65529": [0, 1], + "0/51/65531": [0, 1, 2, 8, 65528, 65529, 65531, 65532, 65533], + "0/60/0": 0, + "0/60/1": null, + "0/60/2": null, + "0/60/65532": 0, + "0/60/65533": 1, + "0/60/65528": [], + "0/60/65529": [0, 2], + "0/60/65531": [0, 1, 2, 65528, 65529, 65531, 65532, 65533], + "0/62/0": [ + { + "1": "FTABAQEkAgE3AyQTAhgmBIAigScmBYAlTTo3BiQVASQRFxgkBwEkCAEwCUEECp4PASYUFk/DwQqGNBikYdiBRDJZbrfF4AYK8Y9jOeIpx7Xy+giJhmTpAVZ662hwszsFDGULGY/owXtMrqTxEDcKNQEoARgkAgE2AwQCBAEYMAQUqBmxO16fPQhbf33Gb2XwQ+NkXpswBRTx8+4bdkuqlxInfB5LXkhRBBvS2hgwC0A8aefsLm663Vuy+TkSvn/oLhRqt2phrG+i5aM5o15xiWDjnNVdUYpT09+K0mgVoMdFuFsmoWQxQh6jahaFJzUgGA==", + "2": "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQTAhgkBwEkCAEwCUEEGp55xGRB0FBQ3Yw7ayQSzVtYA0BtCJFm9vRRcdr+nk0cuGX6zrUowSYOO/qiRBEACcCNNSqKh+DpRm2uVLOtaDcKNQEpARgkAmAwBBTx8+4bdkuqlxInfB5LXkhRBBvS2jAFFIxTG68U5WQVsk8AtvSQyeK3KLqPGDALQIw/6q5ILMNdOMcSif8HNbEgpjBeaBMfUpzOJFCRPM16sv1xiq3mALZj0u+iG8lUJEvDJOFKPoBvsOubwIwRgAQY", + "254": 1 + } + ], + "0/62/1": [ + { + "1": "BMeyHMXjJpVWF9saehBu7pZLTwdopKZTl5JdhU0/ozZ/sk1paVFE1U8OtuZqM/S/4W/fnkCnUrQ/Xcs7Ddy0hPE=", + "2": 65521, + "3": 1, + "4": 23, + "5": "HA_test", + "254": 1 + }, + { + "1": "BBF47gm4BEBA6LXQluAHjn6P3+MZKrhuMcJligg1xcBM7X++F7GsZFh4hYAhdmD9HHwhtZxH2c85aAzbpikViwI=", + "2": 65521, + "3": 1, + "4": 100, + "5": "", + "254": 2 + } + ], + "0/62/2": 16, + "0/62/3": 2, + "0/62/4": [ + "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEEx7IcxeMmlVYX2xp6EG7ulktPB2ikplOXkl2FTT+jNn+yTWlpUUTVTw625moz9L/hb9+eQKdStD9dyzsN3LSE8TcKNQEpARgkAmAwBBSMUxuvFOVkFbJPALb0kMnityi6jzAFFIxTG68U5WQVsk8AtvSQyeK3KLqPGDALQPBVUg+OBUWl1pe/k55ZigAZl3lfBP1Qd5zQP4AUB45mNTzdli8DRCj+h7cIs3JHQQPlUaRvG5xUoBZ+C7Gg2sQY", + "FTABAQEkAgE3AyQUARgmBIAigScmBYAlTTo3BiQUARgkBwEkCAEwCUEEEXjuCbgEQEDotdCW4AeOfo/f4xkquG4xwmWKCDXFwEztf74XsaxkWHiFgCF2YP0cfCG1nEfZzzloDNumKRWLAjcKNQEpARgkAmAwBBQD3rx0jOdkiCPt06hxW7Z2jJBPXTAFFAPevHSM52SII+3TqHFbtnaMkE9dGDALQL+L3Zc6En6Ionk6WIz+lM50iwOEzTi9VwyYQRUdtO99T8jRX52+Olh6zcUtWQuYO2XYiH2OZ8lM4guqqnS8U4UY" + ], + "0/62/5": 1, + "0/62/65532": 0, + "0/62/65533": 1, + "0/62/65528": [1, 3, 5, 8], + "0/62/65529": [0, 2, 4, 6, 7, 9, 10, 11], + "0/62/65531": [0, 1, 2, 3, 4, 5, 65528, 65529, 65531, 65532, 65533], + "0/63/0": [], + "0/63/1": [], + "0/63/2": 4, + "0/63/3": 3, + "0/63/65532": 0, + "0/63/65533": 2, + "0/63/65528": [2, 5], + "0/63/65529": [0, 1, 3, 4], + "0/63/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "1/3/0": 0, + "1/3/1": 0, + "1/3/65532": 0, + "1/3/65533": 5, + "1/3/65528": [], + "1/3/65529": [0, 64], + "1/3/65531": [0, 1, 65528, 65529, 65531, 65532, 65533], + "1/29/0": [ + { + "0": 1293, + "1": 1 + }, + { + "0": 1292, + "1": 1 + }, + { + "0": 1296, + "1": 1 + }, + { + "0": 17, + "1": 1 + } + ], + "1/29/1": [3, 29, 47, 144, 145, 152, 153, 156, 157, 159], + "1/29/2": [], + "1/29/3": [], + "1/29/65532": 0, + "1/29/65533": 2, + "1/29/65528": [], + "1/29/65529": [], + "1/29/65531": [0, 1, 2, 3, 65528, 65529, 65531, 65532, 65533], + "1/47/0": 1, + "1/47/1": 0, + "1/47/2": "Primary Mains Power", + "1/47/5": 0, + "1/47/7": 230000, + "1/47/8": 32000, + "1/47/31": [1], + "1/47/65532": 1, + "1/47/65533": 3, + "1/47/65528": [], + "1/47/65529": [], + "1/47/65531": [0, 1, 2, 5, 7, 8, 31, 65528, 65529, 65531, 65532, 65533], + "1/144/0": 2, + "1/144/1": 3, + "1/144/2": [ + { + "0": 5, + "1": true, + "2": -50000000, + "3": 50000000, + "4": [ + { + "0": -50000000, + "1": -10000000, + "2": 5000, + "3": 2000, + "4": 3000 + }, + { + "0": -9999999, + "1": 9999999, + "2": 1000, + "3": 100, + "4": 500 + }, + { + "0": 10000000, + "1": 50000000, + "2": 5000, + "3": 2000, + "4": 3000 + } + ] + }, + { + "0": 2, + "1": true, + "2": -100000, + "3": 100000, + "4": [ + { + "0": -100000, + "1": -5000, + "2": 5000, + "3": 2000, + "4": 3000 + }, + { + "0": -4999, + "1": 4999, + "2": 1000, + "3": 100, + "4": 500 + }, + { + "0": 5000, + "1": 100000, + "2": 5000, + "3": 2000, + "4": 3000 + } + ] + }, + { + "0": 1, + "1": true, + "2": -500000, + "3": 500000, + "4": [ + { + "0": -500000, + "1": -100000, + "2": 5000, + "3": 2000, + "4": 3000 + }, + { + "0": -99999, + "1": 99999, + "2": 1000, + "3": 100, + "4": 500 + }, + { + "0": 100000, + "1": 500000, + "2": 5000, + "3": 2000, + "4": 3000 + } + ] + } + ], + "1/144/3": [], + "1/144/4": null, + "1/144/5": null, + "1/144/6": null, + "1/144/7": null, + "1/144/8": null, + "1/144/9": null, + "1/144/10": null, + "1/144/11": null, + "1/144/12": null, + "1/144/13": null, + "1/144/14": null, + "1/144/15": [ + { + "0": 1, + "1": 100000 + } + ], + "1/144/16": [ + { + "0": 1, + "1": 100000 + } + ], + "1/144/17": null, + "1/144/18": null, + "1/144/65532": 31, + "1/144/65533": 1, + "1/144/65528": [], + "1/144/65529": [], + "1/144/65531": [ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 65528, + 65529, 65531, 65532, 65533 + ], + "1/145/0": { + "0": 14, + "1": true, + "2": 0, + "3": 1000000000000000, + "4": [ + { + "0": 98440650424323, + "1": 98442759724168, + "2": 0, + "3": 0, + "5": 140728898420739, + "6": 98440650424355 + } + ] + }, + "1/145/1": null, + "1/145/2": null, + "1/145/3": null, + "1/145/4": null, + "1/145/5": { + "0": 0, + "1": 0, + "2": 0, + "3": 0 + }, + "1/145/65532": 15, + "1/145/65533": 1, + "1/145/65528": [], + "1/145/65529": [], + "1/145/65531": [0, 1, 2, 3, 4, 5, 65528, 65529, 65531, 65532, 65533], + "1/152/0": 0, + "1/152/1": false, + "1/152/2": 1, + "1/152/3": 1200000, + "1/152/4": 7600000, + "1/152/5": null, + "1/152/6": null, + "1/152/7": 0, + "1/152/65532": 123, + "1/152/65533": 4, + "1/152/65528": [], + "1/152/65529": [0, 1, 2, 3, 4, 5, 6, 7], + "1/152/65531": [0, 1, 2, 3, 4, 5, 6, 7, 65528, 65529, 65531, 65532, 65533], + "1/153/0": 3, + "1/153/1": 1, + "1/153/2": 0, + "1/153/3": null, + "1/153/5": 32000, + "1/153/6": 2000, + "1/153/7": 30000, + "1/153/9": 32000, + "1/153/10": 600, + "1/153/35": null, + "1/153/36": null, + "1/153/37": null, + "1/153/38": null, + "1/153/39": null, + "1/153/64": 2, + "1/153/65": 0, + "1/153/66": 0, + "1/153/65532": 9, + "1/153/65533": 3, + "1/153/65528": [0], + "1/153/65529": [1, 2, 5, 6, 7, 4], + "1/153/65531": [ + 0, 1, 2, 3, 5, 6, 7, 9, 10, 35, 36, 37, 38, 39, 64, 65, 66, 65528, 65529, + 65531, 65532, 65533 + ], + "1/156/65532": 1, + "1/156/65533": 1, + "1/156/65528": [], + "1/156/65529": [], + "1/156/65531": [65528, 65529, 65531, 65532, 65533], + "1/157/0": [ + { + "0": "Manual", + "1": 0, + "2": [ + { + "1": 16384 + } + ] + }, + { + "0": "Auto-scheduled", + "1": 1, + "2": [ + { + "1": 16385 + } + ] + }, + { + "0": "Solar", + "1": 2, + "2": [ + { + "1": 16386 + } + ] + }, + { + "0": "Auto-scheduled with Solar charging", + "1": 3, + "2": [ + { + "1": 16385 + }, + { + "1": 16386 + } + ] + } + ], + "1/157/1": 1, + "1/157/65532": 0, + "1/157/65533": 2, + "1/157/65528": [1], + "1/157/65529": [0], + "1/157/65531": [0, 1, 65528, 65529, 65531, 65532, 65533], + "1/159/0": [ + { + "0": "No energy management (forecast only)", + "1": 0, + "2": [ + { + "1": 16384 + } + ] + }, + { + "0": "Device optimizes (no local or grid control)", + "1": 1, + "2": [ + { + "1": 16385 + } + ] + }, + { + "0": "Optimized within building", + "1": 2, + "2": [ + { + "1": 16386 + }, + { + "1": 16385 + } + ] + }, + { + "0": "Optimized for grid", + "1": 3, + "2": [ + { + "1": 16385 + }, + { + "1": 16387 + } + ] + }, + { + "0": "Optimized for grid and building", + "1": 4, + "2": [ + { + "1": 16386 + }, + { + "1": 16385 + }, + { + "1": 16387 + } + ] + } + ], + "1/159/1": 3, + "1/159/65532": 0, + "1/159/65533": 2, + "1/159/65528": [1], + "1/159/65529": [0], + "1/159/65531": [0, 1, 65528, 65529, 65531, 65532, 65533] + }, + "attribute_subscriptions": [] +} diff --git a/tests/components/matter/snapshots/test_binary_sensor.ambr b/tests/components/matter/snapshots/test_binary_sensor.ambr index c8de905d03f..ec5317ba808 100644 --- a/tests/components/matter/snapshots/test_binary_sensor.ambr +++ b/tests/components/matter/snapshots/test_binary_sensor.ambr @@ -383,6 +383,150 @@ 'state': 'off', }) # --- +# name: test_binary_sensors[silabs_evse_charging][binary_sensor.evse_charging_status-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.evse_charging_status', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Charging status', + 'platform': 'matter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'evse_charging_status', + 'unique_id': '00000000000004D2-0000000000000017-MatterNodeDevice-1-EnergyEvseChargingStatusSensor-153-0', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[silabs_evse_charging][binary_sensor.evse_charging_status-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'battery_charging', + 'friendly_name': 'evse Charging status', + }), + 'context': , + 'entity_id': 'binary_sensor.evse_charging_status', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_binary_sensors[silabs_evse_charging][binary_sensor.evse_plug-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.evse_plug', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Plug', + 'platform': 'matter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'evse_plug_state', + 'unique_id': '00000000000004D2-0000000000000017-MatterNodeDevice-1-EnergyEvsePlugStateSensor-153-0', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[silabs_evse_charging][binary_sensor.evse_plug-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'plug', + 'friendly_name': 'evse Plug', + }), + 'context': , + 'entity_id': 'binary_sensor.evse_plug', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- +# name: test_binary_sensors[silabs_evse_charging][binary_sensor.evse_supply_charging_state-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'binary_sensor', + 'entity_category': None, + 'entity_id': 'binary_sensor.evse_supply_charging_state', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Supply charging state', + 'platform': 'matter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'evse_supply_charging_state', + 'unique_id': '00000000000004D2-0000000000000017-MatterNodeDevice-1-EnergyEvseSupplyStateSensor-153-1', + 'unit_of_measurement': None, + }) +# --- +# name: test_binary_sensors[silabs_evse_charging][binary_sensor.evse_supply_charging_state-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'running', + 'friendly_name': 'evse Supply charging state', + }), + 'context': , + 'entity_id': 'binary_sensor.evse_supply_charging_state', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- # name: test_binary_sensors[smoke_detector][binary_sensor.smoke_sensor_battery_alert-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/matter/snapshots/test_select.ambr b/tests/components/matter/snapshots/test_select.ambr index 772ee297e13..8ad579214d0 100644 --- a/tests/components/matter/snapshots/test_select.ambr +++ b/tests/components/matter/snapshots/test_select.ambr @@ -1543,6 +1543,128 @@ 'state': 'previous', }) # --- +# name: test_selects[silabs_evse_charging][select.evse_energy_management_mode-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'No energy management (forecast only)', + 'Device optimizes (no local or grid control)', + 'Optimized within building', + 'Optimized for grid', + 'Optimized for grid and building', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'select', + 'entity_category': None, + 'entity_id': 'select.evse_energy_management_mode', + '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': 'Energy management mode', + 'platform': 'matter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'device_energy_management_mode', + 'unique_id': '00000000000004D2-0000000000000017-MatterNodeDevice-1-MatterDeviceEnergyManagementMode-159-1', + 'unit_of_measurement': None, + }) +# --- +# name: test_selects[silabs_evse_charging][select.evse_energy_management_mode-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'evse Energy management mode', + 'options': list([ + 'No energy management (forecast only)', + 'Device optimizes (no local or grid control)', + 'Optimized within building', + 'Optimized for grid', + 'Optimized for grid and building', + ]), + }), + 'context': , + 'entity_id': 'select.evse_energy_management_mode', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'Optimized for grid', + }) +# --- +# name: test_selects[silabs_evse_charging][select.evse_mode-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'Manual', + 'Auto-scheduled', + 'Solar', + 'Auto-scheduled with Solar charging', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'select', + 'entity_category': None, + 'entity_id': 'select.evse_mode', + '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': 'Mode', + 'platform': 'matter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'mode', + 'unique_id': '00000000000004D2-0000000000000017-MatterNodeDevice-1-MatterEnergyEvseMode-157-1', + 'unit_of_measurement': None, + }) +# --- +# name: test_selects[silabs_evse_charging][select.evse_mode-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'evse Mode', + 'options': list([ + 'Manual', + 'Auto-scheduled', + 'Solar', + 'Auto-scheduled with Solar charging', + ]), + }), + 'context': , + 'entity_id': 'select.evse_mode', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'Auto-scheduled', + }) +# --- # name: test_selects[silabs_laundrywasher][select.laundrywasher_number_of_rinses-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/matter/snapshots/test_sensor.ambr b/tests/components/matter/snapshots/test_sensor.ambr index cb26f1d8e70..b3395551d74 100644 --- a/tests/components/matter/snapshots/test_sensor.ambr +++ b/tests/components/matter/snapshots/test_sensor.ambr @@ -2866,6 +2866,323 @@ 'state': '120.0', }) # --- +# name: test_sensors[silabs_evse_charging][sensor.evse_circuit_capacity-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + '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': , + 'entity_id': 'sensor.evse_circuit_capacity', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Circuit capacity', + 'platform': 'matter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'evse_circuit_capacity', + 'unique_id': '00000000000004D2-0000000000000017-MatterNodeDevice-1-EnergyEvseCircuitCapacity-153-5', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[silabs_evse_charging][sensor.evse_circuit_capacity-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'evse Circuit capacity', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.evse_circuit_capacity', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '32.0', + }) +# --- +# name: test_sensors[silabs_evse_charging][sensor.evse_fault_state-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': dict({ + 'options': list([ + 'no_error', + 'meter_failure', + 'over_voltage', + 'under_voltage', + 'over_current', + 'contact_wet_failure', + 'contact_dry_failure', + 'power_loss', + 'power_quality', + 'pilot_short_circuit', + 'emergency_stop', + 'ev_disconnected', + 'wrong_power_supply', + 'live_neutral_swap', + 'over_temperature', + 'other', + ]), + }), + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'sensor', + 'entity_category': , + 'entity_id': 'sensor.evse_fault_state', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Fault state', + 'platform': 'matter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'evse_fault_state', + 'unique_id': '00000000000004D2-0000000000000017-MatterNodeDevice-1-EnergyEvseFaultState-153-2', + 'unit_of_measurement': None, + }) +# --- +# name: test_sensors[silabs_evse_charging][sensor.evse_fault_state-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'enum', + 'friendly_name': 'evse Fault state', + 'options': list([ + 'no_error', + 'meter_failure', + 'over_voltage', + 'under_voltage', + 'over_current', + 'contact_wet_failure', + 'contact_dry_failure', + 'power_loss', + 'power_quality', + 'pilot_short_circuit', + 'emergency_stop', + 'ev_disconnected', + 'wrong_power_supply', + 'live_neutral_swap', + 'over_temperature', + 'other', + ]), + }), + 'context': , + 'entity_id': 'sensor.evse_fault_state', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'no_error', + }) +# --- +# name: test_sensors[silabs_evse_charging][sensor.evse_max_charge_current-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + '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': , + 'entity_id': 'sensor.evse_max_charge_current', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Max charge current', + 'platform': 'matter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'evse_max_charge_current', + 'unique_id': '00000000000004D2-0000000000000017-MatterNodeDevice-1-EnergyEvseMaximumChargeCurrent-153-7', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[silabs_evse_charging][sensor.evse_max_charge_current-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'evse Max charge current', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.evse_max_charge_current', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '30.0', + }) +# --- +# name: test_sensors[silabs_evse_charging][sensor.evse_min_charge_current-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + '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': , + 'entity_id': 'sensor.evse_min_charge_current', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'Min charge current', + 'platform': 'matter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'evse_min_charge_current', + 'unique_id': '00000000000004D2-0000000000000017-MatterNodeDevice-1-EnergyEvseMinimumChargeCurrent-153-6', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[silabs_evse_charging][sensor.evse_min_charge_current-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'evse Min charge current', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.evse_min_charge_current', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '2.0', + }) +# --- +# name: test_sensors[silabs_evse_charging][sensor.evse_user_max_charge_current-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + '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': , + 'entity_id': 'sensor.evse_user_max_charge_current', + 'has_entity_name': True, + 'hidden_by': None, + 'icon': None, + 'id': , + 'labels': set({ + }), + 'name': None, + 'options': dict({ + 'sensor': dict({ + 'suggested_display_precision': 2, + }), + 'sensor.private': dict({ + 'suggested_unit_of_measurement': , + }), + }), + 'original_device_class': , + 'original_icon': None, + 'original_name': 'User max charge current', + 'platform': 'matter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'evse_user_max_charge_current', + 'unique_id': '00000000000004D2-0000000000000017-MatterNodeDevice-1-EnergyEvseUserMaximumChargeCurrent-153-9', + 'unit_of_measurement': , + }) +# --- +# name: test_sensors[silabs_evse_charging][sensor.evse_user_max_charge_current-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'device_class': 'current', + 'friendly_name': 'evse User max charge current', + 'state_class': , + 'unit_of_measurement': , + }), + 'context': , + 'entity_id': 'sensor.evse_user_max_charge_current', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': '32.0', + }) +# --- # name: test_sensors[silabs_laundrywasher][sensor.laundrywasher_current-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/matter/snapshots/test_switch.ambr b/tests/components/matter/snapshots/test_switch.ambr index ebf43117846..d60a2933e6f 100644 --- a/tests/components/matter/snapshots/test_switch.ambr +++ b/tests/components/matter/snapshots/test_switch.ambr @@ -334,6 +334,53 @@ 'state': 'off', }) # --- +# name: test_switches[silabs_evse_charging][switch.evse_enable_charging-entry] + EntityRegistryEntrySnapshot({ + 'aliases': set({ + }), + 'area_id': None, + 'capabilities': None, + 'config_entry_id': , + 'config_subentry_id': , + 'device_class': None, + 'device_id': , + 'disabled_by': None, + 'domain': 'switch', + 'entity_category': None, + 'entity_id': 'switch.evse_enable_charging', + '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': 'Enable charging', + 'platform': 'matter', + 'previous_unique_id': None, + 'supported_features': 0, + 'translation_key': 'evse_charging_switch', + 'unique_id': '00000000000004D2-0000000000000017-MatterNodeDevice-1-EnergyEvseChargingSwitch-153-1', + 'unit_of_measurement': None, + }) +# --- +# name: test_switches[silabs_evse_charging][switch.evse_enable_charging-state] + StateSnapshot({ + 'attributes': ReadOnlyDict({ + 'friendly_name': 'evse Enable charging', + }), + 'context': , + 'entity_id': 'switch.evse_enable_charging', + 'last_changed': , + 'last_reported': , + 'last_updated': , + 'state': 'on', + }) +# --- # name: test_switches[switch_unit][switch.mock_switchunit-entry] EntityRegistryEntrySnapshot({ 'aliases': set({ diff --git a/tests/components/matter/test_binary_sensor.py b/tests/components/matter/test_binary_sensor.py index cddee975ac8..acd150d9131 100644 --- a/tests/components/matter/test_binary_sensor.py +++ b/tests/components/matter/test_binary_sensor.py @@ -147,3 +147,53 @@ async def test_optional_sensor_from_featuremap( ) state = hass.states.get(entity_id) assert state is None + + +@pytest.mark.parametrize("node_fixture", ["silabs_evse_charging"]) +async def test_evse_sensor( + hass: HomeAssistant, + matter_client: MagicMock, + matter_node: MatterNode, +) -> None: + """Test evse sensors.""" + # Test StateEnum value with binary_sensor.evse_charging_status + entity_id = "binary_sensor.evse_charging_status" + state = hass.states.get(entity_id) + assert state + assert state.state == "on" + # switch to PluggedInDemand state + set_node_attribute(matter_node, 1, 153, 0, 2) + await trigger_subscription_callback( + hass, matter_client, data=(matter_node.node_id, "1/153/0", 2) + ) + state = hass.states.get(entity_id) + assert state + assert state.state == "off" + + # Test StateEnum value with binary_sensor.evse_plug + entity_id = "binary_sensor.evse_plug" + state = hass.states.get(entity_id) + assert state + assert state.state == "on" + # switch to NotPluggedIn state + set_node_attribute(matter_node, 1, 153, 0, 0) + await trigger_subscription_callback( + hass, matter_client, data=(matter_node.node_id, "1/153/0", 0) + ) + state = hass.states.get(entity_id) + assert state + assert state.state == "off" + + # Test SupplyStateEnum value with binary_sensor.evse_supply_charging + entity_id = "binary_sensor.evse_supply_charging_state" + state = hass.states.get(entity_id) + assert state + assert state.state == "on" + # switch to Disabled state + set_node_attribute(matter_node, 1, 153, 1, 0) + await trigger_subscription_callback( + hass, matter_client, data=(matter_node.node_id, "1/153/1", 0) + ) + state = hass.states.get(entity_id) + assert state + assert state.state == "off" diff --git a/tests/components/matter/test_sensor.py b/tests/components/matter/test_sensor.py index 251aab73e3b..bcdb573b3c8 100644 --- a/tests/components/matter/test_sensor.py +++ b/tests/components/matter/test_sensor.py @@ -399,3 +399,71 @@ async def test_list_sensor( state = hass.states.get("sensor.laundrywasher_current_phase") assert state assert state.state == "rinse" + + +@pytest.mark.parametrize("node_fixture", ["silabs_evse_charging"]) +async def test_evse_sensor( + hass: HomeAssistant, + matter_client: MagicMock, + matter_node: MatterNode, +) -> None: + """Test evse sensors.""" + # EnergyEvseFaultState + state = hass.states.get("sensor.evse_fault_state") + assert state + assert state.state == "no_error" + + set_node_attribute(matter_node, 1, 153, 2, 4) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get("sensor.evse_fault_state") + assert state + assert state.state == "over_current" + + # EnergyEvseCircuitCapacity + state = hass.states.get("sensor.evse_circuit_capacity") + assert state + assert state.state == "32.0" + + set_node_attribute(matter_node, 1, 153, 5, 63000) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get("sensor.evse_circuit_capacity") + assert state + assert state.state == "63.0" + + # EnergyEvseMinimumChargeCurrent + state = hass.states.get("sensor.evse_min_charge_current") + assert state + assert state.state == "2.0" + + set_node_attribute(matter_node, 1, 153, 6, 5000) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get("sensor.evse_min_charge_current") + assert state + assert state.state == "5.0" + + # EnergyEvseMaximumChargeCurrent + state = hass.states.get("sensor.evse_max_charge_current") + assert state + assert state.state == "30.0" + + set_node_attribute(matter_node, 1, 153, 7, 20000) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get("sensor.evse_max_charge_current") + assert state + assert state.state == "20.0" + + # EnergyEvseUserMaximumChargeCurrent + state = hass.states.get("sensor.evse_user_max_charge_current") + assert state + assert state.state == "32.0" + + set_node_attribute(matter_node, 1, 153, 9, 63000) + await trigger_subscription_callback(hass, matter_client) + + state = hass.states.get("sensor.evse_user_max_charge_current") + assert state + assert state.state == "63.0" diff --git a/tests/components/matter/test_switch.py b/tests/components/matter/test_switch.py index e82848fcc3a..f294cd31a26 100644 --- a/tests/components/matter/test_switch.py +++ b/tests/components/matter/test_switch.py @@ -3,6 +3,7 @@ from unittest.mock import MagicMock, call from chip.clusters import Objects as clusters +from chip.clusters.Objects import NullValue from matter_server.client.models.node import MatterNode from matter_server.common.errors import MatterError from matter_server.common.helpers.util import create_attribute_path_from_attribute @@ -188,3 +189,46 @@ async def test_matter_exception_on_command( }, blocking=True, ) + + +@pytest.mark.parametrize("node_fixture", ["silabs_evse_charging"]) +async def test_evse_sensor( + hass: HomeAssistant, + matter_client: MagicMock, + matter_node: MatterNode, +) -> None: + """Test evse sensors.""" + state = hass.states.get("switch.evse_enable_charging") + assert state + assert state.state == "on" + # test switch service + await hass.services.async_call( + "switch", + "turn_off", + {"entity_id": "switch.evse_enable_charging"}, + 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.EnergyEvse.Commands.Disable(), + timed_request_timeout_ms=3000, + ) + await hass.services.async_call( + "switch", + "turn_on", + {"entity_id": "switch.evse_enable_charging"}, + blocking=True, + ) + assert matter_client.send_device_command.call_count == 2 + assert matter_client.send_device_command.call_args == call( + node_id=matter_node.node_id, + endpoint_id=1, + command=clusters.EnergyEvse.Commands.EnableCharging( + chargingEnabledUntil=NullValue, + minimumChargeCurrent=0, + maximumChargeCurrent=0, + ), + timed_request_timeout_ms=3000, + )