Skip to content

Commit e43a9b0

Browse files
authored
Merge pull request #256 from plugwise/sense
Update sense parameter handling and initialisation
2 parents 0dd7182 + 9676a39 commit e43a9b0

File tree

5 files changed

+57
-46
lines changed

5 files changed

+57
-46
lines changed

plugwise_usb/api.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ class NodeFeature(str, Enum):
5252
RELAY_INIT = "relay_init"
5353
RELAY_LOCK = "relay_lock"
5454
SWITCH = "switch"
55+
SENSE = "sense"
5556
TEMPERATURE = "temperature"
5657

5758

@@ -80,6 +81,7 @@ class NodeType(Enum):
8081
NodeFeature.MOTION,
8182
NodeFeature.MOTION_CONFIG,
8283
NodeFeature.TEMPERATURE,
84+
NodeFeature.SENSE,
8385
NodeFeature.SWITCH,
8486
)
8587

@@ -229,6 +231,12 @@ class EnergyStatistics:
229231
day_production: float | None = None
230232
day_production_reset: datetime | None = None
231233

234+
@dataclass
235+
class SenseStatistics:
236+
"""Sense statistics collection."""
237+
238+
temperature: float | None = None
239+
humidity: float | None = None
232240

233241
class PlugwiseNode(Protocol):
234242
"""Protocol definition of a Plugwise device node."""

plugwise_usb/nodes/helpers/firmware.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ class SupportedVersions(NamedTuple):
156156
FEATURE_SUPPORTED_AT_FIRMWARE: Final = {
157157
NodeFeature.BATTERY: 2.0,
158158
NodeFeature.INFO: 2.0,
159+
NodeFeature.SENSE: 2.0,
159160
NodeFeature.TEMPERATURE: 2.0,
160161
NodeFeature.HUMIDITY: 2.0,
161162
NodeFeature.ENERGY: 2.0,

plugwise_usb/nodes/node.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
RelayConfig,
2626
RelayLock,
2727
RelayState,
28+
SenseStatistics,
2829
)
2930
from ..connection import StickController
3031
from ..constants import SUPPRESS_INITIALIZATION_WARNINGS, TYPE_MODEL, UTF8
@@ -192,14 +193,6 @@ def features(self) -> tuple[NodeFeature, ...]:
192193
"""Supported feature types of node."""
193194
return self._features
194195

195-
@property
196-
@raise_not_loaded
197-
def humidity(self) -> float:
198-
"""Humidity state."""
199-
if NodeFeature.HUMIDITY not in self._features:
200-
raise FeatureError(f"Humidity state is not supported for node {self.mac}")
201-
raise NotImplementedError()
202-
203196
@property
204197
def is_battery_powered(self) -> bool:
205198
"""Return if node is battery powered."""
@@ -320,13 +313,12 @@ def switch(self) -> bool:
320313

321314
@property
322315
@raise_not_loaded
323-
def temperature(self) -> float:
324-
"""Temperature value."""
325-
if NodeFeature.TEMPERATURE not in self._features:
316+
def sense(self) -> SenseStatistics:
317+
"""Sense statistics."""
318+
if NodeFeature.SENSE not in self._features:
326319
raise FeatureError(
327-
f"Temperature state is not supported for node {self.mac}"
320+
f"Sense statistics is not supported for node {self.mac}"
328321
)
329-
raise NotImplementedError()
330322

331323
# endregion
332324

plugwise_usb/nodes/sense.py

Lines changed: 41 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import logging
77
from typing import Any, Final
88

9-
from ..api import NodeEvent, NodeFeature
9+
from ..api import NodeEvent, NodeFeature, SenseStatistics
1010
from ..connection import StickController
1111
from ..exceptions import MessageError, NodeError
1212
from ..messages.responses import SENSE_REPORT_ID, PlugwiseResponse, SenseReportResponse
@@ -25,8 +25,7 @@
2525

2626
SENSE_FEATURES: Final = (
2727
NodeFeature.INFO,
28-
NodeFeature.TEMPERATURE,
29-
NodeFeature.HUMIDITY,
28+
NodeFeature.SENSE,
3029
)
3130

3231

@@ -43,8 +42,7 @@ def __init__(
4342
"""Initialize Scan Device."""
4443
super().__init__(mac, address, controller, loaded_callback)
4544

46-
self._humidity: float | None = None
47-
self._temperature: float | None = None
45+
self._sense_statistics = SenseStatistics()
4846

4947
self._sense_subscription: Callable[[], None] | None = None
5048

@@ -56,16 +54,17 @@ async def load(self) -> bool:
5654
self._node_info.is_battery_powered = True
5755
if self._cache_enabled:
5856
_LOGGER.debug("Loading Sense node %s from cache", self._node_info.mac)
59-
if await self._load_from_cache():
60-
self._loaded = True
61-
self._setup_protocol(
62-
SENSE_FIRMWARE_SUPPORT,
63-
(NodeFeature.INFO, NodeFeature.TEMPERATURE, NodeFeature.HUMIDITY),
64-
)
65-
if await self.initialize():
66-
await self._loaded_callback(NodeEvent.LOADED, self.mac)
67-
return True
68-
57+
await self._load_from_cache()
58+
else:
59+
self._load_defaults()
60+
self._loaded = True
61+
self._setup_protocol(
62+
SENSE_FIRMWARE_SUPPORT,
63+
(NodeFeature.INFO, NodeFeature.SENSE),
64+
)
65+
if await self.initialize():
66+
await self._loaded_callback(NodeEvent.LOADED, self.mac)
67+
return True
6968
_LOGGER.debug("Loading of Sense node %s failed", self._node_info.mac)
7069
return False
7170

@@ -90,6 +89,24 @@ async def unload(self) -> None:
9089
self._sense_subscription()
9190
await super().unload()
9291

92+
def _load_defaults(self) -> None:
93+
"""Load default configuration settings."""
94+
super()._load_defaults()
95+
self._sense_statistics = SenseStatistics(
96+
temperature=0.0,
97+
humidity=0.0,
98+
)
99+
100+
# region properties
101+
102+
@property
103+
@raise_not_loaded
104+
def sense_statistics(self) -> SenseStatistics:
105+
"""Sense Statistics."""
106+
return self._sense_statistics
107+
108+
# end region
109+
93110
async def _sense_report(self, response: PlugwiseResponse) -> bool:
94111
"""Process sense report message to extract current temperature and humidity values."""
95112
if not isinstance(response, SenseReportResponse):
@@ -99,25 +116,24 @@ async def _sense_report(self, response: PlugwiseResponse) -> bool:
99116
report_received = False
100117
await self._available_update_state(True, response.timestamp)
101118
if response.temperature.value != 65535:
102-
self._temperature = int(
119+
self._sense_statistics.temperature = float(
103120
SENSE_TEMPERATURE_MULTIPLIER * (response.temperature.value / 65536)
104121
- SENSE_TEMPERATURE_OFFSET
105122
)
106-
await self.publish_feature_update_to_subscribers(
107-
NodeFeature.TEMPERATURE, self._temperature
108-
)
109123
report_received = True
110124

111125
if response.humidity.value != 65535:
112-
self._humidity = int(
126+
self._sense_statistics.humidity = float(
113127
SENSE_HUMIDITY_MULTIPLIER * (response.humidity.value / 65536)
114128
- SENSE_HUMIDITY_OFFSET
115129
)
130+
report_received = True
131+
132+
if report_received:
116133
await self.publish_feature_update_to_subscribers(
117-
NodeFeature.HUMIDITY, self._humidity
134+
NodeFeature.SENSE, self._sense_statistics
118135
)
119-
report_received = True
120-
136+
121137
return report_received
122138

123139
@raise_not_loaded
@@ -136,12 +152,10 @@ async def get_state(self, features: tuple[NodeFeature]) -> dict[NodeFeature, Any
136152
)
137153

138154
match feature:
139-
case NodeFeature.TEMPERATURE:
140-
states[NodeFeature.TEMPERATURE] = self._temperature
141-
case NodeFeature.HUMIDITY:
142-
states[NodeFeature.HUMIDITY] = self._humidity
143155
case NodeFeature.PING:
144156
states[NodeFeature.PING] = await self.ping_update()
157+
case NodeFeature.SENSE:
158+
states[NodeFeature.SENSE] = self._sense_statistics
145159
case _:
146160
state_result = await super().get_state((feature,))
147161
states[feature] = state_result[feature]

tests/test_usb.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -614,9 +614,7 @@ async def test_stick_node_discovered_subscription(
614614
with pytest.raises(pw_exceptions.FeatureError):
615615
assert stick.nodes["5555555555555555"].power
616616
with pytest.raises(pw_exceptions.FeatureError):
617-
assert stick.nodes["5555555555555555"].humidity
618-
with pytest.raises(pw_exceptions.FeatureError):
619-
assert stick.nodes["5555555555555555"].temperature
617+
assert stick.nodes["5555555555555555"].sense
620618
with pytest.raises(pw_exceptions.FeatureError):
621619
assert stick.nodes["5555555555555555"].energy
622620

@@ -847,9 +845,7 @@ async def test_node_relay_and_power(self, monkeypatch: pytest.MonkeyPatch) -> No
847845
with pytest.raises(pw_exceptions.FeatureError):
848846
assert stick.nodes["0098765432101234"].switch
849847
with pytest.raises(pw_exceptions.FeatureError):
850-
assert stick.nodes["0098765432101234"].humidity
851-
with pytest.raises(pw_exceptions.FeatureError):
852-
assert stick.nodes["0098765432101234"].temperature
848+
assert stick.nodes["0098765432101234"].sense
853849

854850
# Test relay init
855851
# load node 2222222222222222 which has

0 commit comments

Comments
 (0)