Skip to content

Commit e5ad7e0

Browse files
authored
Merge pull request #55 from plugwise/refactor_stick_api
0.9.0 - API change for stick
2 parents b0bb0be + 6e9e962 commit e5ad7e0

File tree

15 files changed

+945
-543
lines changed

15 files changed

+945
-543
lines changed

CHANGELOG.md

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,50 @@
11
# Changelog
22

3+
## 0.9.0 - API change for stick
4+
5+
- Improvement: Debounce relay state
6+
- Improvement: Prioritize request so requests like switching a relay get send out before power measurement requests.
7+
- Improvement: Dynamically change the refresh interval based on the actual discovered nodes with power measurement capabilities
8+
- Added: New property attributes for USB-stick.
9+
The old methods are still available but will give a deprecate warning
10+
- Stick
11+
- `devices` (dict) - All discovered and supported plugwise devices with the MAC address as their key
12+
- `joined_nodes` (integer) - Total number of registered nodes at Plugwise Circle+
13+
- `mac` (string) - The MAC address of the USB-Stick
14+
- `network_state` (boolean) - The state (on-line/off-line) of the Plugwise network.
15+
- `network_id` (integer) - The ID of the Plugwise network.
16+
- `port` (string) - The port connection string
17+
- All plugwise devices
18+
- `available` (boolean) - The current network availability state of the device
19+
- `battery_powered` (boolean) - Indicates if device is battery powered
20+
- `features` (tuple) - List of supported attribute IDs
21+
- `firmware_version` (string) - Firmware version device is running
22+
- `hardware_model` (string) - Hardware model name
23+
- `hardware_version` (string) - Hardware version of device
24+
- `last_update` (datetime) - Date/time stamp of last received update from device
25+
- `mac` (string) - MAC address of device
26+
- `measures_power` (boolean) - Indicates if device supports power measurement
27+
- `name` (string) - Name of device based om hardware model and MAC address
28+
- `ping` (integer) - Network roundtrip time in milliseconds
29+
- `rssi_in` (integer) - Inbound RSSI level in DBm
30+
- `rssi_out` (integer) - Outbound RSSI level based on the received inbound RSSI level of the neighbor node in DBm
31+
- Scan devices
32+
- `motion` (boolean) - Current detection state of motion.
33+
- Sense devices
34+
- `humidity` (integer) - Last reported humidity value.
35+
- `temperature` (integer) - Last reported temperature value.
36+
- Circle/Circle+/Stealth devices
37+
- `current_power_usage` (float) - Current power usage (Watts) during the last second
38+
- `current_power_usage_8_sec` (float) - Current power usage (Watts) during the last 8 seconds
39+
- `power_consumption_current_hour` (float) - Total power consumption (kWh) this running hour
40+
- `power_consumption_previous_hour` (float) - Total power consumption (kWh) during the previous hour
41+
- `power_consumption_today` (float) - Total power consumption (kWh) of today
42+
- `power_consumption_yesterday` (float) - Total power consumption (kWh) during yesterday
43+
- `power_production_current_hour` (float) - Total power production (kWh) this hour
44+
- `relay_state` (boolean) - State of the output power relay. Setting this property will operate the relay
45+
- Switch devices
46+
- `switch` (boolean) - Last reported state of switch
47+
348
## 0.8.6 - Code quality improvements for stick
449

550
- Bug-fix: Power history was not reported (0 value) during last week of the month
@@ -17,9 +62,10 @@
1762
- Improvement: Resolves all flake8 comments
1863

1964
## 0.8.5 - Fix sensor scaling
20-
- Fix for via HA Core issue #44349
21-
- Fix other value scaling bugs
22-
- Remove aiohttp-workaround - issue solved in aiohttp 3.7.1
65+
66+
- Fix for via HA Core issue #44349
67+
- Fix other value scaling bugs
68+
- Remove aiohttp-workaround - issue solved in aiohttp 3.7.1
2369

2470
(## 0.8.4 - Not released: Fix "Gas Consumed Interval stays 0" )
2571

plugwise/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
"""Plugwise module."""
22

3-
__version__ = "0.8.6"
3+
__version__ = "0.9.0"
44

55
from plugwise.smile import Smile
66
from plugwise.stick import stick

plugwise/constants.py

Lines changed: 45 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,11 @@
136136
# Default sleep between sending messages
137137
SLEEP_TIME = 150 / 1000
138138

139+
# Message priority levels
140+
PRIORITY_HIGH = 1
141+
PRIORITY_LOW = 3
142+
PRIORITY_MEDIUM = 2
143+
139144
# Max seconds the internal clock of plugwise nodes
140145
# are allowed to drift in seconds
141146
MAX_TIME_DRIFT = 30
@@ -220,120 +225,112 @@
220225
CB_NEW_NODE = "NEW_NODE"
221226
CB_JOIN_REQUEST = "JOIN_REQUEST"
222227

223-
# Sensors
224-
SENSOR_AVAILABLE = {
228+
# Stick device features
229+
FEATURE_AVAILABLE = {
225230
"id": "available",
226231
"name": "Available",
227-
"state": "get_available",
232+
"state": "available",
228233
"unit": "state",
229234
}
230-
SENSOR_HUMIDITY = {
235+
FEATURE_HUMIDITY = {
231236
"id": "humidity",
232237
"name": "Humidity",
233-
"state": "get_humidity",
238+
"state": "humidity",
234239
"unit": "%",
235240
}
236-
SENSOR_MOTION = {
241+
FEATURE_MOTION = {
237242
"id": "motion",
238243
"name": "Motion",
239-
"state": "get_motion",
244+
"state": "motion",
240245
"unit": "state",
241246
}
242-
SENSOR_PING = {
247+
FEATURE_PING = {
243248
"id": "ping",
244249
"name": "Ping roundtrip",
245-
"state": "get_ping",
250+
"state": "ping",
246251
"unit": TIME_MILLISECONDS,
247252
}
248-
SENSOR_POWER_USE = {
253+
FEATURE_POWER_USE = {
249254
"id": "power_1s",
250255
"name": "Power usage",
251-
"state": "get_power_usage",
256+
"state": "current_power_usage",
252257
"unit": POWER_WATT,
253258
}
254-
SENSOR_POWER_USE_LAST_8_SEC = {
259+
FEATURE_POWER_USE_LAST_8_SEC = {
255260
"id": "power_8s",
256261
"name": "Power usage 8 seconds",
257-
"state": "get_power_usage_8_sec",
262+
"state": "current_power_usage_8_sec",
258263
"unit": POWER_WATT,
259264
}
260-
SENSOR_POWER_CONSUMPTION_CURRENT_HOUR = {
265+
FEATURE_POWER_CONSUMPTION_CURRENT_HOUR = {
261266
"id": "power_con_cur_hour",
262267
"name": "Power consumption current hour",
263-
"state": "get_power_consumption_current_hour",
268+
"state": "power_consumption_current_hour",
264269
"unit": ENERGY_KILO_WATT_HOUR,
265270
}
266-
SENSOR_POWER_CONSUMPTION_PREVIOUS_HOUR = {
271+
FEATURE_POWER_CONSUMPTION_PREVIOUS_HOUR = {
267272
"id": "power_con_prev_hour",
268273
"name": "Power consumption previous hour",
269-
"state": "get_power_consumption_previous_hour",
274+
"state": "power_consumption_previous_hour",
270275
"unit": ENERGY_KILO_WATT_HOUR,
271276
}
272-
SENSOR_POWER_CONSUMPTION_TODAY = {
277+
FEATURE_POWER_CONSUMPTION_TODAY = {
273278
"id": "power_con_today",
274279
"name": "Power consumption today",
275-
"state": "get_power_consumption_today",
280+
"state": "power_consumption_today",
276281
"unit": ENERGY_KILO_WATT_HOUR,
277282
}
278-
SENSOR_POWER_CONSUMPTION_YESTERDAY = {
283+
FEATURE_POWER_CONSUMPTION_YESTERDAY = {
279284
"id": "power_con_yesterday",
280285
"name": "Power consumption yesterday",
281-
"state": "get_power_consumption_yesterday",
286+
"state": "power_consumption_yesterday",
282287
"unit": ENERGY_KILO_WATT_HOUR,
283288
}
284-
SENSOR_POWER_PRODUCTION_CURRENT_HOUR = {
289+
FEATURE_POWER_PRODUCTION_CURRENT_HOUR = {
285290
"id": "power_prod_cur_hour",
286291
"name": "Power production current hour",
287-
"state": "get_power_production_current_hour",
292+
"state": "power_production_current_hour",
288293
"unit": ENERGY_KILO_WATT_HOUR,
289294
}
290-
SENSOR_POWER_PRODUCTION_PREVIOUS_HOUR = {
295+
FEATURE_POWER_PRODUCTION_PREVIOUS_HOUR = {
291296
"id": "power_prod_prev_hour",
292297
"name": "Power production previous hour",
293-
"state": "get_power_production_previous_hour",
298+
"state": "power_production_previous_hour",
294299
"unit": ENERGY_KILO_WATT_HOUR,
295300
}
296-
SENSOR_SWITCH = {
301+
FEATURE_RELAY = {
302+
"id": "relay",
303+
"name": "Relay state",
304+
"state": "relay_state",
305+
"unit": "state",
306+
}
307+
FEATURE_SWITCH = {
297308
"id": "switch",
298-
"name": "switch",
299-
"state": "get_switch_state",
309+
"name": "Switch state",
310+
"state": "switch_state",
300311
"unit": "state",
301312
}
302-
SENSOR_TEMPERATURE = {
313+
FEATURE_TEMPERATURE = {
303314
"id": "temperature",
304315
"name": "Temperature",
305-
"state": "get_temperature",
316+
"state": "temperature",
306317
"unit": TEMP_CELSIUS,
307318
}
308319

309320
# TODO: Need to validate RSSI sensors
310-
SENSOR_RSSI_IN = {
321+
FEATURE_RSSI_IN = {
311322
"id": "RSSI_in",
312323
"name": "RSSI in",
313-
"state": "get_rssi_in",
324+
"state": "rssi_in",
314325
"unit": "Unknown",
315326
}
316-
SENSOR_RSSI_OUT = {
327+
FEATURE_RSSI_OUT = {
317328
"id": "RSSI_out",
318329
"name": "RSSI out",
319-
"state": "get_rssi_out",
330+
"state": "rssi_out",
320331
"unit": "Unknown",
321332
}
322333

323-
# Switches
324-
SWITCH_RELAY = {
325-
"id": "relay",
326-
"name": "Relay state",
327-
"state": "get_relay_state",
328-
"switch": "set_relay_state",
329-
}
330-
331-
# Home Assistant entities
332-
HA_SWITCH = "switch"
333-
HA_SENSOR = "sensor"
334-
HA_BINARY_SENSOR = "binary_sensor"
335-
336-
337334
### Smile constants ###
338335

339336
APPLIANCES = "/core/appliances"

plugwise/controller.py

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@
55
- handle the connection (connect/disconnect) to the USB-Stick
66
- take care for message acknowledgements based on sequence id's
77
- resend message requests when timeouts occurs
8-
- holds a sending queue (fifo)
8+
- holds a sending queue and submit messages based on the message priority (high, medium, low)
99
- passes received messages back to message processor (stick.py)
1010
- execution of callbacks after processing the response message
1111
1212
"""
1313

1414
from datetime import datetime, timedelta
1515
import logging
16-
import queue
16+
from queue import Empty, PriorityQueue
1717
import threading
1818
import time
1919

@@ -22,6 +22,7 @@
2222
from .constants import (
2323
MESSAGE_RETRY,
2424
MESSAGE_TIME_OUT,
25+
PRIORITY_MEDIUM,
2526
REQUEST_FAILED,
2627
REQUEST_SUCCESS,
2728
SLEEP_TIME,
@@ -62,7 +63,7 @@ def connect_to_stick(self, callback=None) -> bool:
6263
"""
6364
Connect to USB-Stick and startup all worker threads
6465
65-
Return: True when if successfully.
66+
Return: True when connection is successful.
6667
"""
6768
self.init_callback = callback
6869
# Open connection to USB Stick
@@ -77,7 +78,7 @@ def connect_to_stick(self, callback=None) -> bool:
7778
if self.connection.connect():
7879
_LOGGER.debug("Starting message controller threads...")
7980
# send daemon
80-
self._send_message_queue = queue.Queue()
81+
self._send_message_queue = PriorityQueue()
8182
self._run_send_message_thread = True
8283
self._send_message_thread = threading.Thread(
8384
None, self._send_message_loop, "send_messages_thread", (), {}
@@ -96,20 +97,32 @@ def connect_to_stick(self, callback=None) -> bool:
9697
_LOGGER.warning("Failed to connect to USB stick")
9798
return self.connection.is_connected()
9899

99-
def send(self, request: NodeRequest, callback=None, retry_counter=0):
100+
def send(
101+
self,
102+
request: NodeRequest,
103+
callback=None,
104+
retry_counter=0,
105+
priority=PRIORITY_MEDIUM,
106+
):
100107
"""Queue request message to be sent into Plugwise Zigbee network."""
101108
_LOGGER.debug(
102-
"Queue %s to be send with retry counter %s",
109+
"Queue %s to be send with retry counter %s and priority %s",
103110
request.__class__.__name__,
104111
str(retry_counter),
112+
str(priority),
105113
)
106114
self._send_message_queue.put(
107-
[
108-
request,
109-
callback,
115+
(
116+
priority,
110117
retry_counter,
111-
None,
112-
]
118+
datetime.now(),
119+
[
120+
request,
121+
callback,
122+
retry_counter,
123+
None,
124+
],
125+
)
113126
)
114127

115128
def resend(self, seq_id):
@@ -142,7 +155,7 @@ def resend(self, seq_id):
142155
if self.expected_responses[seq_id][1]:
143156
self.expected_responses[seq_id][1]()
144157
else:
145-
_LOGGER.warning(
158+
_LOGGER.info(
146159
"Resend %s for %s, retry %s of %s",
147160
_request,
148161
_mac,
@@ -180,8 +193,10 @@ def _send_message_loop(self):
180193
"""Daemon to send messages waiting in queue."""
181194
while self._run_send_message_thread:
182195
try:
183-
request_set = self._send_message_queue.get(block=True, timeout=1)
184-
except queue.Empty:
196+
_prio, _retry, _dt, request_set = self._send_message_queue.get(
197+
block=True, timeout=1
198+
)
199+
except Empty:
185200
time.sleep(SLEEP_TIME)
186201
else:
187202
# Calc next seq_id based last received ack message

plugwise/messages/responses.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ class NodeFeaturesResponse(NodeResponse):
495495

496496
def __init__(self):
497497
super().__init__()
498-
self.features = Int(0, 16)
498+
self.features = String(None, length=16)
499499
self.params += [self.features]
500500

501501

0 commit comments

Comments
 (0)