Query SMA Energy Meter / Home Manager by UDP in

that manual is terrible - not nearly enough info to decode that protocol.

Fortunately, the python code gave me plenty of clues.

I was going to give you clues and pointers but TBF, this was a fun challenge so I did the lions share. It may not be 100% complete (or even accurate) but it should be close enough to progress...

[{"id":"9763dc2c.40756","type":"inject","z":"b872cb4b.5a6448","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":300,"y":580,"wires":[["97dec846.ffc208"]]},{"id":"97dec846.ffc208","type":"function","z":"b872cb4b.5a6448","name":"fake udp msg","func":"return { \n    \"payload\": Buffer.from([83, 77, 65, 0, 0, 4, 2, 160, 0, 0, 0, 1, 2, 76, 0, 16, 96, 105, 1, 116, 113, 89, 181, 228, 88, 186, 142, 41, 0, 1, 4, 0, 0, 0, 0, 74, 0, 1, 8, 0, 0, 0, 0, 6, 140, 178, 168, 168, 0, 2, 4, 0, 0, 0, 0, 0, 0, 2, 8, 0, 0, 0, 0, 7, 253, 178, 78, 24, 0, 3, 4, 0, 0, 0, 0, 0, 0, 3, 8, 0, 0, 0, 0, 0, 16, 235, 94, 240, 0, 4, 4, 0, 0, 0, 22, 30, 0, 4, 8, 0, 0, 0, 0, 12, 168, 135, 222, 48, 0, 9, 4, 0, 0, 0, 22, 30, 0, 9, 8, 0, 0, 0, 0, 12, 28, 154, 227, 224, 0, 10, 4, 0, 0, 0, 0, 0, 0, 10, 8, 0, 0, 0, 0, 9, 97, 63, 42, 104, 0, 13, 4, 0, 0, 0, 0, 13, 0, 14, 4, 0, 0, 0, 195, 82, 0, 21, 4, 0, 0, 0, 0, 0, 0, 21, 8, 0, 0, 0, 0, 3, 125, 229, 248, 40, 0, 22, 4, 0, 0, 0, 5, 89, 0, 22, 8, 0, 0, 0, 0, 7, 95, 110, 238, 0, 0, 23, 4, 0, 0, 0, 0, 0, 0, 23, 8, 0, 0, 0, 0, 0, 25, 7, 4, 144, 0, 24, 4, 0, 0, 0, 10, 18, 0, 24, 8, 0, 0, 0, 0, 4, 201, 201, 10, 64, 0, 29, 4, 0, 0, 0, 0, 0, 0, 29, 8, 0, 0, 0, 0, 5, 52, 51, 139, 248, 0, 30, 4, 0, 0, 0, 11, 103, 0, 30, 8, 0, 0, 0, 0, 7, 216, 157, 153, 232, 0, 31, 4, 0, 0, 0, 6, 73, 0, 32, 4, 0, 0, 3, 136, 221, 0, 33, 4, 0, 0, 0, 1, 213, 0, 41, 4, 0, 0, 0, 6, 77, 0, 41, 8, 0, 0, 0, 0, 2, 143, 16, 39, 40, 0, 42, 4, 0, 0, 0, 0, 0, 0, 42, 8, 0, 0, 0, 0, 0, 212, 170, 232, 136, 0, 43, 4, 0, 0, 0, 0, 0, 0, 43, 8, 0, 0, 0, 0, 0, 11, 51, 114, 184, 0, 44, 4, 0, 0, 0, 5, 74, 0, 44, 8, 0, 0, 0, 0, 2, 21, 225, 52, 240, 0, 49, 4, 0, 0, 0, 8, 58, 0, 49, 8, 0, 0, 0, 0, 3, 115, 86, 47, 64, 0, 50, 4, 0, 0, 0, 0, 0, 0, 50, 8, 0, 0, 0, 0, 0, 229, 93, 153, 200, 0, 51, 4, 0, 0, 0, 4, 5, 0, 52, 4, 0, 0, 3, 139, 244, 0, 53, 4, 0, 0, 0, 2, 254, 0, 61, 4, 0, 0, 0, 0, 0, 0, 61, 8, 0, 0, 0, 0, 1, 193, 39, 152, 200, 0, 62, 4, 0, 0, 0, 0, 170, 0, 62, 8, 0, 0, 0, 0, 1, 11, 3, 142, 8, 0, 63, 4, 0, 0, 0, 0, 0]),\n    \"fromip\": \"192.168.168.23:58874\", \"ip\": \"192.168.168.23\", \"port\": 58874, \"_msgid\": \"b43d1ee5.26a5f\" \n    }\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":460,"y":580,"wires":[["d31802c3.e2aef"]]},{"id":"d31802c3.e2aef","type":"buffer-parser","z":"b872cb4b.5a6448","name":"","data":"payload","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"string","name":"sma","offset":0,"length":3,"offsetbit":0,"scale":"1","mask":""},{"type":"uint32be","name":"Tag=>Tag0","offset":4,"length":1,"offsetbit":0,"scale":">> 4","mask":"0xff0"},{"type":"uint32be","name":"Tag=>Version","offset":4,"length":1,"offsetbit":0,"scale":"0","mask":"0xf"},{"type":"uint32be","name":"Group","offset":8,"length":1,"offsetbit":0,"scale":"0","mask":""},{"type":"uint32be","name":"item10","offset":25,"length":1,"offsetbit":0,"scale":">> 4","mask":"0xFFF0"},{"type":"uint16be","name":"ProtocolID","offset":16,"length":1,"offsetbit":0,"scale":"0","mask":""},{"type":"uint32be","name":"meter_identifier=>SusyID","offset":18,"length":1,"offsetbit":0,"scale":">> 4","mask":"0xFFF0"},{"type":"uint32be","name":"meter_identifier=>SerNo","offset":21,"length":1,"offsetbit":0,"scale":">> 4","mask":"0xFFF0"},{"type":"buffer","name":"data","offset":28,"length":-1,"offsetbit":0,"scale":"1","mask":""}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","resultType":"keyvalue","resultTypeType":"output","multipleResult":false,"fanOutMultipleResult":false,"setTopic":true,"outputs":1,"x":650,"y":580,"wires":[["6c5f3651.e1e838"]]},{"id":"6c5f3651.e1e838","type":"buffer-parser","z":"b872cb4b.5a6448","name":"","data":"payload.data","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"int16be","name":"measurement","offset":0,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"uint8","name":"datatype","offset":2,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"buffer","name":"data","offset":0,"length":-1,"offsetbit":0,"scale":"1","mask":""}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload","msgPropertyType":"str","resultType":"keyvalue","resultTypeType":"output","multipleResult":false,"fanOutMultipleResult":false,"setTopic":true,"outputs":1,"x":310,"y":680,"wires":[["35f7b433.19293c"]]},{"id":"35f7b433.19293c","type":"switch","z":"b872cb4b.5a6448","name":"8-counter, 4-actual, 0-version, other","property":"payload.datatype","propertyType":"msg","rules":[{"t":"eq","v":"8","vt":"num"},{"t":"eq","v":"4","vt":"num"},{"t":"eq","v":"0","vt":"num"},{"t":"else"}],"checkall":"true","repair":false,"outputs":4,"x":560,"y":680,"wires":[["99493b53.093878"],["701afb7c.a29b14"],["2518624f.84d29e"],["2518624f.84d29e"]]},{"id":"701afb7c.a29b14","type":"buffer-parser","z":"b872cb4b.5a6448","name":"","data":"payload.data","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"uint32be","name":"value","offset":4,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"buffer","name":"data","offset":8,"length":-1,"offsetbit":0,"scale":"1","mask":""}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload2","msgPropertyType":"str","resultType":"keyvalue","resultTypeType":"output","multipleResult":false,"fanOutMultipleResult":false,"setTopic":true,"outputs":1,"x":830,"y":700,"wires":[["fa42d9d5.faa708"]]},{"id":"99493b53.093878","type":"buffer-parser","z":"b872cb4b.5a6448","name":"","data":"payload.data","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"biguint64be","name":"value","offset":4,"length":1,"offsetbit":0,"scale":"1","mask":""},{"type":"buffer","name":"data","offset":12,"length":-1,"offsetbit":0,"scale":"1","mask":""}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload2","msgPropertyType":"str","resultType":"keyvalue","resultTypeType":"output","multipleResult":false,"fanOutMultipleResult":false,"setTopic":true,"outputs":1,"x":830,"y":660,"wires":[["fa42d9d5.faa708"]]},{"id":"fa42d9d5.faa708","type":"function","z":"b872cb4b.5a6448","name":"more data available?","func":"var sma_units = {\n    \"W\": 10,\n    \"VA\": 10,\n    \"VAr\": 10,\n    \"kWh\": 3600000,\n    \"kVAh\": 3600000,\n    \"kVArh\": 3600000,\n    \"A\": 1000,\n    \"V\": 1000,\n    \"°\": 1000,\n    \"Hz\": 1000,\n};\nvar sma_channels = {\n    //# totals\n    1: ['pconsume', 'W', 'kWh'],\n    2: ['psupply', 'W', 'kWh'],\n    3: ['qconsume', 'VAr', 'kVArh'],\n    4: ['qsupply', 'VAr', 'kVArh'],\n    9: ['sconsume', 'VA', 'kVAh'],\n    10: ['ssupply', 'VA', 'kVAh'],\n    13: ['cosphi', '°'],\n    14: ['frequency', 'Hz'],\n    //# phase 1\n    21: ['p1consume', 'W', 'kWh'],\n    22: ['p1supply', 'W', 'kWh'],\n    23: ['q1consume', 'VAr', 'kVArh'],\n    24: ['q1supply', 'VAr', 'kVArh'],\n    29: ['s1consume', 'VA', 'kVAh'],\n    30: ['s1supply', 'VA', 'kVAh'],\n    31: ['i1', 'A'],\n    32: ['u1', 'V'],\n    33: ['cosphi1', '°'],\n    //# phase 2\n    41: ['p2consume', 'W', 'kWh'],\n    42: ['p2supply', 'W', 'kWh'],\n    43: ['q2consume', 'VAr', 'kVArh'],\n    44: ['q2supply', 'VAr', 'kVArh'],\n    49: ['s2consume', 'VA', 'kVAh'],\n    50: ['s2supply', 'VA', 'kVAh'],\n    51: ['i2', 'A'],\n    52: ['u2', 'V'],\n    53: ['cosphi2', '°'],\n    //# phase 3\n    61: ['p3consume', 'W', 'kWh'],\n    62: ['p3supply', 'W', 'kWh'],\n    63: ['q3consume', 'VAr', 'kVArh'],\n    64: ['q3supply', 'VAr', 'kVArh'],\n    69: ['s3consume', 'VA', 'kVAh'],\n    70: ['s3supply', 'VA', 'kVAh'],\n    71: ['i3', 'A'],\n    72: ['u3', 'V'],\n    73: ['cosphi3', '°'],\n    //# common\n    36864: ['speedwire-version', ''],\n};\n\nmsg.result = msg.result || {};\n\nfunction decode_item_header(datatype, measurement) {\n    if (datatype == 4)\n        return 'actual'\n    else if (datatype == 8)\n        return 'counter';\n    else if (datatype == 0 && measurement == 36864)\n        return 'version'\n    else\n        return 'unknown_' + measurement;\n}\n\n// @ts-ignore\nvar pl2 = msg.payload2;\nvar pl = msg.payload;\n\nvar measurement = pl.measurement;\nvar datatype = pl.datatype;\nvar ch = sma_channels[measurement] || [];\nvar valuename = ch[0], unit = ch[1];\n\nvar hasValue = pl2.hasOwnProperty('value');\nif (valuename && hasValue) {\n    var value = pl2.value;\n    var typeName = decode_item_header(datatype, measurement);\n    msg.result[valuename] = msg.result[valuename] || {};\n    msg.result[valuename][typeName] = {};\n    if (typeName == \"actual\"){\n        msg.result[valuename][typeName].unit = unit;\n    }\n    var t = typeof value;\n    if (t===\"number\") {\n        msg.result[valuename][typeName].value = value / (sma_units[unit] || 1);\n    } else if (t === \"bigint\") {\n        msg.result[valuename][typeName].value = value / BigInt(sma_units[unit] || 1);\n    } else {\n        msg.result[valuename][typeName].value = value;\n    }\n}\n\n\n/** @type {Buffer} */ var buf = pl2.data;\nif (buf && buf.length >= 8) {\n    msg.payload = {\n        data: pl2.data\n    };\n    return [msg,null];\n}\nmsg.payload = msg.result;\nreturn [null, msg];\n","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1060,"y":700,"wires":[["4924e0b.c55cc2"],["214e43d8.b9817c"]]},{"id":"2518624f.84d29e","type":"buffer-parser","z":"b872cb4b.5a6448","name":"","data":"payload.data","dataType":"msg","specification":"spec","specificationType":"ui","items":[{"type":"buffer","name":"data","offset":8,"length":-1,"offsetbit":0,"scale":"1","mask":""}],"swap1":"","swap2":"","swap3":"","swap1Type":"swap","swap2Type":"swap","swap3Type":"swap","msgProperty":"payload2","msgPropertyType":"str","resultType":"keyvalue","resultTypeType":"output","multipleResult":false,"fanOutMultipleResult":false,"setTopic":true,"outputs":1,"x":830,"y":740,"wires":[["fa42d9d5.faa708"]]},{"id":"197fcf94.b189b","type":"link in","z":"b872cb4b.5a6448","name":"","links":["4924e0b.c55cc2"],"x":175,"y":680,"wires":[["6c5f3651.e1e838"]]},{"id":"4924e0b.c55cc2","type":"link out","z":"b872cb4b.5a6448","name":"","links":["197fcf94.b189b"],"x":1215,"y":700,"wires":[]},{"id":"214e43d8.b9817c","type":"debug","z":"b872cb4b.5a6448","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":1130,"y":760,"wires":[]}]
1 Like