u9n / dlms-cosem

A Python library for DLMS/COSEM
Other
79 stars 39 forks source link

Unable to read an ISKRA AM550 meter #71

Closed jeremie-borel closed 4 months ago

jeremie-borel commented 6 months ago

Hello,

I'm trying to read the data from my ISKRA AM550 trough the P1 port. The setup at the time is with a FT232 Serial cable into a raspberry py. The meter is provided by SIE Lausanne, in Switzerland.

The tiny doc they provided me is quite clear (though in french) ISKRA.pdf

Interface: P1 DSMR v5.0 Protocole: DLMS/COSEM Frame length: 154 bytes

Baudrate: 1152000, 8bits, no parity, 1 stop bit.

Then they give some OBIS codes with what they match (e.g. current on phase 2, etc.)

They also state that the data are not encrypted.

I've tried all kind of libraries to read the data but with no success. I wrote a minimal example with your library:

from dlms_cosem.client import DlmsClient
from dlms_cosem import cosem, enumerations

from dlms_cosem.io import SerialIO, HdlcTransport

from dlms_cosem.security import NoSecurityAuthentication

usb_port: str = "/dev/ttyUSB0"

serial_io = SerialIO(
    port_name=usb_port,
    baud_rate=115200,
)
public_hdlc_transport = HdlcTransport(
    client_logical_address=1,
    server_logical_address=16,
    server_physical_address=17,
    io=serial_io,
)

public_client = DlmsClient(
    transport=public_hdlc_transport,
    authentication=NoSecurityAuthentication(),
)

with public_client.session() as client:
    pass

But the connection cannot starts and it look quite like one of the other issue that has been open: https://github.com/pwitab/dlms-cosem/issues/62. I know the problem might not be on your side but I hope you can put me on some track. Many thanks.

2024-01-07 16:15:49 [debug    ] HDLC state transitioned        new_state=AWAITING_CONNECTION old_state=NOT_CONNECTED
2024-01-07 16:15:49 [debug    ] Sending data                   data=bytearray(b'~\xa0\x08 #\x03\x93\x1b\xc2~') transport=HdlcTransport(client_logical_address=1, server_logical_address=16, io=SerialIO(port_name='/dev/ttyUSB0', baud_rate=115200, timeout=10, serial_port=Serial<id=0x7f9cbaa2e0, open=True>(port='/dev/ttyUSB0', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=10, xonxoff=False, rtscts=False, dsrdtr=False)), server_physical_address=17, client_physical_address=None, extended_addressing=False, timeout=10, hdlc_connection=HdlcConnection(client_address=HdlcAddress(logical_address=16, physical_address=17, address_type='server', extended_addressing=False), server_address=HdlcAddress(logical_address=1, physical_address=None, address_type='client', extended_addressing=False), client_ssn=0, client_rsn=0, server_ssn=0, server_rsn=0, max_data_size=128, state=HdlcConnectionState(current_state=AWAITING_CONNECTION), buffer=bytearray(b''), buffer_search_position=1), _send_buffer=[], out_buffer=bytearray(b''), in_buffer=bytearray(b''))

2024-01-07 16:15:54 [debug    ] Received data                  data=b'~\xa8\xa4\xcf\x02#\x03\x99\x96\xe6\xe7\x00\x0f\x00\x17\xc4@\x0c\x07\xe8\x01\x07\x07\x10\x0f7\x00\xff\xc4\x00\x02\x10\x02\x02\t\x06\x00\x00`\x01\x00\xff\t\x0885738459\x02\x02\t\x06\x00\x00`\x01\x01\xff\t\x071058708\x02\x03\t\x06\x01\x00\x01\x07\x00\xff\x06\x00\x00\x05\x9d\x02\x02\x0f\x00\x16\x1b\x02\x03\t\x06\x01\x00\x02\x07\x00\xff\x06\x00\x00\x00\x00\x02\x02\x0f\x00\x16\x1b\x02\x03\t\x06\x01\x00\x01\x08\x00\xff\x06\x00L\x9f\xe7\x02\x02\x0f\x00\x16\x1e\x02\x03\t\x06\x01\x00\x02\x08\x00\xff\x06\x00sk\xf7\x02\x02\x0f\x00\x16\x1e\x02\x03\t\x06\x01\x00 \x07\xbd\x0c~' transport=HdlcTransport(client_logical_address=1, server_logical_address=16, io=SerialIO(port_name='/dev/ttyUSB0', baud_rate=115200, timeout=10, serial_port=Serial<id=0x7f9cbaa2e0, open=True>(port='/dev/ttyUSB0', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=10, xonxoff=False, rtscts=False, dsrdtr=False)), server_physical_address=17, client_physical_address=None, extended_addressing=False, timeout=10, hdlc_connection=HdlcConnection(client_address=HdlcAddress(logical_address=16, physical_address=17, address_type='server', extended_addressing=False), server_address=HdlcAddress(logical_address=1, physical_address=None, address_type='client', extended_addressing=False), client_ssn=0, client_rsn=0, server_ssn=0, server_rsn=0, max_data_size=128, state=HdlcConnectionState(current_state=AWAITING_CONNECTION), buffer=bytearray(b''), buffer_search_position=1), _send_buffer=[], out_buffer=bytearray(b''), in_buffer=bytearray(b''))
2024-01-07 16:15:54 [debug    ] Added data to buffer           data=b'~\xa8\xa4\xcf\x02#\x03\x99\x96\xe6\xe7\x00\x0f\x00\x17\xc4@\x0c\x07\xe8\x01\x07\x07\x10\x0f7\x00\xff\xc4\x00\x02\x10\x02\x02\t\x06\x00\x00`\x01\x00\xff\t\x0885738459\x02\x02\t\x06\x00\x00`\x01\x01\xff\t\x071058708\x02\x03\t\x06\x01\x00\x01\x07\x00\xff\x06\x00\x00\x05\x9d\x02\x02\x0f\x00\x16\x1b\x02\x03\t\x06\x01\x00\x02\x07\x00\xff\x06\x00\x00\x00\x00\x02\x02\x0f\x00\x16\x1b\x02\x03\t\x06\x01\x00\x01\x08\x00\xff\x06\x00L\x9f\xe7\x02\x02\x0f\x00\x16\x1e\x02\x03\t\x06\x01\x00\x02\x08\x00\xff\x06\x00sk\xf7\x02\x02\x0f\x00\x16\x1e\x02\x03\t\x06\x01\x00 \x07\xbd\x0c~'
2024-01-07 16:15:54 [debug    ] HDLC frame could not be parsed. Need more data
2024-01-07 16:15:54 [debug    ] Received data                  data=b'~\xa8\xa4\xcf\x02#\x03\x99\x96\x00\xff\x12\x08\xd8\x02\x02\x0f\xff\x16#\x02\x03\t\x06\x01\x004\x07\x00\xff\x12\x08\xe1\x02\x02\x0f\xff\x16#\x02\x03\t\x06\x01\x00H\x07\x00\xff\x12\x08\xc5\x02\x02\x0f\xff\x16#\x02\x03\t\x06\x01\x00\x1f\x07\x00\xff\x12\x00U\x02\x02\x0f\xfe\x16!\x02\x03\t\x06\x01\x003\x07\x00\xff\x12\x006\x02\x02\x0f\xfe\x16!\x02\x03\t\x06\x01\x00G\x07\x00\xff\x12\x02\xce\x02\x02\x0f\xfe\x16!\x02\x03\t\x06\x01\x00\x01\x08\x01\xff\x06\x00"\x90h\x02\x02\x0f\x00\x16\x1e\x02\x03\t\x06\x01\x00\x01\x08\x02\xff\x06\x00*\x0f\x7f\x02\x02\x0f\x00\x16\x1e\x02\x03\t\x06\x01\x00g\xf9~' transport=HdlcTransport(client_logical_address=1, server_logical_address=16, io=SerialIO(port_name='/dev/ttyUSB0', baud_rate=115200, timeout=10, serial_port=Serial<id=0x7f9cbaa2e0, open=True>(port='/dev/ttyUSB0', baudrate=115200, bytesize=8, parity='N', stopbits=1, timeout=10, xonxoff=False, rtscts=False, dsrdtr=False)), server_physical_address=17, client_physical_address=None, extended_addressing=False, timeout=10, hdlc_connection=HdlcConnection(client_address=HdlcAddress(logical_address=16, physical_address=17, address_type='server', extended_addressing=False), server_address=HdlcAddress(logical_address=1, physical_address=None, address_type='client', extended_addressing=False), client_ssn=0, client_rsn=0, server_ssn=0, server_rsn=0, max_data_size=128, state=HdlcConnectionState(current_state=AWAITING_CONNECTION), buffer=bytearray(b'~\xa8\xa4\xcf\x02#\x03\x99\x96\xe6\xe7\x00\x0f\x00\x17\xc4@\x0c\x07\xe8\x01\x07\x07\x10\x0f7\x00\xff\xc4\x00\x02\x10\x02\x02\t\x06\x00\x00`\x01\x00\xff\t\x0885738459\x02\x02\t\x06\x00\x00`\x01\x01\xff\t\x071058708\x02\x03\t\x06\x01\x00\x01\x07\x00\xff\x06\x00\x00\x05\x9d\x02\x02\x0f\x00\x16\x1b\x02\x03\t\x06\x01\x00\x02\x07\x00\xff\x06\x00\x00\x00\x00\x02\x02\x0f\x00\x16\x1b\x02\x03\t\x06\x01\x00\x01\x08\x00\xff\x06\x00L\x9f\xe7\x02\x02\x0f\x00\x16\x1e\x02\x03\t\x06\x01\x00\x02\x08\x00\xff\x06\x00sk\xf7\x02\x02\x0f\x00\x16\x1e\x02\x03\t\x06\x01\x00 \x07\xbd\x0c~'), buffer_search_position=166), _send_buffer=[], out_buffer=bytearray(b''), in_buffer=bytearray(b''))
2024-01-07 16:15:54 [debug    ] Added data to buffer           data=b'~\xa8\xa4\xcf\x02#\x03\x99\x96\x00\xff\x12\x08\xd8\x02\x02\x0f\xff\x16#\x02\x03\t\x06\x01\x004\x07\x00\xff\x12\x08\xe1\x02\x02\x0f\xff\x16#\x02\x03\t\x06\x01\x00H\x07\x00\xff\x12\x08\xc5\x02\x02\x0f\xff\x16#\x02\x03\t\x06\x01\x00\x1f\x07\x00\xff\x12\x00U\x02\x02\x0f\xfe\x16!\x02\x03\t\x06\x01\x003\x07\x00\xff\x12\x006\x02\x02\x0f\xfe\x16!\x02\x03\t\x06\x01\x00G\x07\x00\xff\x12\x02\xce\x02\x02\x0f\xfe\x16!\x02\x03\t\x06\x01\x00\x01\x08\x01\xff\x06\x00"\x90h\x02\x02\x0f\x00\x16\x1e\x02\x03\t\x06\x01\x00\x01\x08\x02\xff\x06\x00*\x0f\x7f\x02\x02\x0f\x00\x16\x1e\x02\x03\t\x06\x01\x00g\xf9~'
2024-01-07 16:15:54 [debug    ] HDLC frame could not be parsed. Need more data

And it goes on like this forever with more and more data in the buffer.

Krolken commented 5 months ago

Sorry for a bit late response, I saw it during vacation and then I forgot about it.

You cant use the normal connection handling for P1 port data.

The P1 port just pushes data, and with an HDLC frame that usually is not used in the normal HDLC connection.

What you need to do is to create a listner that gets each HDLC-frame and the parse it.

It can just be a simple while loop.

Standard P1 port communcation is Ascii (IEC 62056-21 / IEC 1107) but your meter is set to HDLC. The norwegian standard for HAN port comunication is also HDLC push. Here is some example code to parse that that I have written: https://hanporten.se/norska/protokollet/. You should be able to see how to parse it there.

The data stucture might not be the same, but parse_as_dlms_data should give you a better view of the structure and then you just have to figure out what is what. It seems like they also push the OBIS-codes (\x01\x00\x01\x08\x00\xff\ = 1.0.1.8.0.255 = meter stand) so it should be possible to see what is what.

hjaltij commented 5 months ago

@jeremie-borel Did you get any further. I'm trying to do the same thing.

jeremie-borel commented 5 months ago

Hi, tanks to @Krolken answer I was able to guess the data structure. I've now written a small "proof of concept" and I spend so much time on this that I though its worth writing a small step by step to help others with slightly different smart meters: https://github.com/jeremie-borel/sie-p1-parser. Hope this can helps

Krolken commented 5 months ago

Seem like utils.parse_as_dlms_data() enters an infinate loop when decoding this data. Not all data is there. The unnumbered information frame is indicating that it is segmented. You you need to keep on reading HDLC frames until it is final=True. Then add all the HDLC payloads together and parse as DataNotification.

data = b'~\xa8\xa4\xcf\x02#\x03\x99\x96\xe6\xe7\x00\x0f\x00\x17\xc4@\x0c\x07\xe8\x01\x07\x07\x10\x0f7\x00\xff\xc4\x00\x02\x10\x02\x02\t\x06\x00\x00`\x01\x00\xff\t\x0885738459\x02\x02\t\x06\x00\x00`\x01\x01\xff\t\x071058708\x02\x03\t\x06\x01\x00\x01\x07\x00\xff\x06\x00\x00\x05\x9d\x02\x02\x0f\x00\x16\x1b\x02\x03\t\x06\x01\x00\x02\x07\x00\xff\x06\x00\x00\x00\x00\x02\x02\x0f\x00\x16\x1b\x02\x03\t\x06\x01\x00\x01\x08\x00\xff\x06\x00L\x9f\xe7\x02\x02\x0f\x00\x16\x1e\x02\x03\t\x06\x01\x00\x02\x08\x00\xff\x06\x00sk\xf7\x02\x02\x0f\x00\x16\x1e\x02\x03\t\x06\x01\x00 \x07\xbd\x0c~'
payload = UnnumberedInformationFrame.from_bytes(data).payload
dn = DataNotification.from_bytes(payload[3:])
dn.body
b'\x02\x10\x02\x02\t\x06\x00\x00`\x01\x00\xff\t\x0885738459\x02\x02\t\x06\x00\x00`\x01\x01\xff\t\x071058708\x02\x03\t\x06\x01\x00\x01\x07\x00\xff\x06\x00\x00\x05\x9d\x02\x02\x0f\x00\x16\x1b\x02\x03\t\x06\x01\x00\x02\x07\x00\xff\x06\x00\x00\x00\x00\x02\x02\x0f\x00\x16\x1b\x02\x03\t\x06\x01\x00\x01\x08\x00\xff\x06\x00L\x9f\xe7\x02\x02\x0f\x00\x16\x1e\x02\x03\t\x06\x01\x00\x02\x08\x00\xff\x06\x00sk\xf7\x02\x02\x0f\x00\x16\x1e\x02\x03\t\x06\x01\x00 \x07'

Should be parsed as this:

\x02\x10 - Structure, length 16 (but it is not 16 in lenghth
    \x02\x02 - substructure, length 2
          \t\x06\x00\x00`\x01\x00\xff - OBIS 0.0.96.1.255
          \t\x0885738459
    \x02\x02 - Next substructure. (obis and value
        \t\x06\x00\x00`\x01\x01\xff\t\x071058708
    \x02\x03 - substruture 3 items
         \t\x06\x01\x00\x01\x07\x00\xff
         \x06\x00\x00\x05\x9d
         \x02\x02 - sub-sub structure (shuóuld be scalar and unit.)
              \x0f\x00 
              \x16\x1b
      \x02\x03
         \t\x06\x01\x00\x02\x07\x00\xff
          \x06\x00\x00\x00\x00
         \x02\x02
              \x0f\x00
              \x16\x1b
       \x02\x03
        \t\x06\x01\x00\x01\x08\x00\xff
        \x06\x00L\x9f\xe7
        \x02\x02
             \x0f\x00
             \x16\x1e
        \x02\x03
            \t\x06\x01\x00\x02\x08\x00\xff
            \x06\x00sk\xf7
            \x02\x02
                  \x0f\x00
                  \x16\x1e
            \x02\x03
                 \t\x06\x01\x00 \x07

Not all data is here!
hjaltij commented 5 months ago

Thanks!

I'm actually trying to use the optical port on my AM550 because the P1 port is not there unless it's covered with a plastic piece, and I can't really open the meter to check since it's sealed.

Not sure if the optical port is even enabled for this so I might be completely out of luck. I'm not receiving any data from it at least.

Krolken commented 5 months ago

Thanks!

I'm actually trying to use the optical port on my AM550 because the P1 port is not there unless it's covered with a plastic piece, and I can't really open the meter to check since it's sealed.

Not sure if the optical port is even enabled for this so I might be completely out of luck. I'm not receiving any data from it at least.

You won't be able to get any data from the optical port via push. It is only full HDLC connection and most likely encrypted. If you can get the encryption keys from the meter you can use a management client association to read all data in the meter. If you don't have the encryption keys you can only access the public client, which just tells you information about the meter itself, not data measured.

The P1 port in Iskra AM550 is a plug in module that sits to the right under the top cover. If it is not visible there probably is no module installed. It is not a requirement in all countries.

You can get pulse-data from the led on the front of used kWh, but not that useful and annoying to connect.

If you want a simple solution that is good enough when you don't have a P1 port, I usually recommend an external energy meter with clamp on current sensors like Shelly PRO 3EM.

hjaltij commented 5 months ago

@Krolken Thanks that's super useful.

Apparently the energy company is about to replace my meter again since they never set this one up for remote reading. I got it installed when I switched to a 3-phase to fully support a charging station I had installed.

They say the new one will have a P1 port that is open for customers to read from. In the meantime I had already bought a Shelly 3EM but haven't installed it yet.

Krolken commented 4 months ago

I see this as solved and closing the issue.