Package: amshan
AMSHANPackage to help decode smart power meter data stream of IEC 62056-21 Mode D P1 or DLMS/Cosem HDLC frames used by MBUS (Meter Bus). The package can both help reading frames of meter data and/or decoding them.The package has special support for DLMS formats used by Aidon, Kaifa and Kamstrup smart meteres (HAN) in Norway (Seehttps://www.nek.no/info-ams-han-utviklere/) and Sweden. The Swedish P1 format format is also supported.Reading asynchronous from a stream of dataSmartMeterMessagePayloadProtocol can be used to read smart meter P1 date readout (ascii) or MBUS HDLC (binary) frames asynchronous. The content of each mdssage (no headers and control characters) is passed as bytes to a Queue. Headers are checked and checksum validated, and only content from non empty frames with expected length (only DLMS) and checksum is passed to the queue.SmartMeterMessageProtocol can be used to read smart meter P1 data readout (ascii) or MBUS HDLC frames asynchronous. The complete message is sent to a Queue as an instance of as subclass of MeterReaderBase. Frames are not validated. This class is a more low level alternative to SmartMeterMessagePayloadProtocol. This type has to be used to get the meter type from P1 readouts as this is part of the message "header".Both SmartMeterMessagePayloadProtocol and SmartMeterMessageProtocol is aPython asyncio protocol. Protocols support different types of transports like network and serial.It is recommended to use provided ConnectionManager and connection factories to read the data stream.Create protocol using transportPass a factory for the selected protocol (SmartMeterMessagePayloadProtocol or SmartMeterMessageProtocol) to a utility function of your selected transport (e.g., EventLoop.create_connection() for TCP/IP or serial_asyncio.create_serial_connection() for serial).Serial example:transport,protocol=awaitserial_asyncio.create_serial_connection(loop,lambda:SmartMeterMessagePayloadProtocol(queue,[ModeDReader]),url="/dev/tty01")Serial example:transport,protocol=awaitserial_asyncio.create_serial_connection(loop,lambda:SmartMeterMessagePayloadProtocol(queue,[ModeDReader]),url="/dev/tty01")Create protocol using provided factoriesMultiple factories are provided to create a protocol as an alternative to using selected transports create function as above. Useserial_connection_factoryfor serial andtcp_connection_factoryfor TCP/IP.Factory moduleSmartMeterMessageProtocolSmartMeterMessagePayloadProtocolserial_connection_factorycreate_serial_message_payload_connection()create_serial_message_connection()tcp_connection_factorycreate_tcp_message_connection()create_tcp_message_payload_connection()Example of creating a SmartMeterMessagePayloadProtocol serial connection on device /dev/ttyUSB0:queue=Queue()loop=asyncio.get_event_loop()transport,protocol=awaitcreate_serial_frame_content_connection(queue,loop,None,url="/dev/ttyUSB0",baudrate=2400,parity=N)Example of creating a SmartMeterMessageProtocol protocol TCP/IP connection to host 192.168.1.1 on port 1234:queue=Queue()loop=asyncio.get_event_loop()transport,protocol=awaitcreate_tcp_frame_connection(queue,loop,None,"192.168.1.1",1234)Seereader_async.pyfor a complete example.Create resilient connection with ConnectionManagerConnectionManager maintain connection and reconnect if connection is lost. A back-off retry strategy is used when reconnecting, and a simple circuit breaker is used for lost connection.queue=Queue()loop=asyncio.get_event_loop()connection_manager=ConnectionManager(lambda:create_serial_message_connection(queue,loop,None,url="/dev/ttyUSB0",baudrate=2400,parity=N))awaitconnection_manager.connect_loop()Seereader_async.pyfor a complete example.Parse P1 readouts directly from raw bytesdlde.ModeDReader can be used to read readout by readout from bytes. Call read() to read readouts as more bytes become available. The function takes bytes as an argument and returns a list of DataReadout (the list can be empty). The function can receive incomplete readout in the buffer input and add incomplete data to an internal buffer. The buffer is schrinked when complete readout are found and returned. You should check if returned readouts are valid with readout.is_valid before using them.Parse frames directly from raw byteshdlc.HdlcFrameReader can be used to read frame by frame from bytes. Call read() to read frames as more bytes become available. The function takes bytes as an argument and returns a list of HdlcFrame (the list can be empty). The function can receive incomplete frames in the buffer input and add incomplete data to an internal buffer. The buffer is schrinked when complete frames are found and returned. You should check if returned frames are valid with frame.is_valid before using them.Decode norwegian and swedish messagesP1 readout and MBUS frames using the norwegian or swedish DMLS AMS format can be parsed into meter specific objects or decoded into a common dictionary. Modules exists for P1 (generic format), Aidon, Kaifa and Kamstrup meters, but the easiest is to useautodecoder.AutoDecodeto automatically detect meter type and decode the frame into a dictionary. The dictionay content is as far as possible common between meters. Possible dictionary keys kan be found as constants inobis_map.py.Example:decoder=AutoDecoder()frame=bytes.fromhex("e6e700""0f""40000000""00""0101""020309060100010700ff060000011802020f00161b")decoded=decoder.decode_frame_content(frame)