Skip to main content

Decode MBUS (Meter Bus) data with special support for norwegian AMS-smart meters (HAN port)

Project description

GitHub Release Language grade: Python License

Project Maintenance buy me a coffee

AMSHAN

Package to help decode smart power meter data stream of 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 formats used by Aidon, Kaifa and Kamstrum smart meteres (HAN) in Norway. See https://www.nek.no/info-ams-han-utviklere/

Reading asynchronous from a stream of data

SmartMeterFrameContentProtocol can be used to read smart meter MBUS HDLC frames asynchronous. The content of each frame (no headers and control characters) is passed as bytes to a Queue. HDLC frame headers are checked and checksum validated, and only content from non empty frames with expected length and checksum is passed to the queue.

SmartMeterFrameProtocol can be used to read smart meter MBUS HDLC frames asynchronous. The complete fram is sent to a Queue as an instance of HdlcFrame. Frames are not validated. This class is a more low level alternative to SmartMeterFrameContentProtocol.

Both SmartMeterFrameContentProtocol and SmartMeterFrameProtocol is a Python asyncio protocol. Protocols support different types of transports like network and serial.

It is recommended to use provided ConnectionManager and connection factories to read MBus meter data stream.

Create protocol using transport

Pass a factory for the selected protocol (SmartMeterFrameContentProtocol or SmartMeterFrameProtocol) 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 = await serial_asyncio.create_serial_connection(loop, lambda: SmartMeterFrameContentProtocol(queue), url = "/dev/tty01")

Serial example:

transport, protocol = await serial_asyncio.create_serial_connection(loop, lambda: SmartMeterFrameContentProtocol(queue), url = "/dev/tty01")

Create protocol using provided factories

Multiple factories are provided to create a protocol as an alternative to using selected transports create function as above. Use serial_connection_factory for serial and tcp_connection_factory for TCP/IP.

Factory module SmartMeterFrameProtocol SmartMeterFrameContentProtocol
serial_connection_factory create_serial_frame_content_connection() create_serial_frame_connection()
tcp_connection_factory create_tcp_frame_content_connection() create_tcp_frame_connection()

Example of creating a SmartMeterFrameContentProtocol serial connection on device /dev/ttyUSB0:

queue = Queue()
loop = asyncio.get_event_loop()
transport, protocol = await create_serial_frame_content_connection(queue, loop, url="/dev/ttyUSB0", baudrate=2400, parity=N)

Example of creating a SmartMeterFrameProtocol protocol TCP/IP connection to host 192.168.1.1 on port 1234:

queue = Queue()
loop = asyncio.get_event_loop()
transport, protocol = await create_tcp_frame_connection(queue, loop, "192.168.1.1", 1234)

See reader_async.py for a complete example.

Create resilient connection with ConnectionManager

ConnectionManager 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_frame_content_connection(queue, loop, url="/dev/ttyUSB0", baudrate=2400, parity=N))
await connection_manager.connect_loop()

See reader_async.py for a complete example.

Parse frames directly from raw bytes

hdlc.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_good_ffc and frame.is_expected_length before using them.

Decode norwegian HAN port frames

MBUS frames using the norwegian AMS format can be parsed into meter specific objects or decoded into a common dictionary. Modules exists for Aidon, Kaifa and Kamstrup meters, but the easiest is to use autodecoder.AutoDecode to 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 in obis_map.py.

Example:

decoder = AutoDecoder()
frame = bytes.fromhex("e6e700" "0f" "40000000" "00" "0101" "020309060100010700ff060000011802020f00161b")
decoded = decoder.decode_frame_content(frame)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

amshan-1.0.1.tar.gz (19.9 kB view hashes)

Uploaded Source

Built Distribution

amshan-1.0.1-py3-none-any.whl (22.2 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page