Merge pull request #63 from mjkl-gh/master

Improve documentation asyncio
This commit is contained in:
Nigel Dokter 2022-04-20 21:58:59 +02:00 committed by GitHub
commit 7f35cd3c73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -39,10 +39,6 @@ process because the code is blocking (not asynchronous):
for telegram in serial_reader.read():
print(telegram) # see 'Telegram object' docs below
**AsyncIO client**
To be documented.
**Socket client**
Read a remote serial port (for example using ser2net) and work with the parsed telegrams.
@ -62,6 +58,115 @@ It should be run in a separate process because the code is blocking (not asynchr
for telegram in socket_reader.read():
print(telegram) # see 'Telegram object' docs below
**AsyncIO client**
For a test run using a tcp server (lasting 20 seconds) use the following example:
.. code-block:: python
import asyncio
import logging
from dsmr_parser import obis_references
from dsmr_parser.clients.protocol import create_dsmr_reader, create_tcp_dsmr_reader
logging.basicConfig(level=logging.INFO, format='%(message)s')
HOST = MY_HOST
PORT = MY_PORT
DSMR_VERSION = MY_DSMR_VERSION
logger = logging.getLogger('tcpclient')
logger.debug("Logger created")
def printTelegram(telegram):
logger.info(telegram)
async def main():
try:
logger.debug("Getting loop")
loop = asyncio.get_event_loop()
logger.debug("Creating reader")
await create_tcp_dsmr_reader(
HOST,
PORT,
DSMR_VERSION,
printTelegram,
loop
)
logger.debug("Reader created going to sleep now")
await asyncio.sleep(20)
logger.info('Finished run')
except Exception as e:
logger.error("Unexpected error: "+ e)
asyncio.run(main())
Note the creation of a callback function to call when a telegram is received. In this case `printTelegram`. Normally the used loop is the one running.
Currently the asyncio implementation does not support returning telegram objects directly as a `read_as_object()` for async tcp is currently not implemented.
Moreover, the telegram passed to `telegram_callback(telegram)` is already parsed. Therefore we can't feed it into the telegram constructor directly as that expects unparsed telegrams
However, if we construct a mock TelegramParser that just returns the already parsed object we can work around this. An example is below:
.. code-block:: python
import asyncio
import logging
#from dsmr_parser import obis_references
#from dsmr_parser import telegram_specifications
#from dsmr_parser.clients.protocol import create_dsmr_reader, create_tcp_dsmr_reader
#from dsmr_parser.objects import Telegram
logging.basicConfig(level=logging.INFO, format='%(message)s')
HOST = MY_HOST
PORT = MY_PORT
DSMR_VERSION = MY_DSMR_VERSION
logger = logging.getLogger('tcpclient')
logger.debug("Logger created")
class mockTelegramParser(object):
def parse(self, telegram):
return telegram
telegram_parser = mockTelegramParser()
def printTelegram(telegram):
try:
logger.info(Telegram(telegram, telegram_parser, telegram_specifications.V4))
except InvalidChecksumError as e:
logger.warning(str(e))
except ParseError as e:
logger.error('Failed to parse telegram: %s', e)
async def main():
try:
logger.debug("Getting loop")
loop = asyncio.get_event_loop()
logger.debug("Creating reader")
await create_tcp_dsmr_reader(
HOST,
PORT,
DSMR_VERSION,
printTelegram,
loop
)
logger.debug("Reader created going to sleep now")
while True:
await asyncio.sleep(1)
except Exception as e:
logger.error("Unexpected error: "+ e)
raise
if __name__ == '__main__':
try:
asyncio.run(main())
except (KeyboardInterrupt, SystemExit):
logger.info('Closing down...')
except Exception as e:
logger.error("Unexpected error: "+ e)
Parsing module usage
--------------------
@ -70,39 +175,39 @@ into a dictionary.
.. code-block:: python
from dsmr_parser import telegram_specifications
from dsmr_parser.parsers import TelegramParser
from dsmr_parser import telegram_specifications
from dsmr_parser.parsers import TelegramParser
# String is formatted in separate lines for readability.
telegram_str = (
'/ISk5\\2MT382-1000\r\n'
'\r\n'
'0-0:96.1.1(4B384547303034303436333935353037)\r\n'
'1-0:1.8.1(12345.678*kWh)\r\n'
'1-0:1.8.2(12345.678*kWh)\r\n'
'1-0:2.8.1(12345.678*kWh)\r\n'
'1-0:2.8.2(12345.678*kWh)\r\n'
'0-0:96.14.0(0002)\r\n'
'1-0:1.7.0(001.19*kW)\r\n'
'1-0:2.7.0(000.00*kW)\r\n'
'0-0:17.0.0(016*A)\r\n'
'0-0:96.3.10(1)\r\n'
'0-0:96.13.1(303132333435363738)\r\n'
'0-0:96.13.0(303132333435363738393A3B3C3D3E3F303132333435363738393A3B3C3D3E'
'3F303132333435363738393A3B3C3D3E3F303132333435363738393A3B3C3D3E3F30313233'
'3435363738393A3B3C3D3E3F)\r\n'
'0-1:96.1.0(3232323241424344313233343536373839)\r\n'
'0-1:24.1.0(03)\r\n'
'0-1:24.3.0(090212160000)(00)(60)(1)(0-1:24.2.1)(m3)\r\n'
'(00001.001)\r\n'
'0-1:24.4.0(1)\r\n'
'!\r\n'
)
# String is formatted in separate lines for readability.
telegram_str = (
'/ISk5\\2MT382-1000\r\n'
'\r\n'
'0-0:96.1.1(4B384547303034303436333935353037)\r\n'
'1-0:1.8.1(12345.678*kWh)\r\n'
'1-0:1.8.2(12345.678*kWh)\r\n'
'1-0:2.8.1(12345.678*kWh)\r\n'
'1-0:2.8.2(12345.678*kWh)\r\n'
'0-0:96.14.0(0002)\r\n'
'1-0:1.7.0(001.19*kW)\r\n'
'1-0:2.7.0(000.00*kW)\r\n'
'0-0:17.0.0(016*A)\r\n'
'0-0:96.3.10(1)\r\n'
'0-0:96.13.1(303132333435363738)\r\n'
'0-0:96.13.0(303132333435363738393A3B3C3D3E3F303132333435363738393A3B3C3D3E'
'3F303132333435363738393A3B3C3D3E3F303132333435363738393A3B3C3D3E3F30313233'
'3435363738393A3B3C3D3E3F)\r\n'
'0-1:96.1.0(3232323241424344313233343536373839)\r\n'
'0-1:24.1.0(03)\r\n'
'0-1:24.3.0(090212160000)(00)(60)(1)(0-1:24.2.1)(m3)\r\n'
'(00001.001)\r\n'
'0-1:24.4.0(1)\r\n'
'!\r\n'
)
parser = TelegramParser(telegram_specifications.V3)
telegram = parser.parse(telegram_str)
print(telegram) # see 'Telegram object' docs below
parser = TelegramParser(telegram_specifications.V3)
telegram = parser.parse(telegram_str)
print(telegram) # see 'Telegram object' docs below
Telegram dictionary
-------------------