Skip to content

Commit 753b93f

Browse files
committed
Update switch to return SwitchGroup object conforming to other node implementations.
Update switch to publish switch group number
1 parent 895142e commit 753b93f

File tree

6 files changed

+62
-41
lines changed

6 files changed

+62
-41
lines changed

plugwise_usb/api.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ class NodeFeature(str, Enum):
5353
RELAY = "relay"
5454
RELAY_INIT = "relay_init"
5555
RELAY_LOCK = "relay_lock"
56-
SWITCH = "switch"
56+
SWITCH_GROUP_1 = "switch_group_1"
57+
SWITCH_GROUP_2 = "switch_group_2"
5758
SENSE = "sense"
5859
TEMPERATURE = "temperature"
5960

@@ -86,7 +87,8 @@ class NodeType(Enum):
8687
NodeFeature.MOTION_CONFIG,
8788
NodeFeature.TEMPERATURE,
8889
NodeFeature.SENSE,
89-
NodeFeature.SWITCH,
90+
NodeFeature.SWITCH_GROUP_1,
91+
NodeFeature.SWITCH_GROUP_2,
9092
)
9193

9294

@@ -205,6 +207,15 @@ class RelayState:
205207
timestamp: datetime | None = None
206208

207209

210+
@dataclass()
211+
class SwitchGroup:
212+
"""Status of Switch."""
213+
214+
state: bool | None = None
215+
group: int | None = None
216+
timestamp: datetime | None = None
217+
218+
208219
@dataclass(frozen=True)
209220
class MotionState:
210221
"""Status of motion sensor."""

plugwise_usb/messages/responses.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,11 @@ def switch_state(self) -> bool:
858858
"""Return state of switch (True = On, False = Off)."""
859859
return self._power_state.value != 0
860860

861+
@property
862+
def switch_group(self) -> int:
863+
"""Return group number."""
864+
return self.group.value
865+
861866
def __repr__(self) -> str:
862867
"""Convert request into writable str."""
863868
return f"{super().__repr__()[:-1]}, power_state={self._power_state.value}, group={self.group.value})"

plugwise_usb/nodes/helpers/firmware.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,8 @@ class SupportedVersions(NamedTuple):
168168
NodeFeature.RELAY_LOCK: 2.0,
169169
NodeFeature.MOTION: 2.0,
170170
NodeFeature.MOTION_CONFIG: 2.0,
171-
NodeFeature.SWITCH: 2.0,
171+
NodeFeature.SWITCH_GROUP_1: 2.0,
172+
NodeFeature.SWITCH_GROUP_2: 2.0,
172173
}
173174

174175
# endregion

plugwise_usb/nodes/node.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ def relay_lock(self) -> RelayLock:
315315
@raise_not_loaded
316316
def switch(self) -> bool:
317317
"""Switch button value."""
318-
if NodeFeature.SWITCH not in self._features:
318+
if NodeFeature.SWITCH_GROUP_1 not in self._features:
319319
raise FeatureError(f"Switch value is not supported for node {self.mac}")
320320
raise NotImplementedError()
321321

plugwise_usb/nodes/switch.py

Lines changed: 33 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
from collections.abc import Awaitable, Callable
77
from datetime import datetime
88
import logging
9-
from typing import Any, Final
9+
from typing import Any
1010

11-
from ..api import NodeEvent, NodeFeature
11+
from ..api import NodeEvent, NodeFeature, SwitchGroup
1212
from ..connection import StickController
1313
from ..exceptions import MessageError, NodeError
1414
from ..messages.responses import (
@@ -22,9 +22,6 @@
2222

2323
_LOGGER = logging.getLogger(__name__)
2424

25-
CACHE_SWITCH_STATE: Final = "switch_state"
26-
CACHE_SWITCH_TIMESTAMP: Final = "switch_timestamp"
27-
2825

2926
class PlugwiseSwitch(NodeSED):
3027
"""Plugwise Switch node."""
@@ -39,7 +36,8 @@ def __init__(
3936
"""Initialize Scan Device."""
4037
super().__init__(mac, address, controller, loaded_callback)
4138
self._switch_subscription: Callable[[], None] | None = None
42-
self._switch_state: bool | None = None
39+
self._switch_group_1 = SwitchGroup()
40+
self._switch_group_2 = SwitchGroup()
4341

4442
async def load(self) -> bool:
4543
"""Load and activate Switch node features."""
@@ -57,7 +55,8 @@ async def load(self) -> bool:
5755
NodeFeature.BATTERY,
5856
NodeFeature.INFO,
5957
NodeFeature.PING,
60-
NodeFeature.SWITCH,
58+
NodeFeature.SWITCH_GROUP_1,
59+
NodeFeature.SWITCH_GROUP_2,
6160
),
6261
)
6362
if await self.initialize():
@@ -73,7 +72,7 @@ async def initialize(self) -> bool:
7372
return True
7473

7574
self._switch_subscription = await self._message_subscribe(
76-
self._switch_group,
75+
self._switch_response,
7776
self._mac_in_bytes,
7877
(NODE_SWITCH_GROUP_ID,),
7978
)
@@ -92,49 +91,48 @@ async def unload(self) -> None:
9291
@raise_not_loaded
9392
def switch(self) -> bool:
9493
"""Current state of switch."""
95-
return bool(self._switch_state)
94+
return bool(self._switch_group_1.state)
9695

9796
# endregion
9897

99-
async def _switch_group(self, response: PlugwiseResponse) -> bool:
98+
async def _switch_response(self, response: PlugwiseResponse) -> bool:
10099
"""Switch group request from Switch."""
101100
if not isinstance(response, NodeSwitchGroupResponse):
102101
raise MessageError(
103102
f"Invalid response message type ({response.__class__.__name__}) received, expected NodeSwitchGroupResponse"
104103
)
105104
await gather(
106105
self._available_update_state(True, response.timestamp),
107-
self._switch_state_update(response.switch_state, response.timestamp),
106+
self._switch_state_update(
107+
response.switch_state, response.switch_group, response.timestamp
108+
),
108109
)
109110
return True
110111

111112
async def _switch_state_update(
112-
self, switch_state: bool, timestamp: datetime
113+
self, switch_state: bool, switch_group: int, timestamp: datetime
113114
) -> None:
114115
"""Process switch state update."""
115116
_LOGGER.debug(
116-
"_switch_state_update for %s: %s -> %s",
117+
"_switch_state_update for %s: %s",
117118
self.name,
118-
self._switch_state,
119119
switch_state,
120120
)
121-
state_update = False
122-
# Update cache
123-
self._set_cache(CACHE_SWITCH_STATE, str(switch_state))
124-
# Check for a state change
125-
if self._switch_state != switch_state:
126-
self._switch_state = switch_state
127-
state_update = True
128-
129-
self._set_cache(CACHE_SWITCH_TIMESTAMP, timestamp)
130-
if state_update:
131-
await gather(
132-
*[
133-
self.publish_feature_update_to_subscribers(
134-
NodeFeature.SWITCH, self._switch_state
135-
),
136-
self.save_cache(),
137-
]
121+
if switch_group == 1:
122+
self._switch_group_1.state = switch_state
123+
self._switch_group_1.group = switch_group
124+
self._switch_group_1.timestampe = timestamp
125+
126+
await self.publish_feature_update_to_subscribers(
127+
NodeFeature.SWITCH_GROUP_1, self._switch_group_1
128+
)
129+
elif switch_group == 2:
130+
self._switch_group_2.state = switch_state
131+
self._switch_group_2.group = switch_group
132+
self._switch_group_2.timestampe = timestamp
133+
134+
await self.publish_feature_update_to_subscribers(
135+
NodeFeature.SWITCH_GROUP_2, self._switch_group_2
138136
)
139137

140138
@raise_not_loaded
@@ -154,8 +152,10 @@ async def get_state(self, features: tuple[NodeFeature]) -> dict[NodeFeature, Any
154152
)
155153

156154
match feature:
157-
case NodeFeature.SWITCH:
158-
states[NodeFeature.SWITCH] = self._switch_state
155+
case NodeFeature.SWITCH_GROUP_1:
156+
states[NodeFeature.SWITCH_GROUP_1] = self._switch_group_1
157+
case NodeFeature.SWITCH_GROUP_2:
158+
states[NodeFeature.SWITCH_GROUP_2] = self._switch_group_2
159159
case _:
160160
state_result = await super().get_state((feature,))
161161
states[feature] = state_result[feature]

tests/test_usb.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2363,7 +2363,8 @@ async def load_callback(event: pw_api.NodeEvent, mac: str) -> None: # type: ign
23632363
pw_api.NodeFeature.BATTERY,
23642364
pw_api.NodeFeature.INFO,
23652365
pw_api.NodeFeature.PING,
2366-
pw_api.NodeFeature.SWITCH,
2366+
pw_api.NodeFeature.SWITCH_GROUP_1,
2367+
pw_api.NodeFeature.SWITCH_GROUP_2,
23672368
)
23682369
)
23692370

@@ -2372,7 +2373,8 @@ async def load_callback(event: pw_api.NodeEvent, mac: str) -> None: # type: ign
23722373
pw_api.NodeFeature.AVAILABLE,
23732374
pw_api.NodeFeature.BATTERY,
23742375
pw_api.NodeFeature.INFO,
2375-
pw_api.NodeFeature.SWITCH,
2376+
pw_api.NodeFeature.SWITCH_GROUP_1,
2377+
pw_api.NodeFeature.SWITCH_GROUP_2,
23762378
)
23772379
)
23782380
assert not state[pw_api.NodeFeature.AVAILABLE].state
@@ -2633,15 +2635,17 @@ async def test_node_discovery_and_load( # noqa: PLR0915
26332635
pw_api.NodeFeature.BATTERY,
26342636
pw_api.NodeFeature.INFO,
26352637
pw_api.NodeFeature.PING,
2636-
pw_api.NodeFeature.SWITCH,
2638+
pw_api.NodeFeature.SWITCH_GROUP_1,
2639+
pw_api.NodeFeature.SWITCH_GROUP_2,
26372640
)
26382641
)
26392642
state = await stick.nodes["8888888888888888"].get_state(
26402643
(
26412644
pw_api.NodeFeature.AVAILABLE,
26422645
pw_api.NodeFeature.BATTERY,
26432646
pw_api.NodeFeature.INFO,
2644-
pw_api.NodeFeature.SWITCH,
2647+
pw_api.NodeFeature.SWITCH_GROUP_1,
2648+
pw_api.NodeFeature.SWITCH_GROUP_2,
26452649
)
26462650
)
26472651
assert state[pw_api.NodeFeature.AVAILABLE].state

0 commit comments

Comments
 (0)