Skip to content

Commit d62f136

Browse files
authored
Add child lock entity for Eve Matter devices (#169391)
1 parent 86e8b9d commit d62f136

3 files changed

Lines changed: 262 additions & 0 deletions

File tree

homeassistant/components/matter/switch.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,4 +316,14 @@ def _update_from_device(self) -> None:
316316
value_contains=clusters.EnergyEvse.Commands.EnableCharging.command_id,
317317
allow_multi=True,
318318
),
319+
MatterDiscoverySchema(
320+
platform=Platform.SWITCH,
321+
entity_description=MatterNumericSwitchEntityDescription(
322+
key="EveChildLock",
323+
entity_category=EntityCategory.CONFIG,
324+
translation_key="child_lock",
325+
),
326+
entity_class=MatterNumericSwitch,
327+
required_attributes=(clusters.EveCluster.Attributes.ChildLock,),
328+
),
319329
]

tests/components/matter/snapshots/test_switch.ambr

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,54 @@
11
# serializer version: 1
2+
# name: test_switches[eve_energy_20ecn4101][switch.eve_energy_20ecn4101_child_lock_top-entry]
3+
EntityRegistryEntrySnapshot({
4+
'aliases': list([
5+
None,
6+
]),
7+
'area_id': None,
8+
'capabilities': None,
9+
'config_entry_id': <ANY>,
10+
'config_subentry_id': <ANY>,
11+
'device_class': None,
12+
'device_id': <ANY>,
13+
'disabled_by': None,
14+
'domain': 'switch',
15+
'entity_category': <EntityCategory.CONFIG: 'config'>,
16+
'entity_id': 'switch.eve_energy_20ecn4101_child_lock_top',
17+
'has_entity_name': True,
18+
'hidden_by': None,
19+
'icon': None,
20+
'id': <ANY>,
21+
'labels': set({
22+
}),
23+
'name': None,
24+
'object_id_base': 'Child lock (top)',
25+
'options': dict({
26+
}),
27+
'original_device_class': None,
28+
'original_icon': None,
29+
'original_name': 'Child lock (top)',
30+
'platform': 'matter',
31+
'previous_unique_id': None,
32+
'suggested_object_id': None,
33+
'supported_features': 0,
34+
'translation_key': 'child_lock',
35+
'unique_id': '00000000000004D2-00000000000000C7-MatterNodeDevice-1-EveChildLock-319486977-319422481',
36+
'unit_of_measurement': None,
37+
})
38+
# ---
39+
# name: test_switches[eve_energy_20ecn4101][switch.eve_energy_20ecn4101_child_lock_top-state]
40+
StateSnapshot({
41+
'attributes': ReadOnlyDict({
42+
'friendly_name': 'Eve Energy 20ECN4101 Child lock (top)',
43+
}),
44+
'context': <ANY>,
45+
'entity_id': 'switch.eve_energy_20ecn4101_child_lock_top',
46+
'last_changed': <ANY>,
47+
'last_reported': <ANY>,
48+
'last_updated': <ANY>,
49+
'state': 'off',
50+
})
51+
# ---
252
# name: test_switches[eve_energy_20ecn4101][switch.eve_energy_20ecn4101_switch_bottom-entry]
353
EntityRegistryEntrySnapshot({
454
'aliases': list([
@@ -152,6 +202,56 @@
152202
'state': 'off',
153203
})
154204
# ---
205+
# name: test_switches[eve_energy_plug][switch.eve_energy_plug_child_lock-entry]
206+
EntityRegistryEntrySnapshot({
207+
'aliases': list([
208+
None,
209+
]),
210+
'area_id': None,
211+
'capabilities': None,
212+
'config_entry_id': <ANY>,
213+
'config_subentry_id': <ANY>,
214+
'device_class': None,
215+
'device_id': <ANY>,
216+
'disabled_by': None,
217+
'domain': 'switch',
218+
'entity_category': <EntityCategory.CONFIG: 'config'>,
219+
'entity_id': 'switch.eve_energy_plug_child_lock',
220+
'has_entity_name': True,
221+
'hidden_by': None,
222+
'icon': None,
223+
'id': <ANY>,
224+
'labels': set({
225+
}),
226+
'name': None,
227+
'object_id_base': 'Child lock',
228+
'options': dict({
229+
}),
230+
'original_device_class': None,
231+
'original_icon': None,
232+
'original_name': 'Child lock',
233+
'platform': 'matter',
234+
'previous_unique_id': None,
235+
'suggested_object_id': None,
236+
'supported_features': 0,
237+
'translation_key': 'child_lock',
238+
'unique_id': '00000000000004D2-000000000000003D-MatterNodeDevice-1-EveChildLock-319486977-319422481',
239+
'unit_of_measurement': None,
240+
})
241+
# ---
242+
# name: test_switches[eve_energy_plug][switch.eve_energy_plug_child_lock-state]
243+
StateSnapshot({
244+
'attributes': ReadOnlyDict({
245+
'friendly_name': 'Eve Energy Plug Child lock',
246+
}),
247+
'context': <ANY>,
248+
'entity_id': 'switch.eve_energy_plug_child_lock',
249+
'last_changed': <ANY>,
250+
'last_reported': <ANY>,
251+
'last_updated': <ANY>,
252+
'state': 'off',
253+
})
254+
# ---
155255
# name: test_switches[eve_energy_plug_patched][switch.eve_energy_plug_patched-entry]
156256
EntityRegistryEntrySnapshot({
157257
'aliases': list([
@@ -203,6 +303,106 @@
203303
'state': 'off',
204304
})
205305
# ---
306+
# name: test_switches[eve_energy_plug_patched][switch.eve_energy_plug_patched_child_lock-entry]
307+
EntityRegistryEntrySnapshot({
308+
'aliases': list([
309+
None,
310+
]),
311+
'area_id': None,
312+
'capabilities': None,
313+
'config_entry_id': <ANY>,
314+
'config_subentry_id': <ANY>,
315+
'device_class': None,
316+
'device_id': <ANY>,
317+
'disabled_by': None,
318+
'domain': 'switch',
319+
'entity_category': <EntityCategory.CONFIG: 'config'>,
320+
'entity_id': 'switch.eve_energy_plug_patched_child_lock',
321+
'has_entity_name': True,
322+
'hidden_by': None,
323+
'icon': None,
324+
'id': <ANY>,
325+
'labels': set({
326+
}),
327+
'name': None,
328+
'object_id_base': 'Child lock',
329+
'options': dict({
330+
}),
331+
'original_device_class': None,
332+
'original_icon': None,
333+
'original_name': 'Child lock',
334+
'platform': 'matter',
335+
'previous_unique_id': None,
336+
'suggested_object_id': None,
337+
'supported_features': 0,
338+
'translation_key': 'child_lock',
339+
'unique_id': '00000000000004D2-00000000000000B7-MatterNodeDevice-1-EveChildLock-319486977-319422481',
340+
'unit_of_measurement': None,
341+
})
342+
# ---
343+
# name: test_switches[eve_energy_plug_patched][switch.eve_energy_plug_patched_child_lock-state]
344+
StateSnapshot({
345+
'attributes': ReadOnlyDict({
346+
'friendly_name': 'Eve Energy Plug Patched Child lock',
347+
}),
348+
'context': <ANY>,
349+
'entity_id': 'switch.eve_energy_plug_patched_child_lock',
350+
'last_changed': <ANY>,
351+
'last_reported': <ANY>,
352+
'last_updated': <ANY>,
353+
'state': 'off',
354+
})
355+
# ---
356+
# name: test_switches[eve_shutter][switch.eve_shutter_switch_20eci1701_child_lock-entry]
357+
EntityRegistryEntrySnapshot({
358+
'aliases': list([
359+
None,
360+
]),
361+
'area_id': None,
362+
'capabilities': None,
363+
'config_entry_id': <ANY>,
364+
'config_subentry_id': <ANY>,
365+
'device_class': None,
366+
'device_id': <ANY>,
367+
'disabled_by': None,
368+
'domain': 'switch',
369+
'entity_category': <EntityCategory.CONFIG: 'config'>,
370+
'entity_id': 'switch.eve_shutter_switch_20eci1701_child_lock',
371+
'has_entity_name': True,
372+
'hidden_by': None,
373+
'icon': None,
374+
'id': <ANY>,
375+
'labels': set({
376+
}),
377+
'name': None,
378+
'object_id_base': 'Child lock',
379+
'options': dict({
380+
}),
381+
'original_device_class': None,
382+
'original_icon': None,
383+
'original_name': 'Child lock',
384+
'platform': 'matter',
385+
'previous_unique_id': None,
386+
'suggested_object_id': None,
387+
'supported_features': 0,
388+
'translation_key': 'child_lock',
389+
'unique_id': '00000000000004D2-0000000000000094-MatterNodeDevice-1-EveChildLock-319486977-319422481',
390+
'unit_of_measurement': None,
391+
})
392+
# ---
393+
# name: test_switches[eve_shutter][switch.eve_shutter_switch_20eci1701_child_lock-state]
394+
StateSnapshot({
395+
'attributes': ReadOnlyDict({
396+
'friendly_name': 'Eve Shutter Switch 20ECI1701 Child lock',
397+
}),
398+
'context': <ANY>,
399+
'entity_id': 'switch.eve_shutter_switch_20eci1701_child_lock',
400+
'last_changed': <ANY>,
401+
'last_reported': <ANY>,
402+
'last_updated': <ANY>,
403+
'state': 'off',
404+
})
405+
# ---
206406
# name: test_switches[eve_thermo_v4][switch.eve_thermo_20ebp1701_child_lock-entry]
207407
EntityRegistryEntrySnapshot({
208408
'aliases': list([

tests/components/matter/test_switch.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,3 +285,55 @@ async def test_speaker_mute_uses_onoff_commands(
285285
state = hass.states.get("switch.mock_speaker_mute")
286286
assert state
287287
assert state.state == "off"
288+
289+
290+
@pytest.mark.parametrize("node_fixture", ["eve_energy_plug"])
291+
async def test_eve_child_lock(
292+
hass: HomeAssistant,
293+
matter_client: MagicMock,
294+
matter_node: MatterNode,
295+
) -> None:
296+
"""Test the Eve child lock switch entity."""
297+
state = hass.states.get("switch.eve_energy_plug_child_lock")
298+
assert state
299+
assert state.state == "off"
300+
# test attribute changes
301+
set_node_attribute(matter_node, 1, 319486977, 319422481, True)
302+
await trigger_subscription_callback(hass, matter_client)
303+
state = hass.states.get("switch.eve_energy_plug_child_lock")
304+
assert state.state == "on"
305+
set_node_attribute(matter_node, 1, 319486977, 319422481, False)
306+
await trigger_subscription_callback(hass, matter_client)
307+
state = hass.states.get("switch.eve_energy_plug_child_lock")
308+
assert state.state == "off"
309+
# test switch service
310+
await hass.services.async_call(
311+
"switch",
312+
"turn_on",
313+
{"entity_id": "switch.eve_energy_plug_child_lock"},
314+
blocking=True,
315+
)
316+
assert matter_client.write_attribute.call_count == 1
317+
assert matter_client.write_attribute.call_args_list[0] == call(
318+
node_id=matter_node.node_id,
319+
attribute_path=create_attribute_path_from_attribute(
320+
endpoint_id=1,
321+
attribute=clusters.EveCluster.Attributes.ChildLock,
322+
),
323+
value=True,
324+
)
325+
await hass.services.async_call(
326+
"switch",
327+
"turn_off",
328+
{"entity_id": "switch.eve_energy_plug_child_lock"},
329+
blocking=True,
330+
)
331+
assert matter_client.write_attribute.call_count == 2
332+
assert matter_client.write_attribute.call_args_list[1] == call(
333+
node_id=matter_node.node_id,
334+
attribute_path=create_attribute_path_from_attribute(
335+
endpoint_id=1,
336+
attribute=clusters.EveCluster.Attributes.ChildLock,
337+
),
338+
value=False,
339+
)

0 commit comments

Comments
 (0)