owlsensor 0.2__tar.gz → 0.3.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: owlsensor
3
- Version: 0.2
3
+ Version: 0.3.1
4
4
  Summary: Library to read data from OWL Energy meters
5
5
  Home-page: https://github.com/PBrunot/owlsensor
6
6
  Author: Pascal Brunot
@@ -0,0 +1,42 @@
1
+ owlsensor - Library for OWL CM 160 Energy meter
2
+ ================================================
3
+
4
+ This library lets you read sensor data from serial-connected OWL Energy meter.
5
+ It current supports the following model:
6
+
7
+ - CM 160
8
+
9
+ Usage
10
+ =====
11
+
12
+ * Create a CMDataCollector with port name as first argument, and OWL model as second argument,
13
+
14
+ ```python
15
+ cm.CMDataCollector("COM4", cm.SUPPORTED_SENSORS["TheOWL,CM160"])
16
+ ```
17
+
18
+ ```python
19
+ cm.CMDataCollector("/dev/ttyUSB0", cm.SUPPORTED_SENSORS["TheOWL,CM160"])
20
+ ```
21
+
22
+ * You can add several devices the same way, on different serial ports.
23
+
24
+ * Connect will be called automatically by read_data.
25
+
26
+ ```python
27
+ await s.connect()
28
+ await s.read_data()
29
+ ```
30
+
31
+ * read_data returns a dict (CMVALS=[CURRENT]) containing the acquired real-time value. Currently only current in ampere is returned.
32
+
33
+ ```
34
+ print(await s.read_data())
35
+
36
+ {'Current': 4.1}
37
+ ```
38
+
39
+ Limitations
40
+ ===========
41
+
42
+ * Historical data returned by the device at connection is discarded, only realtime transmissions are available
@@ -0,0 +1,13 @@
1
+ from .serial_cm import CMDataCollector, SUPPORTED_SENSORS
2
+
3
+ async def get_async_datacollector(port_url: str, model: str, scan_interval_s: int = 30) -> CMDataCollector:
4
+ """
5
+ Return asynchronous version of CMDataCollector interface
6
+ :param port_url: serial port, i.e. '/dev/ttyUSB0'
7
+ :param model: device type, i.e. "CM160"
8
+ :return: asynchronous implementation of Monoprice interface
9
+ """
10
+ if not model in SUPPORTED_SENSORS:
11
+ return None
12
+
13
+ return CMDataCollector(port_url, SUPPORTED_SENSORS[model], scan_interval_s)
@@ -1,5 +1,5 @@
1
1
  """ Constants """
2
- PACKET_LENGTH = 11
2
+
3
3
  ID_REPLY = "IDTCMV001"
4
4
  ID_WAIT_HISTORY = "IDTWAITPC"
5
5
  CONTINUE_REQUEST = [0xa5]
@@ -7,3 +7,12 @@ START_REQUEST = [0x5a]
7
7
  PACKET_ID_HISTORY = 0xa9
8
8
  PACKET_ID_HISTORY_DATA = 0x59
9
9
  PACKET_ID_REALTIME = 0x51
10
+
11
+ RECORD_LENGTH = "RL"
12
+ CURRENT = "Current"
13
+ BAUD_RATE = "BAUD"
14
+ BYTE_ORDER = "BO",
15
+ LSB = "lsb"
16
+ MSB = "msb"
17
+ MULTIPLIER = "MP"
18
+ TIMEOUT = "TO"
@@ -4,27 +4,15 @@ Reading data from particulate matter sensors with a serial interface.
4
4
  import time
5
5
  import logging
6
6
  import asyncio
7
+ from serial import SerialException
7
8
  import serial_asyncio_fast
8
9
 
9
- from .const import CONTINUE_REQUEST, ID_WAIT_HISTORY,ID_REPLY, PACKET_ID_HISTORY, PACKET_ID_HISTORY_DATA, PACKET_ID_REALTIME, START_REQUEST
10
-
11
- STARTBLOCK = "SB"
12
- RECORD_LENGTH = "RL"
13
- # Ofsets of the PM data (always 2 byte)
14
- CURRENT = "Current"
15
- BAUD_RATE = "BAUD"
16
- BYTE_ORDER = "BO",
17
- LSB = "lsb"
18
- MSB = "msb"
19
- DTR_ON = "DTR"
20
- DTR_OFF = "NOT_DTR"
21
- MULTIPLIER = "MP"
22
- TIMEOUT = "TO"
10
+ from .const import *
11
+
23
12
 
24
13
  # Owl CM160 settings
25
14
  OWL_CM160 = {
26
15
  "TheOWL": "CM160",
27
- STARTBLOCK: bytes([0x42, 0x4d, 0x00, 0x14]),
28
16
  RECORD_LENGTH: 11,
29
17
  CURRENT: 8,
30
18
  BAUD_RATE: 250000,
@@ -34,7 +22,7 @@ OWL_CM160 = {
34
22
  }
35
23
 
36
24
  SUPPORTED_SENSORS = {
37
- "TheOWL,CM160": OWL_CM160
25
+ "CM160": OWL_CM160
38
26
  }
39
27
 
40
28
  DEVICE_STATES = {
@@ -75,23 +63,41 @@ class CMDataCollector():
75
63
  self.reader = None
76
64
  self.writer = None
77
65
  self.baudrate = configuration[BAUD_RATE]
66
+ self.connected = False
67
+ self.updateTask = None
78
68
 
79
- async def connect(self):
69
+ async def connect(self) -> bool:
80
70
  """Establish the serial connection asynchronously."""
81
- self.reader, self.writer = await serial_asyncio_fast.open_serial_connection(
82
- url=self.serialdevice,
83
- baudrate=self.baudrate
84
- )
71
+ self.connected = False
72
+ try:
73
+ self.reader, self.writer = await serial_asyncio_fast.open_serial_connection(
74
+ url=self.serialdevice,
75
+ baudrate=self.baudrate
76
+ )
77
+ except SerialException as ex:
78
+ LOGGER.warning("Connect: %s", ex)
79
+ return False
80
+
81
+ self.connected = True
82
+
83
+ if self.updateTask is not None:
84
+ try:
85
+ self.updateTask.cancel()
86
+ self.updateTask = None
87
+ except Exception as e:
88
+ LOGGER.warning("Exception while cancelling update Task: %s", e)
85
89
 
86
90
  if self.scan_interval > 0:
87
- asyncio.create_task(self.refresh())
91
+ self.updateTask = asyncio.create_task(self.refresh())
92
+
93
+ return True
88
94
 
89
95
  async def refresh(self):
90
96
  """Asynchronous background refreshing task."""
91
97
  while True:
92
98
  await self.read_data()
93
99
  await asyncio.sleep(self.scan_interval)
94
-
100
+
95
101
  async def send_data(self, data: bytes):
96
102
  LOGGER.debug("-> %s", ''.join(format(x, '02x') for x in data))
97
103
  self.writer.write(data)
@@ -143,8 +149,13 @@ class CMDataCollector():
143
149
 
144
150
  return None
145
151
 
146
- async def read_data(self):
152
+ async def read_data(self) -> dict | None:
147
153
  """Read data from the serial interface asynchronously."""
154
+
155
+ if not self.connected:
156
+ if not await self.connect():
157
+ return None
158
+
148
159
  mytime = asyncio.get_event_loop().time()
149
160
  if (self.last_poll is not None) and \
150
161
  (mytime - self.last_poll) <= 15 and \
@@ -155,12 +166,17 @@ class CMDataCollector():
155
166
  finished = False
156
167
 
157
168
  while not finished:
158
- packet = await self.get_packet()
159
- if packet:
160
- result = await self.parse_packet(packet)
161
- if result is not None:
162
- res = result
163
- finished = True
169
+ try:
170
+ packet = await self.get_packet()
171
+ if packet:
172
+ result = await self.parse_packet(packet)
173
+ if result is not None:
174
+ res = result
175
+ finished = True
176
+ except SerialException as ex:
177
+ LOGGER.warning(ex)
178
+ self.connected = False
179
+ return None
164
180
 
165
181
  self._data = res
166
182
  self.last_poll = asyncio.get_event_loop().time()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: owlsensor
3
- Version: 0.2
3
+ Version: 0.3.1
4
4
  Summary: Library to read data from OWL Energy meters
5
5
  Home-page: https://github.com/PBrunot/owlsensor
6
6
  Author: Pascal Brunot
@@ -1,7 +1,7 @@
1
1
  from setuptools import setup, find_packages
2
2
 
3
3
  setup(name='owlsensor',
4
- version='0.2',
4
+ version='0.3.1',
5
5
  description='Library to read data from OWL Energy meters',
6
6
  long_description='This package is designed for integrating into Home Assistant a serial-connected OWL energy meter.',
7
7
  long_description_content_type = 'text/x-rst',
owlsensor-0.2/README.rst DELETED
@@ -1,7 +0,0 @@
1
- owlsensor - Library for OWL CM 160 Energy meter
2
- ================================================
3
-
4
- This library lets you read sensor data from serial-connected OWL Energy meter.
5
- It current supports the following model:
6
-
7
- - CM 160
File without changes
File without changes
File without changes