Skip to content

Commit b0bb0be

Browse files
authored
Merge pull request #53 from plugwise/refactor_stick
Refactor code for USB-stick
2 parents d1e91b3 + 6658825 commit b0bb0be

27 files changed

+1655
-2009
lines changed

.coveragerc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ omit=
44
*/venv/*
55
setup.py
66
plugwise/connections/*
7-
plugwise/message.py
7+
plugwise/controller.py
88
plugwise/messages/*
9-
plugwise/node.py
109
plugwise/nodes/*
1110
plugwise/parser.py
1211
plugwise/stick.py

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
# Changelog
22

3+
## 0.8.6 - Code quality improvements for stick
4+
5+
- Bug-fix: Power history was not reported (0 value) during last week of the month
6+
- Improvement: Validate message checksums
7+
- Improvement: Do a single ping request to validate if node is on-line
8+
- Improvement: Guard Scan sensitivity setting to medium
9+
- Improvement: Move general module code of messages, nodes, connection to the __init__.py files.
10+
- Improvement: Do proper timeout handling while sequence counter resets (once every 65532 messages)
11+
- Improvement: Better code separation. All logic is in their designated files:
12+
1. Connection (connection/*.py)
13+
2. Data parsing (parser.py)
14+
3. Data encoding/decoding of message (messages/*.py)
15+
4. Message handling - Initialization & transportation (controller.py)
16+
5. Message processing - Do the required stuff (stick.py & nodes/*.py)
17+
- Improvement: Resolves all flake8 comments
18+
319
## 0.8.5 - Fix sensor scaling
420
- Fix for via HA Core issue #44349
521
- Fix other value scaling bugs

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.5"
3+
__version__ = "0.8.6"
44

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

plugwise/connections/__init__.py

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,123 @@
1-
"""Plugwise connections."""
1+
"""Base class for serial or socket connections to USB-Stick."""
2+
import logging
3+
import queue
4+
import threading
5+
import time
6+
7+
from ..constants import SLEEP_TIME
8+
from ..messages.requests import NodeRequest
9+
10+
_LOGGER = logging.getLogger(__name__)
11+
12+
13+
class StickConnection:
14+
"""Generic Plugwise stick connection."""
15+
16+
def __init__(self, port, parser):
17+
"""Initialize StickConnection."""
18+
self.port = port
19+
self.parser = parser
20+
self.run_reader_thread = False
21+
self.run_writer_thread = False
22+
self._is_connected = False
23+
self._writer = None
24+
25+
self._reader_thread = None
26+
self._write_queue = None
27+
self._writer_thread = None
28+
29+
################################################
30+
### Open connection ###
31+
################################################
32+
33+
def connect(self) -> bool:
34+
"""Open the connection."""
35+
if not self._is_connected:
36+
self._open_connection()
37+
return self._is_connected
38+
39+
################################################
40+
### Reader ###
41+
################################################
42+
43+
def _reader_start(self, name):
44+
"""Start the reader thread to receive data."""
45+
self._reader_thread = threading.Thread(None, self._reader_deamon, name, (), {})
46+
self.run_reader_thread = True
47+
self._reader_thread.start()
48+
49+
def _reader_deamon(self):
50+
"""Thread to collect available data from connection."""
51+
while self.run_reader_thread:
52+
data = self._read_data()
53+
if data:
54+
self.parser(data)
55+
time.sleep(0.01)
56+
_LOGGER.debug("Reader daemon stopped")
57+
58+
################################################
59+
### Writer ###
60+
################################################
61+
62+
def _writer_start(self, name: str):
63+
"""Start the writer thread to send data."""
64+
self._write_queue = queue.Queue()
65+
self._writer_thread = threading.Thread(None, self._writer_daemon, name, (), {})
66+
self._writer_thread.daemon = True
67+
self.run_writer_thread = True
68+
self._writer_thread.start()
69+
70+
def _writer_daemon(self):
71+
"""Thread to write data from queue to existing connection."""
72+
while self.run_writer_thread:
73+
try:
74+
(message, callback) = self._write_queue.get(block=True, timeout=1)
75+
except queue.Empty:
76+
time.sleep(SLEEP_TIME)
77+
else:
78+
_LOGGER.debug(
79+
"Sending %s to plugwise stick (%s)",
80+
message.__class__.__name__,
81+
message.serialize(),
82+
)
83+
self._write_data(message.serialize())
84+
time.sleep(SLEEP_TIME)
85+
if callback:
86+
callback()
87+
_LOGGER.debug("Writer daemon stopped")
88+
89+
def send(self, message: NodeRequest, callback=None):
90+
"""Add message to write queue."""
91+
self._write_queue.put_nowait((message, callback))
92+
93+
################################################
94+
### Connection state ###
95+
################################################
96+
97+
def is_connected(self):
98+
"""Return connection state."""
99+
return self._is_connected
100+
101+
def read_thread_alive(self):
102+
"""Return state of write thread."""
103+
return self._reader_thread.isAlive() if self.run_reader_thread else False
104+
105+
def write_thread_alive(self):
106+
"""Return state of write thread."""
107+
return self._writer_thread.isAlive() if self.run_writer_thread else False
108+
109+
################################################
110+
### Close connection ###
111+
################################################
112+
113+
def disconnect(self):
114+
"""Close the connection."""
115+
if self._is_connected:
116+
self._is_connected = False
117+
self.run_writer_thread = False
118+
self.run_reader_thread = False
119+
max_wait = 5 * SLEEP_TIME
120+
while self._writer_thread.isAlive():
121+
time.sleep(SLEEP_TIME)
122+
max_wait -= SLEEP_TIME
123+
self._close_connection()

plugwise/connections/connection.py

Lines changed: 0 additions & 138 deletions
This file was deleted.

plugwise/connections/serial.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,18 @@
33

44
import serial
55

6-
from plugwise.connections.connection import StickConnection
7-
from plugwise.constants import BAUD_RATE, BYTE_SIZE, STOPBITS
8-
from plugwise.exceptions import PortError
6+
from ..connections import StickConnection
7+
from ..constants import BAUD_RATE, BYTE_SIZE, STOPBITS
8+
from ..exceptions import PortError
99

1010
_LOGGER = logging.getLogger(__name__)
1111

1212

1313
class PlugwiseUSBConnection(StickConnection):
1414
"""Simple wrapper around serial module."""
1515

16-
def __init__(self, port, stick=None):
17-
super().__init__(port, stick)
16+
def __init__(self, port, parser):
17+
super().__init__(port, parser)
1818
self._baud = BAUD_RATE
1919
self._byte_size = BYTE_SIZE
2020
self._stopbits = STOPBITS

plugwise/connections/socket.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22
import logging
33
import socket
44

5-
from plugwise.connections.connection import StickConnection
6-
from plugwise.exceptions import PortError
5+
from ..connections import StickConnection
6+
from ..exceptions import PortError
77

88
_LOGGER = logging.getLogger(__name__)
99

1010

1111
class SocketConnection(StickConnection):
1212
"""Wrapper for Socket connection configuration."""
1313

14-
def __init__(self, port, stick=None):
15-
super().__init__(port, stick)
14+
def __init__(self, port, parser):
15+
super().__init__(port, parser)
1616
# get the address from a <host>:<port> format
1717
port_split = self.port.split(":")
1818
self._socket_host = port_split[0]

0 commit comments

Comments
 (0)