Skip to content

Commit 343b177

Browse files
authored
Add support for valance shades / volants to WMS WebControl pro (home-assistant#150882)
1 parent 50349e4 commit 343b177

File tree

5 files changed

+135
-11
lines changed

5 files changed

+135
-11
lines changed

homeassistant/components/wmspro/cover.py

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66
from typing import Any
77

88
from wmspro.const import (
9-
WMS_WebControl_pro_API_actionDescription,
9+
WMS_WebControl_pro_API_actionDescription as ACTION_DESC,
1010
WMS_WebControl_pro_API_actionType,
1111
WMS_WebControl_pro_API_responseType,
1212
)
13+
from wmspro.destination import Destination
1314

1415
from homeassistant.components.cover import ATTR_POSITION, CoverDeviceClass, CoverEntity
1516
from homeassistant.core import HomeAssistant
@@ -32,11 +33,11 @@ async def async_setup_entry(
3233

3334
entities: list[WebControlProGenericEntity] = []
3435
for dest in hub.dests.values():
35-
if dest.hasAction(WMS_WebControl_pro_API_actionDescription.AwningDrive):
36+
if dest.hasAction(ACTION_DESC.AwningDrive):
3637
entities.append(WebControlProAwning(config_entry.entry_id, dest))
37-
elif dest.hasAction(
38-
WMS_WebControl_pro_API_actionDescription.RollerShutterBlindDrive
39-
):
38+
if dest.hasAction(ACTION_DESC.ValanceDrive):
39+
entities.append(WebControlProValance(config_entry.entry_id, dest))
40+
if dest.hasAction(ACTION_DESC.RollerShutterBlindDrive):
4041
entities.append(WebControlProRollerShutter(config_entry.entry_id, dest))
4142

4243
async_add_entities(entities)
@@ -45,7 +46,7 @@ async def async_setup_entry(
4546
class WebControlProCover(WebControlProGenericEntity, CoverEntity):
4647
"""Base representation of a WMS based cover."""
4748

48-
_drive_action_desc: WMS_WebControl_pro_API_actionDescription
49+
_drive_action_desc: ACTION_DESC
4950
_attr_name = None
5051

5152
@property
@@ -79,7 +80,7 @@ async def async_close_cover(self, **kwargs: Any) -> None:
7980
async def async_stop_cover(self, **kwargs: Any) -> None:
8081
"""Stop the device if in motion."""
8182
action = self._dest.action(
82-
WMS_WebControl_pro_API_actionDescription.ManualCommand,
83+
ACTION_DESC.ManualCommand,
8384
WMS_WebControl_pro_API_actionType.Stop,
8485
)
8586
await action(responseType=WMS_WebControl_pro_API_responseType.Detailed)
@@ -89,13 +90,25 @@ class WebControlProAwning(WebControlProCover):
8990
"""Representation of a WMS based awning."""
9091

9192
_attr_device_class = CoverDeviceClass.AWNING
92-
_drive_action_desc = WMS_WebControl_pro_API_actionDescription.AwningDrive
93+
_drive_action_desc = ACTION_DESC.AwningDrive
94+
95+
96+
class WebControlProValance(WebControlProCover):
97+
"""Representation of a WMS based valance."""
98+
99+
_attr_translation_key = "valance"
100+
_attr_device_class = CoverDeviceClass.SHADE
101+
_drive_action_desc = ACTION_DESC.ValanceDrive
102+
103+
def __init__(self, config_entry_id: str, dest: Destination) -> None:
104+
"""Initialize the entity with destination channel."""
105+
super().__init__(config_entry_id, dest)
106+
if self._attr_unique_id:
107+
self._attr_unique_id += "-valance"
93108

94109

95110
class WebControlProRollerShutter(WebControlProCover):
96111
"""Representation of a WMS based roller shutter or blind."""
97112

98113
_attr_device_class = CoverDeviceClass.SHUTTER
99-
_drive_action_desc = (
100-
WMS_WebControl_pro_API_actionDescription.RollerShutterBlindDrive
101-
)
114+
_drive_action_desc = ACTION_DESC.RollerShutterBlindDrive

tests/components/wmspro/conftest.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,18 @@ def mock_hub_configuration_prod_awning_dimmer() -> Generator[AsyncMock]:
7070
yield mock_hub_configuration
7171

7272

73+
@pytest.fixture
74+
def mock_hub_configuration_prod_awning_valance() -> Generator[AsyncMock]:
75+
"""Override WebControlPro._getConfiguration."""
76+
with patch(
77+
"wmspro.webcontrol.WebControlPro._getConfiguration",
78+
return_value=load_json_object_fixture(
79+
"config_prod_awning_valance.json", DOMAIN
80+
),
81+
) as mock_hub_configuration:
82+
yield mock_hub_configuration
83+
84+
7385
@pytest.fixture
7486
def mock_hub_configuration_prod_roller_shutter() -> Generator[AsyncMock]:
7587
"""Override WebControlPro._getConfiguration."""
@@ -114,6 +126,16 @@ def mock_hub_status_prod_roller_shutter() -> Generator[AsyncMock]:
114126
yield mock_hub_status
115127

116128

129+
@pytest.fixture
130+
def mock_hub_status_prod_valance() -> Generator[AsyncMock]:
131+
"""Override WebControlPro._getStatus."""
132+
with patch(
133+
"wmspro.webcontrol.WebControlPro._getStatus",
134+
return_value=load_json_object_fixture("status_prod_valance.json", DOMAIN),
135+
) as mock_hub_status:
136+
yield mock_hub_status
137+
138+
117139
@pytest.fixture
118140
def mock_dest_refresh() -> Generator[AsyncMock]:
119141
"""Override Destination.refresh."""
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"command": "getConfiguration",
3+
"protocolVersion": "1.0.0",
4+
"destinations": [
5+
{
6+
"id": 58717,
7+
"animationType": 1,
8+
"names": ["Markise", "", "", ""],
9+
"actions": [
10+
{
11+
"id": 0,
12+
"actionType": 0,
13+
"actionDescription": 0,
14+
"minValue": 0,
15+
"maxValue": 100
16+
},
17+
{
18+
"id": 2,
19+
"actionType": 0,
20+
"actionDescription": 1,
21+
"minValue": 0,
22+
"maxValue": 100
23+
},
24+
{
25+
"id": 16,
26+
"actionType": 6,
27+
"actionDescription": 12
28+
},
29+
{
30+
"id": 22,
31+
"actionType": 8,
32+
"actionDescription": 13
33+
}
34+
]
35+
}
36+
],
37+
"rooms": [
38+
{
39+
"id": 62571,
40+
"name": "Raum 0",
41+
"destinations": [58717],
42+
"scenes": []
43+
}
44+
],
45+
"scenes": []
46+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"command": "getStatus",
3+
"protocolVersion": "1.0.0",
4+
"details": [
5+
{
6+
"destinationId": 58717,
7+
"data": {
8+
"drivingCause": 0,
9+
"heartbeatError": false,
10+
"blocking": false,
11+
"productData": [
12+
{
13+
"actionId": 0,
14+
"value": {
15+
"percentage": 100
16+
}
17+
},
18+
{
19+
"actionId": 2,
20+
"value": {
21+
"percentage": 100
22+
}
23+
}
24+
]
25+
}
26+
}
27+
]
28+
}

tests/components/wmspro/test_cover.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,11 @@ async def test_cover_update(
8181
"mock_hub_status_prod_awning",
8282
"cover.markise",
8383
),
84+
(
85+
"mock_hub_configuration_prod_awning_valance",
86+
"mock_hub_status_prod_valance",
87+
"cover.markise_2",
88+
),
8489
(
8590
"mock_hub_configuration_prod_roller_shutter",
8691
"mock_hub_status_prod_roller_shutter",
@@ -159,6 +164,11 @@ async def test_cover_open_and_close(
159164
"mock_hub_status_prod_awning",
160165
"cover.markise",
161166
),
167+
(
168+
"mock_hub_configuration_prod_awning_valance",
169+
"mock_hub_status_prod_valance",
170+
"cover.markise_2",
171+
),
162172
(
163173
"mock_hub_configuration_prod_roller_shutter",
164174
"mock_hub_status_prod_roller_shutter",
@@ -218,6 +228,11 @@ async def test_cover_open_to_pos(
218228
"mock_hub_status_prod_awning",
219229
"cover.markise",
220230
),
231+
(
232+
"mock_hub_configuration_prod_awning_valance",
233+
"mock_hub_status_prod_valance",
234+
"cover.markise_2",
235+
),
221236
(
222237
"mock_hub_configuration_prod_roller_shutter",
223238
"mock_hub_status_prod_roller_shutter",

0 commit comments

Comments
 (0)