|
27 | 27 | # along with SmartHomeNG.py. If not, see <http://www.gnu.org/licenses/>. |
28 | 28 | ######################################################################### |
29 | 29 |
|
30 | | - |
31 | | -__license__ = "GPL" |
32 | | -__version__ = "2.0" |
33 | | -__revision__ = "0.1" |
34 | | -__docformat__ = 'reStructuredText' |
35 | | - |
36 | 30 | import asyncio |
37 | 31 | import logging |
38 | 32 | import time |
@@ -246,129 +240,131 @@ def format_time(timedelta: float) -> str: |
246 | 240 | return f"{timedelta * 10 ** 9:.2f} ns" |
247 | 241 |
|
248 | 242 |
|
| 243 | +# TODO: asyncio for DLMS disabled until real testing has succeeded |
| 244 | +# # |
| 245 | +# # asyncio reader |
| 246 | +# # |
| 247 | +# |
| 248 | +# |
| 249 | +# class AsyncReader(): |
| 250 | +# |
| 251 | +# def __init__(self, logger, plugin: SmartPlugin, config: dict): |
| 252 | +# self.buf = bytes() |
| 253 | +# self.logger = logger |
| 254 | +# self.lock = config['lock'] |
| 255 | +# |
| 256 | +# if not ASYNC_IMPORTED: |
| 257 | +# raise ImportError('pyserial_asyncio not installed, running asyncio not possible.') |
| 258 | +# |
| 259 | +# if 'serial_port' not in config: |
| 260 | +# raise ValueError(f'configuration {config} is missing serial port config') |
| 261 | +# |
| 262 | +# self.serial_port = config.get('serial_port') |
| 263 | +# self.timeout = config.get('timeout', 2) |
| 264 | +# self.baudrate = config.get('baudrate', 300) |
| 265 | +# if not config['dlms'].get('only_listen', False): |
| 266 | +# self.logger.warning('asyncio operation can only listen, smartmeter will not be triggered!') |
| 267 | +# |
| 268 | +# self.target = '(not set)' |
| 269 | +# self.listening = False |
| 270 | +# self.reader = None |
| 271 | +# |
| 272 | +# self.config = config |
| 273 | +# self.transport = None |
| 274 | +# self.protocol = DlmsProtocol(logger, config) |
| 275 | +# |
| 276 | +# # set from plugin |
| 277 | +# self.plugin = plugin |
| 278 | +# self.data_callback = plugin._update_values |
| 279 | +# |
| 280 | +# async def listen(self): |
| 281 | +# result = self.lock.acquire(blocking=False) |
| 282 | +# if not result: |
| 283 | +# self.logger.error('couldn\'t acquire lock, polling/manual access active?') |
| 284 | +# return |
| 285 | +# |
| 286 | +# self.logger.debug('acquired lock') |
| 287 | +# try: # LOCK |
| 288 | +# self.reader, _ = await serial_asyncio.open_serial_connection( |
| 289 | +# url=self.serial_port, |
| 290 | +# baudrate=self.baudrate, |
| 291 | +# bytesize=S_BITS, |
| 292 | +# parity=S_PARITY, |
| 293 | +# stopbits=S_STOP, |
| 294 | +# ) |
| 295 | +# self.target = f'async_serial://{self.serial_port}' |
| 296 | +# self.logger.debug(f'target is {self.target}') |
| 297 | +# |
| 298 | +# if self.reader is None and not TESTING: |
| 299 | +# self.logger.error('error on setting up async listener, reader is None') |
| 300 | +# return |
| 301 | +# |
| 302 | +# self.plugin.connected = True |
| 303 | +# self.listening = True |
| 304 | +# self.logger.debug('starting to listen') |
| 305 | +# |
| 306 | +# buf = bytes() |
| 307 | +# |
| 308 | +# while self.listening and self.plugin.alive: |
| 309 | +# |
| 310 | +# if TESTING: |
| 311 | +# # make this bytes... |
| 312 | +# data = RESULT.encode() |
| 313 | +# else: |
| 314 | +# data = await self.reader.readuntil(b'!') |
| 315 | +# |
| 316 | +# # check we got a start byte if buf is empty |
| 317 | +# if len(buf) == 0: |
| 318 | +# if b'/' not in data: |
| 319 | +# self.logger.warning('incomplete data received, no start byte, discarding') |
| 320 | +# continue |
| 321 | +# else: |
| 322 | +# # trim data to start byte |
| 323 | +# data = data[data.find(b'/'):] |
| 324 | +# |
| 325 | +# # add data to buffer |
| 326 | +# buf += data |
| 327 | +# |
| 328 | +# # check if we have an end byte |
| 329 | +# if b'!' not in buf: |
| 330 | +# if len(buf) > 100000: |
| 331 | +# self.logger.warning(f'got {len(buf)} characters without end byte, discarding data') |
| 332 | +# buf = bytes() |
| 333 | +# continue |
| 334 | +# |
| 335 | +# # get data from start (b'/') to end (b'!') into data |
| 336 | +# # leave the remainder in buf |
| 337 | +# data, _, buf = buf.partition(b'!') |
| 338 | +# |
| 339 | +# # we should have data beginning with b'/' and ending with b'!' |
| 340 | +# identification_message = str(data, 'utf-8').splitlines()[0] |
| 341 | +# manid = identification_message[1:4] |
| 342 | +# manname = manufacturer_ids.get(manid, 'unknown') |
| 343 | +# self.logger.debug(f"manufacturer for {manid} is {manname} (out of {len(manufacturer_ids)} given manufacturers)") |
| 344 | +# |
| 345 | +# response = self.protocol(data.decode()) |
| 346 | +# |
| 347 | +# # get data from frameparser and call plugin |
| 348 | +# if response and self.data_callback: |
| 349 | +# self.data_callback(response) |
| 350 | +# |
| 351 | +# finally: |
| 352 | +# # cleanup |
| 353 | +# try: |
| 354 | +# self.reader.feed_eof() |
| 355 | +# except Exception: |
| 356 | +# pass |
| 357 | +# self.plugin.connected = False |
| 358 | +# self.lock.release() |
| 359 | +# |
| 360 | +# async def stop_on_queue(self): |
| 361 | +# """ wait for STOP in queue and signal reader to terminate """ |
| 362 | +# self.logger.debug('task waiting for STOP from queue...') |
| 363 | +# await self.plugin. wait_for_asyncio_termination() |
| 364 | +# self.logger.debug('task received STOP, halting listener') |
| 365 | +# self.listening = False |
249 | 366 | # |
250 | | -# asyncio reader |
251 | | -# |
252 | | - |
253 | | - |
254 | | -class AsyncReader(): |
255 | | - |
256 | | - def __init__(self, logger, plugin: SmartPlugin, config: dict): |
257 | | - self.buf = bytes() |
258 | | - self.logger = logger |
259 | | - self.lock = config['lock'] |
260 | | - |
261 | | - if not ASYNC_IMPORTED: |
262 | | - raise ImportError('pyserial_asyncio not installed, running asyncio not possible.') |
263 | | - |
264 | | - if 'serial_port' not in config: |
265 | | - raise ValueError(f'configuration {config} is missing serial port config') |
266 | | - |
267 | | - self.serial_port = config.get('serial_port') |
268 | | - self.timeout = config.get('timeout', 2) |
269 | | - self.baudrate = config.get('baudrate', 300) |
270 | | - if not config['dlms'].get('only_listen', False): |
271 | | - self.logger.warning('asyncio operation can only listen, smartmeter will not be triggered!') |
272 | | - |
273 | | - self.target = '(not set)' |
274 | | - self.listening = False |
275 | | - self.reader = None |
276 | | - |
277 | | - self.config = config |
278 | | - self.transport = None |
279 | | - self.protocol = DlmsProtocol(logger, config) |
280 | | - |
281 | | - # set from plugin |
282 | | - self.plugin = plugin |
283 | | - self.data_callback = plugin._update_values |
284 | | - |
285 | | - async def listen(self): |
286 | | - result = self.lock.acquire(blocking=False) |
287 | | - if not result: |
288 | | - self.logger.error('couldn\'t acquire lock, polling/manual access active?') |
289 | | - return |
290 | | - |
291 | | - self.logger.debug('acquired lock') |
292 | | - try: # LOCK |
293 | | - self.reader, _ = await serial_asyncio.open_serial_connection( |
294 | | - url=self.serial_port, |
295 | | - baudrate=self.baudrate, |
296 | | - bytesize=S_BITS, |
297 | | - parity=S_PARITY, |
298 | | - stopbits=S_STOP, |
299 | | - ) |
300 | | - self.target = f'async_serial://{self.serial_port}' |
301 | | - self.logger.debug(f'target is {self.target}') |
302 | | - |
303 | | - if self.reader is None and not TESTING: |
304 | | - self.logger.error('error on setting up async listener, reader is None') |
305 | | - return |
306 | | - |
307 | | - self.plugin.connected = True |
308 | | - self.listening = True |
309 | | - self.logger.debug('starting to listen') |
310 | | - |
311 | | - buf = bytes() |
312 | | - |
313 | | - while self.listening and self.plugin.alive: |
314 | | - |
315 | | - if TESTING: |
316 | | - # make this bytes... |
317 | | - data = RESULT.encode() |
318 | | - else: |
319 | | - data = await self.reader.readuntil(b'!') |
320 | | - |
321 | | - # check we got a start byte if buf is empty |
322 | | - if len(buf) == 0: |
323 | | - if b'/' not in data: |
324 | | - self.logger.warning('incomplete data received, no start byte, discarding') |
325 | | - continue |
326 | | - else: |
327 | | - # trim data to start byte |
328 | | - data = data[data.find(b'/'):] |
329 | | - |
330 | | - # add data to buffer |
331 | | - buf += data |
332 | | - |
333 | | - # check if we have an end byte |
334 | | - if b'!' not in buf: |
335 | | - if len(buf) > 100000: |
336 | | - self.logger.warning(f'got {len(buf)} characters without end byte, discarding data') |
337 | | - buf = bytes() |
338 | | - continue |
339 | | - |
340 | | - # get data from start (b'/') to end (b'!') into data |
341 | | - # leave the remainder in buf |
342 | | - data, _, buf = buf.partition(b'!') |
343 | | - |
344 | | - # we should have data beginning with b'/' and ending with b'!' |
345 | | - identification_message = str(data, 'utf-8').splitlines()[0] |
346 | | - manid = identification_message[1:4] |
347 | | - manname = manufacturer_ids.get(manid, 'unknown') |
348 | | - self.logger.debug(f"manufacturer for {manid} is {manname} (out of {len(manufacturer_ids)} given manufacturers)") |
349 | | - |
350 | | - response = self.protocol(data.decode()) |
351 | | - |
352 | | - # get data from frameparser and call plugin |
353 | | - if response and self.data_callback: |
354 | | - self.data_callback(response) |
355 | | - |
356 | | - finally: |
357 | | - # cleanup |
358 | | - try: |
359 | | - self.reader.feed_eof() |
360 | | - except Exception: |
361 | | - pass |
362 | | - self.plugin.connected = False |
363 | | - self.lock.release() |
364 | | - |
365 | | - async def stop_on_queue(self): |
366 | | - """ wait for STOP in queue and signal reader to terminate """ |
367 | | - self.logger.debug('task waiting for STOP from queue...') |
368 | | - await self.plugin. wait_for_asyncio_termination() |
369 | | - self.logger.debug('task received STOP, halting listener') |
370 | | - self.listening = False |
371 | | - |
| 367 | +# TODO end |
372 | 368 |
|
373 | 369 | # |
374 | 370 | # single-shot reader |
|
0 commit comments