Read data from Kostal pv and battery using Sunspec over Modbus TCP
This flow reads data from a sunspec (modbus TCP) inverter for display in node-red.
Most important is the conversion from the given data to a floating point number.
Have fun,
Steffen Maier
[{"id":"73b5f3ca.3cce4c","type":"modbus-read","z":"9131874f.378c58","name":"Battery capacity %","topic":"","showStatusActivities":false,"logIOActivities":false,"showErrors":false,"unitid":"","dataType":"HoldingRegister","adr":"514","quantity":"1","rate":"3","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"c34312b7.3a695","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":130,"y":620,"wires":[["68321116.03f78"],[]]},{"id":"68321116.03f78","type":"function","z":"9131874f.378c58","name":"","func":"\nmsg.result = msg.payload[0];\n\nreturn msg;","outputs":1,"noerr":0,"x":370,"y":620,"wires":[["58f3ba87.8fb744"]]},{"id":"58f3ba87.8fb744","type":"change","z":"9131874f.378c58","name":"","rules":[{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":760,"y":620,"wires":[["61b67ca3.8de804"]]},{"id":"61b67ca3.8de804","type":"function","z":"9131874f.378c58","name":"","func":"msg.payload = msg.result * 0.095 ;\nmsg.topic = 'Batterie';\n\nreturn msg;","outputs":1,"noerr":0,"x":970,"y":620,"wires":[["ef4e870.5370f78","67e24a00.ab30c4"]]},{"id":"ef4e870.5370f78","type":"ui_gauge","z":"9131874f.378c58","name":"","group":"b15bce1.c9f333","order":2,"width":0,"height":0,"gtype":"gage","title":"Battery rest capacity","label":"kwh","format":"{{value | number:3}}","min":0,"max":"9.5","colors":["#b30000","#e6e600","#3acb3e"],"seg1":"","seg2":"","x":1980,"y":560,"wires":[]},{"id":"67e24a00.ab30c4","type":"delay","z":"9131874f.378c58","name":"","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"10","rateUnits":"minute","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":1590,"y":660,"wires":[["9b17abdf.34c808"]]},{"id":"9b17abdf.34c808","type":"ui_chart","z":"9131874f.378c58","name":"","group":"b15bce1.c9f333","order":1,"width":0,"height":0,"label":"Battery rest capacity chart","chartType":"line","legend":"false","xformat":"HH:mm","interpolate":"linear","nodata":"","dot":false,"ymin":"0","ymax":"10","removeOlder":"24","removeOlderPoints":"","removeOlderUnit":"3600","cutout":0,"useOneColor":false,"useUTC":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#d62728","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"outputs":1,"x":1970,"y":660,"wires":[[]]},{"id":"4600cbb0.41ef24","type":"function","z":"9131874f.378c58","name":"","func":"msg.payload = msg.result / 1000;\nmsg.topic = 'PV Production';\n\nreturn msg;","outputs":1,"noerr":0,"x":970,"y":160,"wires":[["7b26ae0a.79734"]]},{"id":"afd35ab0.84c9c8","type":"function","z":"9131874f.378c58","name":"","func":"msg.payload = msg.summe;\nmsg.topic = 'Consumption';\n\nreturn msg;","outputs":1,"noerr":0,"x":1750,"y":220,"wires":[["4c3f90d1.993a7"]]},{"id":"acde408a.6e6c6","type":"function","z":"9131874f.378c58","name":"","func":"msg.payload = msg.result / 1000;\nmsg.topic = 'from/toGrid';\n\nreturn msg;","outputs":1,"noerr":0,"x":950,"y":480,"wires":[["480f4e23.5c355"]]},{"id":"d3029da0.4c09c","type":"change","z":"9131874f.378c58","name":"","rules":[{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":780,"y":160,"wires":[["4600cbb0.41ef24"]]},{"id":"7b26ae0a.79734","type":"ui_gauge","z":"9131874f.378c58","name":"","group":"b273175c.57cfc8","order":1,"width":0,"height":0,"gtype":"gage","title":"PV Production","label":"kW","format":"{{value | number:3}}","min":0,"max":"10","colors":["#b30000","#e6e600","#3acb3e"],"seg1":"","seg2":"","x":1980,"y":100,"wires":[]},{"id":"5f6b91ef.4081","type":"change","z":"9131874f.378c58","name":"","rules":[{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1560,"y":220,"wires":[["afd35ab0.84c9c8"]]},{"id":"4c3f90d1.993a7","type":"ui_gauge","z":"9131874f.378c58","name":"","group":"2003f5f4.e2886a","order":2,"width":0,"height":0,"gtype":"gage","title":"Total own use","label":"kw","format":"{{value | number:3}}","min":0,"max":"10","colors":["#00e62e","#e6e600","#d10000"],"seg1":"","seg2":"","x":1960,"y":220,"wires":[]},{"id":"1562d00d.584e4","type":"change","z":"9131874f.378c58","name":"","rules":[{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":760,"y":480,"wires":[["acde408a.6e6c6"]]},{"id":"480f4e23.5c355","type":"ui_gauge","z":"9131874f.378c58","name":"","group":"b273175c.57cfc8","order":2,"width":0,"height":0,"gtype":"gage","title":"ToGrid/FromGrid","label":"kW","format":"{{value | number:3}}","min":"-10","max":"10","colors":["#00e62e","#e6e600","#d10000"],"seg1":"","seg2":"","x":1970,"y":480,"wires":[]},{"id":"d76dc114.29757","type":"function","z":"9131874f.378c58","name":"convert to floating point number","func":"function convert(number2, number1)\n{\n number1 = parseInt(number1);\n num1 = number1.toString(16);\n \n\twhile(4 - num1.length > 0)\n num1 = \"0\" + num1; \n \n number2 = parseInt(number2);\n num2 = number2.toString(16);\n\n\twhile(4 - num2.length > 0)\n num2 = \"0\" + num2;\n \n concatnum = \"0x\" + num1.toString() + num2.toString();\n\n\n var floatnum = parseFloat(concatnum, 16);\n floatnum = Math.round((floatnum + Number.EPSILON) * 10000) / 10000;\n \n return floatnum;\n \n}\n\nfunction parseFloat(str) {\n var float = 0, sign, order, mantiss,exp,\n int = 0, multi = 1;\n if (/^0x/.exec(str)) {\n int = parseInt(str,16);\n }else{\n for (var i = str.length -1; i >=0; i -= 1) {\n if (str.charCodeAt(i)>255) {\n console.log('Wrong string parametr'); \n return false;\n }\n int += str.charCodeAt(i) * multi;\n multi *= 256;\n }\n }\n sign = (int>>>31)?-1:1;\n exp = (int >>> 23 & 0xff) - 127;\n mantissa = ((int & 0x7fffff) + 0x800000).toString(2);\n for (i=0; i<mantissa.length; i+=1){\n float += parseInt(mantissa[i])? Math.pow(2,exp):0;\n exp--;\n }\n return float*sign;\n}\n\nmsg.result = convert(msg.payload[0],msg.payload[1])\n\nreturn msg;","outputs":1,"noerr":0,"x":470,"y":160,"wires":[["d3029da0.4c09c"]]},{"id":"713487dd.3b5a48","type":"function","z":"9131874f.378c58","name":"","func":"msg.summe = msg.payload.OwnUseFromBattery + msg.payload.OwnUseFromGrid + msg.payload.OwnUseFromPV;\nreturn msg;","outputs":1,"noerr":0,"x":1350,"y":220,"wires":[["5f6b91ef.4081"]]},{"id":"5280cdea.612f54","type":"function","z":"9131874f.378c58","name":"convert to floating point number","func":"function convert(number2, number1)\n{\n number1 = parseInt(number1);\n num1 = number1.toString(16);\n \n\twhile(4 - num1.length > 0)\n num1 = \"0\" + num1; \n \n number2 = parseInt(number2);\n num2 = number2.toString(16);\n\n\twhile(4 - num2.length > 0)\n num2 = \"0\" + num2;\n \n concatnum = \"0x\" + num1.toString() + num2.toString();\n\n\n var floatnum = parseFloat(concatnum, 16);\n floatnum = Math.round((floatnum + Number.EPSILON) * 10000) / 10000;\n \n return floatnum;\n \n}\n\nfunction parseFloat(str) {\n var float = 0, sign, order, mantiss,exp,\n int = 0, multi = 1;\n if (/^0x/.exec(str)) {\n int = parseInt(str,16);\n }else{\n for (var i = str.length -1; i >=0; i -= 1) {\n if (str.charCodeAt(i)>255) {\n console.log('Wrong string parametr'); \n return false;\n }\n int += str.charCodeAt(i) * multi;\n multi *= 256;\n }\n }\n sign = (int>>>31)?-1:1;\n exp = (int >>> 23 & 0xff) - 127;\n mantissa = ((int & 0x7fffff) + 0x800000).toString(2);\n for (i=0; i<mantissa.length; i+=1){\n float += parseInt(mantissa[i])? Math.pow(2,exp):0;\n exp--;\n }\n return float*sign;\n}\n\nmsg.result = convert(msg.payload[0],msg.payload[1])\n\nreturn msg;","outputs":1,"noerr":0,"x":450,"y":480,"wires":[["1562d00d.584e4"]]},{"id":"cd0da3dd.a6e2a","type":"modbus-read","z":"9131874f.378c58","name":"PV Production","topic":"","showStatusActivities":false,"logIOActivities":false,"showErrors":false,"unitid":"","dataType":"HoldingRegister","adr":"172","quantity":"2","rate":"3","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"c34312b7.3a695","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":130,"y":160,"wires":[["d76dc114.29757"],[]]},{"id":"7b3645c9.fb91cc","type":"join","z":"9131874f.378c58","name":"","mode":"custom","build":"object","property":"payload","propertyType":"msg","key":"topic","joiner":"\\n","joinerType":"str","accumulate":false,"timeout":"2.5","count":"3","reduceRight":false,"reduceExp":"","reduceInit":"","reduceInitType":"","reduceFixup":"","x":1190,"y":220,"wires":[["713487dd.3b5a48"]]},{"id":"94a1ac45.9f80f","type":"modbus-read","z":"9131874f.378c58","name":"Total power","topic":"","showStatusActivities":false,"logIOActivities":false,"showErrors":false,"unitid":"","dataType":"HoldingRegister","adr":"252","quantity":"2","rate":"3","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"c34312b7.3a695","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":130,"y":480,"wires":[["5280cdea.612f54"],[]]},{"id":"e3038619.452d68","type":"function","z":"9131874f.378c58","name":"","func":"msg.payload = msg.result / 1000;\nmsg.topic = 'OwnUseFromBattery';\n\nreturn msg;","outputs":1,"noerr":0,"x":970,"y":260,"wires":[["7b3645c9.fb91cc","f877378f.18ac48"]]},{"id":"e288452a.7220e8","type":"function","z":"9131874f.378c58","name":"","func":"msg.payload = msg.result / 1000;\nmsg.topic = 'OwnUseFromGrid';\n\nreturn msg;","outputs":1,"noerr":0,"x":970,"y":320,"wires":[["7b3645c9.fb91cc","b31de177.2be47"]]},{"id":"1da7401.a1951c","type":"function","z":"9131874f.378c58","name":"","func":"msg.payload = msg.result / 1000;\nmsg.topic = 'OwnUseFromPV';\n\nreturn msg;","outputs":1,"noerr":0,"x":950,"y":380,"wires":[["7b3645c9.fb91cc","392328d5.321818"]]},{"id":"3e25cdbb.b0f4a2","type":"change","z":"9131874f.378c58","name":"","rules":[{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":780,"y":260,"wires":[["e3038619.452d68"]]},{"id":"f877378f.18ac48","type":"ui_gauge","z":"9131874f.378c58","name":"","group":"d6f630d1.5736c","order":2,"width":0,"height":0,"gtype":"gage","title":"Own use from Battery","label":"kW","format":"{{value | number:3}}","min":0,"max":"10","colors":["#00e62e","#e6e600","#d10000"],"seg1":"","seg2":"","x":1980,"y":280,"wires":[]},{"id":"c4e4fe0.fe0d4","type":"change","z":"9131874f.378c58","name":"","rules":[{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":780,"y":320,"wires":[["e288452a.7220e8"]]},{"id":"b31de177.2be47","type":"ui_gauge","z":"9131874f.378c58","name":"","group":"d6f630d1.5736c","order":3,"width":0,"height":0,"gtype":"gage","title":"Own use from grid","label":"kW","format":"{{value | number:3}}","min":0,"max":"10","colors":["#00e62e","#e6e600","#d10000"],"seg1":"","seg2":"","x":1970,"y":320,"wires":[]},{"id":"7c2139c0.9a45d8","type":"change","z":"9131874f.378c58","name":"","rules":[{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":760,"y":380,"wires":[["1da7401.a1951c"]]},{"id":"392328d5.321818","type":"ui_gauge","z":"9131874f.378c58","name":"","group":"d6f630d1.5736c","order":1,"width":0,"height":0,"gtype":"gage","title":"Own use from PV","label":"kW","format":"{{value | number:3}}","min":0,"max":"10","colors":["#00e62e","#e6e600","#d10000"],"seg1":"","seg2":"","x":1970,"y":360,"wires":[]},{"id":"2842bccb.3696e4","type":"function","z":"9131874f.378c58","name":"convert to floating point number","func":"function convert(number2, number1)\n{\n number1 = parseInt(number1);\n num1 = number1.toString(16);\n \n\twhile(4 - num1.length > 0)\n num1 = \"0\" + num1; \n \n number2 = parseInt(number2);\n num2 = number2.toString(16);\n\n\twhile(4 - num2.length > 0)\n num2 = \"0\" + num2;\n \n concatnum = \"0x\" + num1.toString() + num2.toString();\n\n\n var floatnum = parseFloat(concatnum, 16);\n floatnum = Math.round((floatnum + Number.EPSILON) * 10000) / 10000;\n \n return floatnum;\n \n}\n\nfunction parseFloat(str) {\n var float = 0, sign, order, mantiss,exp,\n int = 0, multi = 1;\n if (/^0x/.exec(str)) {\n int = parseInt(str,16);\n }else{\n for (var i = str.length -1; i >=0; i -= 1) {\n if (str.charCodeAt(i)>255) {\n console.log('Wrong string parametr'); \n return false;\n }\n int += str.charCodeAt(i) * multi;\n multi *= 256;\n }\n }\n sign = (int>>>31)?-1:1;\n exp = (int >>> 23 & 0xff) - 127;\n mantissa = ((int & 0x7fffff) + 0x800000).toString(2);\n for (i=0; i<mantissa.length; i+=1){\n float += parseInt(mantissa[i])? Math.pow(2,exp):0;\n exp--;\n }\n return float*sign;\n}\n\nmsg.result = convert(msg.payload[0],msg.payload[1])\n\nreturn msg;","outputs":1,"noerr":0,"x":470,"y":260,"wires":[["3e25cdbb.b0f4a2"]]},{"id":"cb9fb32f.5c5f6","type":"function","z":"9131874f.378c58","name":"convert to floating point number","func":"function convert(number2, number1)\n{\n number1 = parseInt(number1);\n num1 = number1.toString(16);\n \n\twhile(4 - num1.length > 0)\n num1 = \"0\" + num1; \n \n number2 = parseInt(number2);\n num2 = number2.toString(16);\n\n\twhile(4 - num2.length > 0)\n num2 = \"0\" + num2;\n \n concatnum = \"0x\" + num1.toString() + num2.toString();\n\n\n var floatnum = parseFloat(concatnum, 16);\n floatnum = Math.round((floatnum + Number.EPSILON) * 10000) / 10000;\n \n return floatnum;\n \n}\n\nfunction parseFloat(str) {\n var float = 0, sign, order, mantiss,exp,\n int = 0, multi = 1;\n if (/^0x/.exec(str)) {\n int = parseInt(str,16);\n }else{\n for (var i = str.length -1; i >=0; i -= 1) {\n if (str.charCodeAt(i)>255) {\n console.log('Wrong string parametr'); \n return false;\n }\n int += str.charCodeAt(i) * multi;\n multi *= 256;\n }\n }\n sign = (int>>>31)?-1:1;\n exp = (int >>> 23 & 0xff) - 127;\n mantissa = ((int & 0x7fffff) + 0x800000).toString(2);\n for (i=0; i<mantissa.length; i+=1){\n float += parseInt(mantissa[i])? Math.pow(2,exp):0;\n exp--;\n }\n return float*sign;\n}\n\nmsg.result = convert(msg.payload[0],msg.payload[1])\n\nreturn msg;","outputs":1,"noerr":0,"x":470,"y":320,"wires":[["c4e4fe0.fe0d4"]]},{"id":"47c5d548.e9910c","type":"function","z":"9131874f.378c58","name":"convert to floating point number","func":"function convert(number2, number1)\n{\n number1 = parseInt(number1);\n num1 = number1.toString(16);\n \n\twhile(4 - num1.length > 0)\n num1 = \"0\" + num1; \n \n number2 = parseInt(number2);\n num2 = number2.toString(16);\n\n\twhile(4 - num2.length > 0)\n num2 = \"0\" + num2;\n \n concatnum = \"0x\" + num1.toString() + num2.toString();\n\n\n var floatnum = parseFloat(concatnum, 16);\n floatnum = Math.round((floatnum + Number.EPSILON) * 10000) / 10000;\n \n return floatnum;\n \n}\n\nfunction parseFloat(str) {\n var float = 0, sign, order, mantiss,exp,\n int = 0, multi = 1;\n if (/^0x/.exec(str)) {\n int = parseInt(str,16);\n }else{\n for (var i = str.length -1; i >=0; i -= 1) {\n if (str.charCodeAt(i)>255) {\n console.log('Wrong string parametr'); \n return false;\n }\n int += str.charCodeAt(i) * multi;\n multi *= 256;\n }\n }\n sign = (int>>>31)?-1:1;\n exp = (int >>> 23 & 0xff) - 127;\n mantissa = ((int & 0x7fffff) + 0x800000).toString(2);\n for (i=0; i<mantissa.length; i+=1){\n float += parseInt(mantissa[i])? Math.pow(2,exp):0;\n exp--;\n }\n return float*sign;\n}\n\nmsg.result = convert(msg.payload[0],msg.payload[1])\n\nreturn msg;","outputs":1,"noerr":0,"x":450,"y":380,"wires":[["7c2139c0.9a45d8"]]},{"id":"f6bf98f5.d4b1b8","type":"modbus-read","z":"9131874f.378c58","name":"Own use from battery","topic":"","showStatusActivities":false,"logIOActivities":false,"showErrors":false,"unitid":"","dataType":"HoldingRegister","adr":"106","quantity":"2","rate":"3","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"c34312b7.3a695","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":160,"y":260,"wires":[["2842bccb.3696e4"],[]]},{"id":"e4f4faab.38ea28","type":"modbus-read","z":"9131874f.378c58","name":"Own use from grid","topic":"","showStatusActivities":false,"logIOActivities":false,"showErrors":false,"unitid":"","dataType":"HoldingRegister","adr":"108","quantity":"2","rate":"3","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"c34312b7.3a695","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":150,"y":320,"wires":[["cb9fb32f.5c5f6"],[]]},{"id":"ce2cb3b9.01854","type":"modbus-read","z":"9131874f.378c58","name":"Own use from PV","topic":"","showStatusActivities":false,"logIOActivities":false,"showErrors":false,"unitid":"","dataType":"HoldingRegister","adr":"116","quantity":"2","rate":"3","rateUnit":"s","delayOnStart":false,"startDelayTime":"","server":"c34312b7.3a695","useIOFile":false,"ioFile":"","useIOForPayload":false,"x":140,"y":380,"wires":[["47c5d548.e9910c"],[]]},{"id":"c34312b7.3a695","type":"modbus-client","z":"","name":"Kostal","clienttype":"tcp","bufferCommands":true,"stateLogEnabled":false,"queueLogEnabled":false,"tcpHost":"192.168.175.1","tcpPort":"1502","tcpType":"DEFAULT","serialPort":"/dev/ttyUSB","serialType":"RTU-BUFFERD","serialBaudrate":"9600","serialDatabits":"8","serialStopbits":"1","serialParity":"none","serialConnectionDelay":"100","unit_id":71,"commandDelay":1,"clientTimeout":1000,"reconnectOnTimeout":true,"reconnectTimeout":2000,"parallelUnitIdsAllowed":true},{"id":"b15bce1.c9f333","type":"ui_group","z":"","name":"Batterie","tab":"cbd0d10a.bc2d","order":2,"disp":true,"width":"6","collapse":false},{"id":"b273175c.57cfc8","type":"ui_group","z":"","name":"Gesamt","tab":"cbd0d10a.bc2d","order":1,"disp":true,"width":"6","collapse":false},{"id":"2003f5f4.e2886a","type":"ui_group","z":"","name":"Verbrauch Gesamt","tab":"cbd0d10a.bc2d","order":4,"disp":true,"width":"6","collapse":false},{"id":"d6f630d1.5736c","type":"ui_group","z":"","name":"Verbrauch","tab":"cbd0d10a.bc2d","order":3,"disp":true,"width":"6","collapse":false},{"id":"cbd0d10a.bc2d","type":"ui_tab","z":"","name":"PV Infos","icon":"dashboard","disabled":false,"hidden":false}]