mirror of
https://github.com/home-assistant/core.git
synced 2025-07-23 13:17:32 +00:00
Fix several issues with the Matter Generic Switch Cluster (#122191)
This commit is contained in:
parent
d3d91a83e5
commit
632dec614a
@ -58,17 +58,32 @@ class MatterEventEntity(MatterEntity, EventEntity):
|
||||
self.get_matter_attribute_value(clusters.Switch.Attributes.FeatureMap)
|
||||
)
|
||||
if feature_map & SwitchFeature.kLatchingSwitch:
|
||||
# a latching switch only supports switch_latched event
|
||||
event_types.append("switch_latched")
|
||||
if feature_map & SwitchFeature.kMomentarySwitch:
|
||||
elif feature_map & SwitchFeature.kMomentarySwitchMultiPress:
|
||||
# Momentary switch with multi press support
|
||||
# NOTE: We ignore 'multi press ongoing' as it doesn't make a lot
|
||||
# of sense and many devices do not support it.
|
||||
# Instead we we report on the 'multi press complete' event with the number
|
||||
# of presses.
|
||||
max_presses_supported = self.get_matter_attribute_value(
|
||||
clusters.Switch.Attributes.MultiPressMax
|
||||
)
|
||||
max_presses_supported = min(max_presses_supported or 1, 8)
|
||||
for i in range(max_presses_supported):
|
||||
event_types.append(f"multi_press_{i + 1}") # noqa: PERF401
|
||||
elif feature_map & SwitchFeature.kMomentarySwitch:
|
||||
# momentary switch without multi press support
|
||||
event_types.append("initial_press")
|
||||
if feature_map & SwitchFeature.kMomentarySwitchRelease:
|
||||
event_types.append("short_release")
|
||||
if feature_map & SwitchFeature.kMomentarySwitchRelease:
|
||||
# momentary switch without multi press support can optionally support release
|
||||
event_types.append("short_release")
|
||||
|
||||
# a momentary switch can optionally support long press
|
||||
if feature_map & SwitchFeature.kMomentarySwitchLongPress:
|
||||
event_types.append("long_press")
|
||||
event_types.append("long_release")
|
||||
if feature_map & SwitchFeature.kMomentarySwitchMultiPress:
|
||||
event_types.append("multi_press_ongoing")
|
||||
event_types.append("multi_press_complete")
|
||||
|
||||
self._attr_event_types = event_types
|
||||
|
||||
async def async_added_to_hass(self) -> None:
|
||||
@ -96,7 +111,20 @@ class MatterEventEntity(MatterEntity, EventEntity):
|
||||
"""Call on NodeEvent."""
|
||||
if data.endpoint_id != self._endpoint.endpoint_id:
|
||||
return
|
||||
self._trigger_event(EVENT_TYPES_MAP[data.event_id], data.data)
|
||||
if data.event_id == clusters.Switch.Events.MultiPressComplete.event_id:
|
||||
# multi press event
|
||||
presses = (data.data or {}).get("totalNumberOfPressesCounted", 1)
|
||||
event_type = f"multi_press_{presses}"
|
||||
else:
|
||||
event_type = EVENT_TYPES_MAP[data.event_id]
|
||||
|
||||
if event_type not in self.event_types:
|
||||
# this should not happen, but guard for bad things
|
||||
# some remotes send events that they do not report as supported (sigh...)
|
||||
return
|
||||
|
||||
# pass the rest of the data as-is (such as the advanced Position data)
|
||||
self._trigger_event(event_type, data.data)
|
||||
self.async_write_ha_state()
|
||||
|
||||
|
||||
@ -119,5 +147,6 @@ DISCOVERY_SCHEMAS = [
|
||||
clusters.Switch.Attributes.NumberOfPositions,
|
||||
clusters.FixedLabel.Attributes.LabelList,
|
||||
),
|
||||
allow_multi=True, # also used for sensor (current position) entity
|
||||
),
|
||||
]
|
||||
|
@ -448,4 +448,18 @@ DISCOVERY_SCHEMAS = [
|
||||
entity_class=MatterSensor,
|
||||
required_attributes=(NeoCluster.Attributes.Current,),
|
||||
),
|
||||
MatterDiscoverySchema(
|
||||
platform=Platform.SENSOR,
|
||||
entity_description=MatterSensorEntityDescription(
|
||||
key="SwitchCurrentPosition",
|
||||
native_unit_of_measurement=None,
|
||||
device_class=None,
|
||||
state_class=SensorStateClass.MEASUREMENT,
|
||||
translation_key="switch_current_position",
|
||||
entity_category=EntityCategory.DIAGNOSTIC,
|
||||
),
|
||||
entity_class=MatterSensor,
|
||||
required_attributes=(clusters.Switch.Attributes.CurrentPosition,),
|
||||
allow_multi=True, # also used for event entity
|
||||
),
|
||||
]
|
||||
|
@ -73,12 +73,18 @@
|
||||
"event_type": {
|
||||
"state": {
|
||||
"switch_latched": "Switch latched",
|
||||
"initial_press": "Initial press",
|
||||
"long_press": "Long press",
|
||||
"short_release": "Short release",
|
||||
"long_release": "Long release",
|
||||
"multi_press_ongoing": "Multi press ongoing",
|
||||
"multi_press_complete": "Multi press complete"
|
||||
"initial_press": "Pressed",
|
||||
"long_press": "Hold down",
|
||||
"short_release": "Released after being pressed",
|
||||
"long_release": "Released after being held down",
|
||||
"multi_press_1": "Pressed once",
|
||||
"multi_press_2": "Pressed twice",
|
||||
"multi_press_3": "Pressed 3 times",
|
||||
"multi_press_4": "Pressed 4 times",
|
||||
"multi_press_5": "Pressed 5 times",
|
||||
"multi_press_6": "Pressed 6 times",
|
||||
"multi_press_7": "Pressed 7 times",
|
||||
"multi_press_8": "Pressed 8 times"
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -151,6 +157,9 @@
|
||||
},
|
||||
"hepa_filter_condition": {
|
||||
"name": "Hepa filter condition"
|
||||
},
|
||||
"switch_current_position": {
|
||||
"name": "Current switch position"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
|
@ -72,8 +72,9 @@
|
||||
"1/59/0": 2,
|
||||
"1/59/65533": 1,
|
||||
"1/59/1": 0,
|
||||
"1/59/2": 2,
|
||||
"1/59/65531": [0, 1, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/59/65532": 14,
|
||||
"1/59/65532": 30,
|
||||
"1/59/65528": [],
|
||||
"1/64/0": [
|
||||
{
|
||||
@ -101,8 +102,9 @@
|
||||
"2/59/0": 2,
|
||||
"2/59/65533": 1,
|
||||
"2/59/1": 0,
|
||||
"2/59/2": 2,
|
||||
"2/59/65531": [0, 1, 65528, 65529, 65531, 65532, 65533],
|
||||
"2/59/65532": 14,
|
||||
"2/59/65532": 30,
|
||||
"2/59/65528": [],
|
||||
"2/64/0": [
|
||||
{
|
||||
|
@ -73,7 +73,7 @@
|
||||
"1/59/65533": 1,
|
||||
"1/59/1": 0,
|
||||
"1/59/65531": [0, 1, 65528, 65529, 65531, 65532, 65533],
|
||||
"1/59/65532": 30,
|
||||
"1/59/65532": 14,
|
||||
"1/59/65528": []
|
||||
},
|
||||
"available": true,
|
||||
|
@ -50,8 +50,6 @@ async def test_generic_switch_node(
|
||||
"short_release",
|
||||
"long_press",
|
||||
"long_release",
|
||||
"multi_press_ongoing",
|
||||
"multi_press_complete",
|
||||
]
|
||||
# trigger firing a new event from the device
|
||||
await trigger_subscription_callback(
|
||||
@ -72,26 +70,6 @@ async def test_generic_switch_node(
|
||||
)
|
||||
state = hass.states.get("event.mock_generic_switch_button")
|
||||
assert state.attributes[ATTR_EVENT_TYPE] == "initial_press"
|
||||
# trigger firing a multi press event
|
||||
await trigger_subscription_callback(
|
||||
hass,
|
||||
matter_client,
|
||||
EventType.NODE_EVENT,
|
||||
MatterNodeEvent(
|
||||
node_id=generic_switch_node.node_id,
|
||||
endpoint_id=1,
|
||||
cluster_id=59,
|
||||
event_id=5,
|
||||
event_number=0,
|
||||
priority=1,
|
||||
timestamp=0,
|
||||
timestamp_type=0,
|
||||
data={"NewPosition": 3},
|
||||
),
|
||||
)
|
||||
state = hass.states.get("event.mock_generic_switch_button")
|
||||
assert state.attributes[ATTR_EVENT_TYPE] == "multi_press_ongoing"
|
||||
assert state.attributes["NewPosition"] == 3
|
||||
|
||||
|
||||
# This tests needs to be adjusted to remove lingering tasks
|
||||
@ -109,8 +87,8 @@ async def test_generic_switch_multi_node(
|
||||
assert state_button_1.name == "Mock Generic Switch Button (1)"
|
||||
# check event_types from featuremap 14
|
||||
assert state_button_1.attributes[ATTR_EVENT_TYPES] == [
|
||||
"initial_press",
|
||||
"short_release",
|
||||
"multi_press_1",
|
||||
"multi_press_2",
|
||||
"long_press",
|
||||
"long_release",
|
||||
]
|
||||
@ -120,3 +98,23 @@ async def test_generic_switch_multi_node(
|
||||
assert state_button_1.state == "unknown"
|
||||
# name should be 'DeviceName Fancy Button' due to the label set to 'Fancy Button'
|
||||
assert state_button_1.name == "Mock Generic Switch Fancy Button"
|
||||
|
||||
# trigger firing a multi press event
|
||||
await trigger_subscription_callback(
|
||||
hass,
|
||||
matter_client,
|
||||
EventType.NODE_EVENT,
|
||||
MatterNodeEvent(
|
||||
node_id=generic_switch_multi_node.node_id,
|
||||
endpoint_id=1,
|
||||
cluster_id=59,
|
||||
event_id=6,
|
||||
event_number=0,
|
||||
priority=1,
|
||||
timestamp=0,
|
||||
timestamp_type=0,
|
||||
data={"totalNumberOfPressesCounted": 2},
|
||||
),
|
||||
)
|
||||
state = hass.states.get("event.mock_generic_switch_button_1")
|
||||
assert state.attributes[ATTR_EVENT_TYPE] == "multi_press_2"
|
||||
|
Loading…
x
Reference in New Issue
Block a user