Skip to content

Commit a0da295

Browse files
bieniuCopilot
andauthored
Add buttons to control the screen of the Shelly Wall Display (home-assistant#156052)
Co-authored-by: Copilot <[email protected]>
1 parent fd6ca8b commit a0da295

File tree

5 files changed

+243
-2
lines changed

5 files changed

+243
-2
lines changed

homeassistant/components/shelly/button.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
MODEL_FRANKEVER_WATER_VALVE,
3131
ROLE_GENERIC,
3232
SHELLY_GAS_MODELS,
33+
SHELLY_WALL_DISPLAY_MODELS,
3334
)
3435
from .coordinator import ShellyBlockCoordinator, ShellyConfigEntry, ShellyRpcCoordinator
3536
from .entity import (
@@ -62,6 +63,7 @@ class ShellyButtonDescription[
6263
"""Class to describe a Button entity."""
6364

6465
press_action: str
66+
params: dict[str, Any] | None = None
6567

6668
supported: Callable[[_ShellyCoordinatorT], bool] = lambda _: True
6769

@@ -103,6 +105,20 @@ class RpcButtonDescription(RpcEntityDescription, ButtonEntityDescription):
103105
press_action="trigger_shelly_gas_unmute",
104106
supported=lambda coordinator: coordinator.model in SHELLY_GAS_MODELS,
105107
),
108+
ShellyButtonDescription[ShellyRpcCoordinator](
109+
key="turn_on_screen",
110+
name="Turn on the screen",
111+
press_action="wall_display_set_screen",
112+
params={"value": True},
113+
supported=lambda coordinator: coordinator.model in SHELLY_WALL_DISPLAY_MODELS,
114+
),
115+
ShellyButtonDescription[ShellyRpcCoordinator](
116+
key="turn_off_screen",
117+
name="Turn off the screen",
118+
press_action="wall_display_set_screen",
119+
params={"value": False},
120+
supported=lambda coordinator: coordinator.model in SHELLY_WALL_DISPLAY_MODELS,
121+
),
106122
]
107123

108124

@@ -317,7 +333,7 @@ async def _press_method(self) -> None:
317333
if TYPE_CHECKING:
318334
assert method is not None
319335

320-
await method()
336+
await method(**(self.entity_description.params or {}))
321337

322338

323339
class ShellyBluTrvButton(ShellyRpcAttributeEntity, ButtonEntity):

homeassistant/components/shelly/const.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,11 @@
223223
ENTRY_RELOAD_COOLDOWN = 60
224224

225225
SHELLY_GAS_MODELS = [MODEL_GAS]
226+
SHELLY_WALL_DISPLAY_MODELS = (
227+
MODEL_WALL_DISPLAY,
228+
MODEL_WALL_DISPLAY_X2,
229+
MODEL_WALL_DISPLAY_XL,
230+
)
226231

227232
CONF_BLE_SCANNER_MODE = "ble_scanner_mode"
228233

tests/components/shelly/snapshots/test_button.ambr

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,102 @@
144144
'state': 'unknown',
145145
})
146146
# ---
147+
# name: test_wall_display_screen_buttons[turn_off-False][button.test_name_turn_off_the_screen-entry]
148+
EntityRegistryEntrySnapshot({
149+
'aliases': set({
150+
}),
151+
'area_id': None,
152+
'capabilities': None,
153+
'config_entry_id': <ANY>,
154+
'config_subentry_id': <ANY>,
155+
'device_class': None,
156+
'device_id': <ANY>,
157+
'disabled_by': None,
158+
'domain': 'button',
159+
'entity_category': None,
160+
'entity_id': 'button.test_name_turn_off_the_screen',
161+
'has_entity_name': True,
162+
'hidden_by': None,
163+
'icon': None,
164+
'id': <ANY>,
165+
'labels': set({
166+
}),
167+
'name': None,
168+
'options': dict({
169+
}),
170+
'original_device_class': None,
171+
'original_icon': None,
172+
'original_name': 'Turn off the screen',
173+
'platform': 'shelly',
174+
'previous_unique_id': None,
175+
'suggested_object_id': None,
176+
'supported_features': 0,
177+
'translation_key': None,
178+
'unique_id': '123456789ABC-turn_off_screen',
179+
'unit_of_measurement': None,
180+
})
181+
# ---
182+
# name: test_wall_display_screen_buttons[turn_off-False][button.test_name_turn_off_the_screen-state]
183+
StateSnapshot({
184+
'attributes': ReadOnlyDict({
185+
'friendly_name': 'Test name Turn off the screen',
186+
}),
187+
'context': <ANY>,
188+
'entity_id': 'button.test_name_turn_off_the_screen',
189+
'last_changed': <ANY>,
190+
'last_reported': <ANY>,
191+
'last_updated': <ANY>,
192+
'state': 'unknown',
193+
})
194+
# ---
195+
# name: test_wall_display_screen_buttons[turn_on-True][button.test_name_turn_on_the_screen-entry]
196+
EntityRegistryEntrySnapshot({
197+
'aliases': set({
198+
}),
199+
'area_id': None,
200+
'capabilities': None,
201+
'config_entry_id': <ANY>,
202+
'config_subentry_id': <ANY>,
203+
'device_class': None,
204+
'device_id': <ANY>,
205+
'disabled_by': None,
206+
'domain': 'button',
207+
'entity_category': None,
208+
'entity_id': 'button.test_name_turn_on_the_screen',
209+
'has_entity_name': True,
210+
'hidden_by': None,
211+
'icon': None,
212+
'id': <ANY>,
213+
'labels': set({
214+
}),
215+
'name': None,
216+
'options': dict({
217+
}),
218+
'original_device_class': None,
219+
'original_icon': None,
220+
'original_name': 'Turn on the screen',
221+
'platform': 'shelly',
222+
'previous_unique_id': None,
223+
'suggested_object_id': None,
224+
'supported_features': 0,
225+
'translation_key': None,
226+
'unique_id': '123456789ABC-turn_on_screen',
227+
'unit_of_measurement': None,
228+
})
229+
# ---
230+
# name: test_wall_display_screen_buttons[turn_on-True][button.test_name_turn_on_the_screen-state]
231+
StateSnapshot({
232+
'attributes': ReadOnlyDict({
233+
'friendly_name': 'Test name Turn on the screen',
234+
}),
235+
'context': <ANY>,
236+
'entity_id': 'button.test_name_turn_on_the_screen',
237+
'last_changed': <ANY>,
238+
'last_reported': <ANY>,
239+
'last_updated': <ANY>,
240+
'state': 'unknown',
241+
})
242+
# ---
147243
# name: test_wall_display_virtual_button[button.test_name_button-entry]
148244
EntityRegistryEntrySnapshot({
149245
'aliases': set({

tests/components/shelly/snapshots/test_devices.ambr

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5374,6 +5374,102 @@
53745374
'state': 'unknown',
53755375
})
53765376
# ---
5377+
# name: test_device[wall_display_xl][button.test_name_turn_off_the_screen-entry]
5378+
EntityRegistryEntrySnapshot({
5379+
'aliases': set({
5380+
}),
5381+
'area_id': None,
5382+
'capabilities': None,
5383+
'config_entry_id': <ANY>,
5384+
'config_subentry_id': <ANY>,
5385+
'device_class': None,
5386+
'device_id': <ANY>,
5387+
'disabled_by': None,
5388+
'domain': 'button',
5389+
'entity_category': None,
5390+
'entity_id': 'button.test_name_turn_off_the_screen',
5391+
'has_entity_name': True,
5392+
'hidden_by': None,
5393+
'icon': None,
5394+
'id': <ANY>,
5395+
'labels': set({
5396+
}),
5397+
'name': None,
5398+
'options': dict({
5399+
}),
5400+
'original_device_class': None,
5401+
'original_icon': None,
5402+
'original_name': 'Turn off the screen',
5403+
'platform': 'shelly',
5404+
'previous_unique_id': None,
5405+
'suggested_object_id': None,
5406+
'supported_features': 0,
5407+
'translation_key': None,
5408+
'unique_id': '123456789ABC-turn_off_screen',
5409+
'unit_of_measurement': None,
5410+
})
5411+
# ---
5412+
# name: test_device[wall_display_xl][button.test_name_turn_off_the_screen-state]
5413+
StateSnapshot({
5414+
'attributes': ReadOnlyDict({
5415+
'friendly_name': 'Test name Turn off the screen',
5416+
}),
5417+
'context': <ANY>,
5418+
'entity_id': 'button.test_name_turn_off_the_screen',
5419+
'last_changed': <ANY>,
5420+
'last_reported': <ANY>,
5421+
'last_updated': <ANY>,
5422+
'state': 'unknown',
5423+
})
5424+
# ---
5425+
# name: test_device[wall_display_xl][button.test_name_turn_on_the_screen-entry]
5426+
EntityRegistryEntrySnapshot({
5427+
'aliases': set({
5428+
}),
5429+
'area_id': None,
5430+
'capabilities': None,
5431+
'config_entry_id': <ANY>,
5432+
'config_subentry_id': <ANY>,
5433+
'device_class': None,
5434+
'device_id': <ANY>,
5435+
'disabled_by': None,
5436+
'domain': 'button',
5437+
'entity_category': None,
5438+
'entity_id': 'button.test_name_turn_on_the_screen',
5439+
'has_entity_name': True,
5440+
'hidden_by': None,
5441+
'icon': None,
5442+
'id': <ANY>,
5443+
'labels': set({
5444+
}),
5445+
'name': None,
5446+
'options': dict({
5447+
}),
5448+
'original_device_class': None,
5449+
'original_icon': None,
5450+
'original_name': 'Turn on the screen',
5451+
'platform': 'shelly',
5452+
'previous_unique_id': None,
5453+
'suggested_object_id': None,
5454+
'supported_features': 0,
5455+
'translation_key': None,
5456+
'unique_id': '123456789ABC-turn_on_screen',
5457+
'unit_of_measurement': None,
5458+
})
5459+
# ---
5460+
# name: test_device[wall_display_xl][button.test_name_turn_on_the_screen-state]
5461+
StateSnapshot({
5462+
'attributes': ReadOnlyDict({
5463+
'friendly_name': 'Test name Turn on the screen',
5464+
}),
5465+
'context': <ANY>,
5466+
'entity_id': 'button.test_name_turn_on_the_screen',
5467+
'last_changed': <ANY>,
5468+
'last_reported': <ANY>,
5469+
'last_updated': <ANY>,
5470+
'state': 'unknown',
5471+
})
5472+
# ---
53775473
# name: test_device[wall_display_xl][event.test_name_input_0-entry]
53785474
EntityRegistryEntrySnapshot({
53795475
'aliases': set({

tests/components/shelly/test_button.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from copy import deepcopy
44
from unittest.mock import Mock
55

6-
from aioshelly.const import MODEL_BLU_GATEWAY_G3, MODEL_PLUS_SMOKE
6+
from aioshelly.const import MODEL_BLU_GATEWAY_G3, MODEL_PLUS_SMOKE, MODEL_WALL_DISPLAY
77
from aioshelly.exceptions import DeviceConnectionError, InvalidAuthError, RpcCallError
88
import pytest
99
from syrupy.assertion import SnapshotAssertion
@@ -538,3 +538,31 @@ async def test_rpc_smoke_mute_alarm_button(
538538
)
539539
mock_rpc_device.mock_update()
540540
mock_rpc_device.smoke_mute_alarm.assert_called_once_with(0)
541+
542+
543+
@pytest.mark.parametrize(("action", "value"), [("turn_on", True), ("turn_off", False)])
544+
async def test_wall_display_screen_buttons(
545+
hass: HomeAssistant,
546+
entity_registry: EntityRegistry,
547+
mock_rpc_device: Mock,
548+
snapshot: SnapshotAssertion,
549+
action: str,
550+
value: bool,
551+
) -> None:
552+
"""Test a Wall Display screen buttons."""
553+
await init_integration(hass, 2, model=MODEL_WALL_DISPLAY)
554+
entity_id = f"button.test_name_{action}_the_screen"
555+
556+
assert (state := hass.states.get(entity_id))
557+
assert state == snapshot(name=f"{entity_id}-state")
558+
559+
assert (entry := entity_registry.async_get(entity_id))
560+
assert entry == snapshot(name=f"{entity_id}-entry")
561+
562+
await hass.services.async_call(
563+
BUTTON_DOMAIN,
564+
SERVICE_PRESS,
565+
{ATTR_ENTITY_ID: entity_id},
566+
blocking=True,
567+
)
568+
mock_rpc_device.wall_display_set_screen.assert_called_once_with(value=value)

0 commit comments

Comments
 (0)