Hello Gurux Team and Forum Members,
I'm new to this forum, and I apologize in advance if some text formatting isn't correct. I'm not a professional programmer, but I've been trying for several months to connect my ISKRA AM550 meter to my RPI4 and send data to Home Assistant via MQTT.
Unfortunately, I haven't had much success, and I could really use some guidance.
My Setup
- Meter: ISKRA AM550
- Connection: P1 port over Serial (ttyS0) with a baud rate of 38400
- Goal: Read data from the meter using Python, parse it correctly, and publish it to Home Assistant via MQTT.
What I Have Done So Far
1. Connection: Successfully connected to the meter using GXDLMSDirector and captured frame data.
2. Translation: Used the Gurux DLMS Translator to convert the frames, and I can see what appears to be valid data.
3. Python Script: I've attempted to write a Python script using the `gurux_dlms` library to handle HDLC frames and parse the incoming data. However, I'm encountering errors when working with the `GXByteBuffer`.
Issues Encountered
- Error Messages:
- `'GXByteBuffer' object has no attribute 'add'`
- `'GXByteBuffer' object has no attribute 'extend'`
- It seems like I'm not using the `GXByteBuffer` correctly, or I'm missing a step in handling the HDLC frames.
###### Data from My Grid Provider
Iskra AM550
IEC local port setup channel 1 Logical name: 0-1:20.0.0*255 Class ID: IEC local port setup (19) Version: 1
Default baud rate: 38400 Port according to IEC 62056-46 (DLMS UA)
Proposed baud rate: 38400
Response time: 200ms
Device address: 0
IEC HDLC setup channel 1 Logical name: 0-1:22.0.0*255 Class ID: IEC HDLC setup class (23) Version: 1
Communication speed: 9600
Window size transmit: 1
Window size receive: 1
Max info field length transmit: 154
Max info field length transmit: 154
Inter octet time out: 50
Inactivity time out: 120
Device address: 17
Push setup - Interval 1
Logical name: 0-1:25.9.0*255 Class ID: Push setup (40) Version: 0
Push object list (unchecked)
Logical Name Item Class ID Attribute Data index
0-0:42.0.0 COSEM logical device name 1 = Data 2 - Value 0
0-0:96.1.3 Device ID 4 2 = Data 2 - Value 0
1-0:1.8.1 Active energy import (+ A) Rate 1 3 - Register 2 - Value 0
1-0:1.8.2 Active energy import (+*) Rate 2 4 - Register 2 - Value 0
1-0:2.8.1 Active energy export (-A) Rate 1 5 - Register 2 - Value 0
1-0:2.8.2 Active energy export. (-4) Rate 2 6 - Register 2 - Value 0
1-0:3.8.1 Reactive energy import (+ R) Rate 1 7 - Register 2 - Value 0
1-0:3.8.2 Reactive energy import (+R) Rate 2 8 - Register 2 - Value 0
1-0.4.8.1 Reactive energy export (-R) Rate 1 9 - Register 2 - Value 0
1-0:4.8.2 Reactive energy export (-R) Rate 2 10 - Register 2 - Value 0
Push setup - Consumer information
Logical name: 0-6:25.9.0*255 Class ID: Push setup (40) Version: 0
Push object list (unchecked)
Logical Name Item Class ID Attribute Data index
0-0:42.0.0 COSEM logical device name 1 = Data 2 - Value 0
0-0:96.1.2 Device ID 3 2 = Data 2 - Value 0
1-0:32.7.0 Instantaneous voltage L1 3 - Register 2 - Value 0
1-0:52.7.0 Instantaneous voltage L2 4 - Register 2 - Value 0
1-0:72.7.0 Instantaneous voltage L3 5 - Register 2 - Value 0
1-0:31.7.0 Instantaneous current L1 6 - Register 2 - Value 0
1-0:51.7.0 Instantaneous current L2 7 - Register 2 - Value 0
1-0:71.7.0 Instantaneous current L3 8 - Register 2 - Value 0
1-0:1.7.0 Instantaneous active import power (+A) 9 - Register 2 - Value 0
1-0:2.7.0 Instantaneous active export power (-A) 10 - Register 2 - Value 0
1-0:3.7.0 Instantaneous reactive import power (+R) 11 - Register 2 - Value 0
1-0:4.7.0 Instantaneous reactive export power (-R) 12 - Register 2 - Value 0
Questions
1. Parsing HDLC Frames**: Could someone provide guidance or examples on how to correctly handle and parse HDLC frames using the `gurux_dlms` Python library?
2. Handling GXByteBuffer**: What is the correct way to manage the `GXByteBuffer` in this context? Are there specific methods or functions that should be used for appending and managing data within this buffer?
3. Known Working Configurations**: Has anyone successfully connected an ISKRA AM550 meter (or similar) to a system in Slovenia? Are there known configurations or steps that work?
$$$$$$ Additional Data
Here are some frames I captured and processed through the translator:
<DataNotification>
<LongInvokeIdAndPriority Value="7236179" />
<DateTime Value="07E80805010E062D00FF8880" />
<NotificationBody>
<DataValue>
<Structure Qty="12" >
<OctetString Value="49534B31303330373839303134373331" />
<OctetString Value="55505F3366" />
<UInt16 Value="2344" />
<UInt16 Value="2350" />
<UInt16 Value="2361" />
<UInt16 Value="227" />
<UInt16 Value="188" />
<UInt16 Value="63" />
<UInt32 Value="766" />
<UInt32 Value="0" />
<UInt32 Value="0" />
<UInt32 Value="502" />
</Structure>
</DataValue>
</NotificationBody>
</DataNotification>
$$$$$$ Additional Data
Some frames:
HDLC frame:
7E A0 60 CF 02 23 13 27 C1 E6 E7 00 0F 00 6E 6A
4E 0C 07 E8 08 05 01 0E 06 28 00 FF 88 80 02 0C
09 10 49 53 4B 31 30 33 30 37 38 39 30 31 34 37
33 31 09 05 55 50 5F 33 66 12 09 26 12 09 2C 12
09 33 12 00 B4 12 00 BE 12 00 42 06 00 00 03 5E
06 00 00 00 00 06 00 00 00 00 06 00 00 01 97 CE
7A 7E
LLC frame:
E6 E7 00 0F 00 6E 6A 4E 0C 07 E8 08 05 01 0E 06
28 00 FF 88 80 02 0C 09 10 49 53 4B 31 30 33 30
37 38 39 30 31 34 37 33 31 09 05 55 50 5F 33 66
12 09 26 12 09 2C 12 09 33 12 00 B4 12 00 BE 12
00 42 06 00 00 03 5E 06 00 00 00 00 06 00 00 00
00 06 00 00 01 97
DLMS frame:
0F 00 6E 6A 4E 0C 07 E8 08 05 01 0E 06 28 00 FF
88 80 02 0C 09 10 49 53 4B 31 30 33 30 37 38 39
30 31 34 37 33 31 09 05 55 50 5F 33 66 12 09 26
12 09 2C 12 09 33 12 00 B4 12 00 BE 12 00 42 06
00 00 03 5E 06 00 00 00 00 06 00 00 00 00 06 00
00 01 97
(D) Received valid DLMS at 30
Using application data:
02 0C 09 10 49 53 4B 31 30 33 30 37 38 39 30 31
34 37 33 31 09 05 55 50 5F 33 66 12 09 26 12 09
2C 12 09 33 12 00 B4 12 00 BE 12 00 42 06 00 00
03 5E 06 00 00 00 00 06 00 00 00 00 06 00 00 01
97
DLMS
HDLC frame:
7E A0 60 CF 02 23 13 27 C1 E6 E7 00 0F 00 6E 6A
4F 0C 07 E8 08 05 01 0E 06 29 00 FF 88 80 02 0C
09 10 49 53 4B 31 30 33 30 37 38 39 30 31 34 37
33 31 09 05 55 50 5F 33 66 12 09 24 12 09 2C 12
09 34 12 01 32 12 00 BD 12 00 40 06 00 00 03 8F
06 00 00 00 00 06 00 00 00 00 06 00 00 01 BF 99
7F 7E
LLC frame:
E6 E7 00 0F 00 6E 6A 4F 0C 07 E8 08 05 01 0E 06
29 00 FF 88 80 02 0C 09 10 49 53 4B 31 30 33 30
37 38 39 30 31 34 37 33 31 09 05 55 50 5F 33 66
12 09 24 12 09 2C 12 09 34 12 01 32 12 00 BD 12
00 40 06 00 00 03 8F 06 00 00 00 00 06 00 00 00
00 06 00 00 01 BF
DLMS frame:
0F 00 6E 6A 4F 0C 07 E8 08 05 01 0E 06 29 00 FF
88 80 02 0C 09 10 49 53 4B 31 30 33 30 37 38 39
30 31 34 37 33 31 09 05 55 50 5F 33 66 12 09 24
12 09 2C 12 09 34 12 01 32 12 00 BD 12 00 40 06
00 00 03 8F 06 00 00 00 00 06 00 00 00 00 06 00
00 01 BF
(D) Received valid DLMS at 30
Any help or pointers would be greatly appreciated!
Thank you very much!
Ivan
Hi Ivan, You don't need to…
Hi Ivan,
You don't need to parse HDLC frames. That is done automatically.
It seems like your meter is configured to send push messages.
This means that you don't establish the connection to the meter.
You just listen to the push messages that the meter sends.
Check the Push listener example. I believe it does what you want to do.
https://github.com/Gurux/Gurux.DLMS.Python/tree/master/Gurux.DLMS.Push…
BR,
Mikko
Hello Mikko, thank You for…
Hello Mikko,
thank You for Your appreciated support and hint.
We tried and established the connection, still one/two questions if possible
When using the GXDLMSClient.parsePushObjects() method, what are the expected input data types and structures? Are there specific conditions or configurations required for this method to correctly parse the incoming HDLC frames from an Iskra AM550 smart meter?
See what we are getting as a result:
Listening to /dev/ttyS0 at 38400 baud rate...
Complete raw data frame received: b"~\xa0\xcf\x02#\x13'\xc1\xe6\xe7\x00\x0f\x00\x92\xf8\xcd\x0c\x07\xe8\t\x02\x01\n\x11 \x00\xff\x88\x80\x02\x0c\t\x10ISK1030789014731\t\x05UP_3f\x12\t\x16\x12\t\x1e\x12\t-\x12\x021\x12\x00\xc1\x12\x00@\x06\x00\x00\x05\xc6\x06\x00\x00\x00\x00\x06\x00\x00\x00\x00\x06\x00\x00\x01\x18#\x00~"
Data is complete. Size of reply data: 65
Exception while parsing HDLC frame data: 'int' object is not subscriptable
Complete raw data frame received: b'~\xa0\xcf\x02#\x13\'\xc1\xe6\xe7\x00\x0f\x00\x92\xf8\xce\x0c\x07\xe8\t\x02\x01\n\x11!\x00\xff\x88\x80\x02\x0c\t\x10ISK1030789014731\t\x05UP_3f\x12\t\x19\x12\t\x1f\x12\t-\x12\x01m\x12\x00\xc2\x12\x00B\x06\x00\x00\x06"\x06\x00\x00\x00\x00\x06\x00\x00\x00\x00\x06\x00\x00\x01\x17\xc8\x89~'
Data is complete. Size of reply data: 65
Exception while parsing HDLC frame data: 'int' object is not subscriptable
Complete raw data frame received: b'~\xa0\xcf\x02#\x13\'\xc1\xe6\xe7\x00\x0f\x00\x92\xf8\xcf\x0c\x07\xe8\t\x02\x01\n\x11"\x00\xff\x88\x80\x02\x0c\t\x10ISK1030789014731\t\x05UP_3f\x12\t\x1b\x12\t\x1d\x12\t,\x12\x01l\x12\x00\xc0\x12\x00>\x06\x00\x00\x05\xe9\x06\x00\x00\x00\x00\x06\x00\x00\x00\x00\x06\x00\x00\x01\x19\xb4#~'
Data is complete. Size of reply data: 65
Exception while parsing HDLC frame data: 'int' object is not subscriptable
And this is what we have done. Maybe a hint from Your side.. Thx in advance!
Thank You again and cheers,
Ivan
import serial
from gurux_dlms.GXDLMSClient import GXDLMSClient
from gurux_dlms.GXReplyData import GXReplyData
from gurux_dlms.GXByteBuffer import GXByteBuffer
from gurux_dlms.enums import InterfaceType
from paho.mqtt import client as mqtt_client
# MQTT Broker details
broker = '192.168.177.101' # Replace with your broker's IP address
port = 1883
topic = 'ISKRA/'
# Serial port configuration
serial_port = '/dev/ttyS0' # Ensure this is the correct port for your setup
baud_rate = 38400
# Initialize MQTT client
mqtt_client = mqtt_client.Client()
mqtt_client.connect(broker, port, 60)
# Serial connection setup
ser = serial.Serial(serial_port, baud_rate, timeout=1)
def publish_mqtt(sub_topic, payload):
"""Publish the data to MQTT broker."""
full_topic = topic + sub_topic
mqtt_client.publish(full_topic, payload)
print(f"Published to MQTT: {full_topic} -> {payload}")
def initialize_client():
"""Initialize the DLMS client."""
client = GXDLMSClient(
useLogicalNameReferencing=True, # Use Logical Name referencing
clientAddress=16, # Example client address
serverAddress=1, # Example server address
interfaceType=InterfaceType.HDLC # Use HDLC interface
)
return client
def read_complete_frame(ser):
"""Read the complete HDLC frame from the serial port."""
frame = b''
while True:
# Read one byte at a time to construct the complete frame
data = ser.read()
if data:
frame += data
# Check for end of frame indicator '~'
if frame.endswith(b'~') and len(frame) > 3:
return frame
def parse_data(client, data):
"""Parse the push data received from the smart meter."""
bb = GXByteBuffer(data)
reply = GXReplyData()
try:
# Process the incoming HDLC frame data using the DLMS client
client.getData(bb, reply)
# Check if there was an error during data retrieval
if reply.error:
print(f"Error occurred while retrieving data: {reply.error}")
return None
# If the data is complete and no errors
if reply.complete:
print(f"Data is complete. Size of reply data: {reply.data.size}")
objects = client.parsePushObjects(reply.data)
# Debugging: Show the number of objects parsed
if objects:
print(f"Parsed {len(objects)} objects from the data.")
else:
print("No objects parsed from the data.")
return
# Iterate over the decoded objects and publish them to MQTT
for obj in objects:
print(f"Processing object: {obj}")
if obj: # Check if obj is not None
try:
obis_code = obj.logicalName if hasattr(obj, 'logicalName') else None
if obis_code and isinstance(obis_code, str): # Ensure OBIS code is a string
value = obj.getValue()
sub_topic = obis_code.replace('.', '_')
publish_mqtt(sub_topic, value)
else:
print(f"Invalid OBIS code or type: {obis_code} of type {type(obis_code)}")
except AttributeError as ae:
print(f"Attribute error while accessing object properties: {ae}")
else:
print("Received None object during parsing.")
except Exception as e:
print(f"Exception while parsing HDLC frame data: {str(e)}")
def main():
print(f"Listening to {serial_port} at {baud_rate} baud rate...")
client = initialize_client()
while True:
try:
if ser.in_waiting:
raw_data = read_complete_frame(ser)
if raw_data:
print(f"Complete raw data frame received: {raw_data}")
parse_data(client, raw_data)
except Exception as e:
print(f"Error: {e}")
if __name__ == "__main__":
main()
Hi, Please, don't add raw…
Hi,
Please, don't add raw data like this. If you add received bytes add them as a hex string.
You need to set the correct client and server address and after that, the client can parse received data. Input data depends on how the meter is configured to send push messages.
BR,
Mikko
Hello Mikko, sorry for the…
Hello Mikko,
sorry for the raw data!
Ok, I managed to make the connection and I am receiving all the data now in Home Assistant - perfect!
Thank You for "Gurux" - and next time when I am in Finland (mostly Helsinki) I can invite You for a drink, snack, lunch - no problems at all!
Thank You again, Ivan