ganehag / pyMeterBus

Pure Python implementation of the Meter-Bus (M-Bus EN13757-3) protocol.
BSD 3-Clause "New" or "Revised" License
74 stars 40 forks source link

help decoding SND_NR #27

Open bencaby opened 5 months ago

bencaby commented 5 months ago

Hi guys I'm trying to decode this frame 20 44 2D 2C 97 18 58 68 1D 16 8D 20 55 82 E2 F5 23 CC EE ED C2 B1 1C 50 35 0B EA CE 7E 01 D0 3A AD all the libraries I tested until now gives me incoherent data. I cannot find the right spec for CI-Field = 0x8D [0x8D: 'Extended Link Layer II (8 Byte)'] I'm pretty sure byte 12 (55) is a sequence number as it increase by one each new message. Then I'm lost when I try to decode this part: 82 E2 F5 23 CC EE ED C2 B1 1C 50 35 0B EA CE 7E 01 D0 3A AD Are we looking for a header ? Is 82 a new CI-Field ? [0x82: 'For future use',]

My meter is a kamstrup flow IQ 3100 and it should use 128bits AES encryption. I don't think this library supports encrypted data but if I can get the encrypted payload, I'll be able to fork and add encryption support.

I hope you can help me ... Regards.

ganehag commented 5 months ago

Sorry for the late reply.

pyMeterbus should be able to decode that for you.

echo 20442D2C971858681D168D205582E2F523CCEEEDC2B11C50350BEACE7E01D03AAD | xxd -r -p > frame.data

And then;

import meterbus

with open("frame.data", 'rb') as f:
    frame = meterbus.load(f.read())
    print(frame.to_JSON())

Or directly in Python code.

import meterbus

data = "\x20\x44\x2D\x2C\x97\x18\x58\x68\x1D\x16\x8D\x20\x55\x82\xE2\xF5\x23\xCC\xEE\xED\xC2\xB1\x1C\x50\x35\x0B\xEA\xCE\x7E\x01\xD0\x3A\xAD"
frame = meterbus.load(data)
print(frame.to_JSON())

Either should give you the content. There are two record. Not sure if there are more that the library are unable to decode.

{
    "header": {
        "manufacturer": "KAM",
        "identification": "0x68, 0x58, 0x18, 0x97",
        "version": "0x1d",
        "device_type": "0x16",
        "type": "0x8d"
    },
    "records": [
        {
            "value": 0.205330000000000012505552149377763271331787109375,
            "unit": "MeasureUnit.M3_S",
            "type": "VIFUnit.VOLUME_FLOW_EXT_S",
            "storage_number": 1700,
            "function": "FunctionType.INSTANTANEOUS_VALUE",
            "tariff": 46,
            "device": 3
        },
        {
            "value": 1004,
            "unit": "MeasureUnit.BAR",
            "type": "VIFUnit.PRESSURE",
            "storage_number": 0,
            "function": "FunctionType.INSTANTANEOUS_VALUE"
        }
    ],
    "length": 32,
    "c": "0x44"
}

The frame returned from the parser is a WTelegramSndNr and the frame.is_encrypted flag is False, so the frame should not be encrypted. Unless the library is missing something.

Also, the values decoded are... highly unlikely. 1004 Bar pressure is... a lot :-)

ganehag commented 5 months ago

I did spend a couple of minutes on taking a look at the code and it's likely a bug that it manages to decode something. It shouldn't.

bencaby commented 5 months ago

indeed my first attempt was to use the library directly and I was happy to see records but they are not valid. The 0x8d field implies an ELL (Extended Link Layer) in which the SN (session number) contains a bit stating that this frame is encrypted. I finally found the documentation of that 0x8d extended layer. https://www.iot.com.tr/uploads/pdf/Telit_Wireless_M-bus_2013_Part4_User_Guide_r14.pdf

ganehag commented 5 months ago

A proper implementation of Wireless M-Bus would take weeks. You could always try https://platform.lobaro.com/#/wmbus/parser as a way to just test decoding the frame. But since its encrypted you are going to need the key anyway.