NEWS
Pylontech mit Nodered in den ioBroker (geschlossen)
-
Hallo zusammen,
ich habe mir einen Flow zum Auslesen der Pylontech Batterien über die RS232 Console mit anschließender Übertragung nach ioBroker gebastelt.
Die Daten werden im ioBroker unter pylontech.0 unter der Seriennummer abgelegt.
Ich habe 4 Batterien. Aktuell sind im Flow 5 vorgesehen, wovon 4 aktiviert sind.
Der Flow kann aber belibig bis zu 15 erweitert werden.
In der aktuellen Einstellung werden die Daten alle 5 Min abgeholt.Der Flow benötigt "node-red-node-serialport".
Zum Anschluss wird ein RS232/USB Wandler oder etwas Ähnliches benötigt auch eine Übertragung des Comports mit einem ESP ist möglich.
Das Kabel muss an die erste Batterie an den Konsolenport angeschlossen werden.Würde mich über Response freuen. Theoretisch kann ich auch einen Adapter daraus bauen.
Die Konsole ist ab Werk auf 1200Baud eingestellt.
Vor dem ersten Zugriff muss die untere V24 mit ihrer Verbindung deaktiviert und die Obere aktiviert werden. Dann einmal den Injekt ausführen.
Sollten danach keine Daten kommen, einmal den init Injekt clicken.[{"id":"8a67418ecc3cedb7","type":"debug","z":"c8efb1fdd535ecb6","name":"debug 1","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1260,"y":400,"wires":[]},{"id":"3f1a6c3e7e5f8e9e","type":"debug","z":"c8efb1fdd535ecb6","name":"debug 2","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":1440,"y":460,"wires":[]},{"id":"6e84de1dc0b0e89a","type":"serial request","z":"c8efb1fdd535ecb6","name":"","serial":"4a956651a40d8e44","x":1020,"y":520,"wires":[["8a67418ecc3cedb7","4ec640d7fa3e2470"]]},{"id":"963306c8b42714bd","type":"change","z":"c8efb1fdd535ecb6","name":"bat 1","rules":[{"t":"set","p":"payload","pt":"msg","to":"bat 1","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":680,"wires":[["6e84de1dc0b0e89a"]]},{"id":"a30bf3dc65887c3f","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":740,"wires":[["806b43c1963ce85a","2e42141b0c0fd3ab"]]},{"id":"806b43c1963ce85a","type":"change","z":"c8efb1fdd535ecb6","name":"bat 2","rules":[{"t":"set","p":"payload","pt":"msg","to":"bat 2","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":740,"wires":[["6e84de1dc0b0e89a"]]},{"id":"3e0e94f84b8388df","type":"change","z":"c8efb1fdd535ecb6","name":"bat 3","rules":[{"t":"set","p":"payload","pt":"msg","to":"bat 3","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":800,"wires":[["6e84de1dc0b0e89a"]]},{"id":"dab2179316524305","type":"change","z":"c8efb1fdd535ecb6","name":"bat 4","rules":[{"t":"set","p":"payload","pt":"msg","to":"bat 4","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":860,"wires":[["6e84de1dc0b0e89a"]]},{"id":"fb3670e4512d05b6","type":"change","z":"c8efb1fdd535ecb6","d":true,"name":"bat 5","rules":[{"t":"set","p":"payload","pt":"msg","to":"bat 5","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":920,"wires":[["6e84de1dc0b0e89a"]]},{"id":"ccc464b0e4c3207c","type":"change","z":"c8efb1fdd535ecb6","name":"soh 1","rules":[{"t":"set","p":"payload","pt":"msg","to":"soh 1","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":1020,"wires":[["6e84de1dc0b0e89a"]]},{"id":"2e42141b0c0fd3ab","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":800,"wires":[["3e0e94f84b8388df","6d4cdbe12aa578f7"]]},{"id":"6d4cdbe12aa578f7","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":860,"wires":[["dab2179316524305","fe6a3514e2a5b4f6"]]},{"id":"fe6a3514e2a5b4f6","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":920,"wires":[["fb3670e4512d05b6","edb87fb32e777632"]]},{"id":"edb87fb32e777632","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":1020,"wires":[["ccc464b0e4c3207c","d15ab215db481e94"]]},{"id":"52eb196c22e0a202","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":680,"wires":[["963306c8b42714bd","a30bf3dc65887c3f"]]},{"id":"752d78cddb20a26e","type":"change","z":"c8efb1fdd535ecb6","name":"info 1","rules":[{"t":"set","p":"payload","pt":"msg","to":"info 1","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":240,"wires":[["6e84de1dc0b0e89a"]]},{"id":"4ec640d7fa3e2470","type":"function","z":"c8efb1fdd535ecb6","name":"Pylontech toIOB","func":"const baseTopic = 'pylontech.0.';\n\nfunction convert(str) {\n const number = /^(-|\\+)?\\d+$/g;\n const numberP = /^(-|\\+)?\\d+%$/g;\n const numbermAH = /^(-|\\+)?\\d+ mAH$/g;\n const numbermA = /^(-|\\+)?\\d+mA$/g;\n if (number.test(str)) {\n return { payload: parseInt(str, 10) };\n }\n if (numberP.test(str)) {\n return { payload: parseInt(str, 10), unit: '%' };\n }\n if (numbermAH.test(str)) {\n return { payload: parseInt(str, 10), unit: 'mAh' };\n }\n if (numbermA.test(str)) {\n return { payload: parseInt(str, 10), unit: 'mA' };\n }\n return { payload: str };\n}\n\nfunction sendVal(name, topic, val) {\n const r = convert(val);\n const msg = {\n payload: r.payload,\n stateName: name,\n stateReadonly: true,\n stateType: typeof r.payload,\n topic,\n ack: true,\n };\n if (r.unit) {\n msg.stateUnit = r.unit;\n }\n node.status({ fill: 'green', shape: 'ring', text: JSON.stringify(msg) });\n node.send(msg);\n}\n\nfunction processData(filter, mkPath, ignoreKeys) {\n const head = filter.exec(msg.payload);\n if (head) {\n for (let i = 1; i < head.length; i++) {\n head[i] = head[i].trim();\n }\n for (let match; (match = filter.exec(msg.payload)) !== null;) {\n const dat = {};\n for (let i = 1; i < match.length; i++) {\n if (match[i]) {\n dat[head[i]] = match[i].trim();\n }\n }\n const spath = mkPath(dat);\n Object.keys(dat).forEach(key => {\n if (ignoreKeys(dat, key)) {\n sendVal(key, spath + key.replaceAll('.', '').replaceAll(' ', '_').toLocaleLowerCase(), dat[key]);\n }\n });\n }\n }\n}\n\nconst prompt = /(pylon>)(\\S+)\\s(\\d+)/g;\nconst cmd = prompt.exec(msg.payload);\nif (cmd && cmd[2] === 'info') {\n let ok = false;\n const row = /(.+\\S)\\s+:\\s(.*)/gm;\n const data = {};\n for (let match; (match = row.exec(msg.payload)) !== null;) {\n data[match[1]] = match[2];\n }\n if (data.Barcode) {\n ok = true;\n const path = baseTopic + data.Barcode.replaceAll(' ', '_');\n global.set(`pylontech${cmd[3]}`, path);\n Object.keys(data).forEach(key => {\n if (key !== 'Barcode') {\n sendVal(key, `${path}.info.${key.replaceAll(' ', '_').toLocaleLowerCase()}`, data[key]);\n }\n });\n sendVal('Barcode', `${baseTopic}info${cmd[3]}.barcode`, data.Barcode);\n }\n sendVal('Verbunden', `${baseTopic}info${cmd[3]}.connected`, ok);\n} else if (cmd && cmd[2] === 'bat') {\n const path = global.get(`pylontech${cmd[3]}`);\n if (path) {\n processData(\n /^(.{9})(.{9})(.{9})(.{9})(.{13})(.{13})(.{13})(.{13})(.{12})(.{14})(.{1,3})/gm,\n dat => {\n return `${path}.battery${(parseInt(dat.Battery, 10) + 1).toString().padStart(2, '0')}.`;\n },\n (dat, key) => {\n return !['Battery'].includes(key);\n }\n );\n }\n} else if (cmd && cmd[2] === 'soh') {\n const path = global.get(`pylontech${cmd[3]}`);\n if (path) {\n processData(\n /^(.{11})(.{11})(.{11})(.{9})/gm,\n dat => {\n return `${path}.battery${(parseInt(dat.Battery, 10) + 1).toString().padStart(2, '0')}.`;\n },\n (dat, key) => {\n return !['Battery', 'Voltage'].includes(key);\n }\n );\n }\n} else {\n const promptS = /(pylon>)(\\S+)/g;\n const cmd = promptS.exec(msg.payload);\n if (cmd && cmd[2] === 'pwr') {\n processData(\n /^(.{6})(.{7})(.{7})(.{7})(.{7})(.{7})(.{7})(.{7})(.{9})(.{9})(.{9})(.{9})(.{9})(.{21})(.{9})(.{9})?(.{8})?(.{7})?/gm,\n dat => {\n const path = global.get(`pylontech${dat.Power}`);\n return `${path}.power.`;\n },\n (dat, key) => {\n return !(dat['Base.St'] && dat['Base.St'] === 'Absent') && !['Power'].includes(key) && dat[key] && dat[key] !== '-';\n }\n );\n } else if (cmd && cmd[2] === 'log') {\n const row = /(.+\\S)\\s+:\\s(.*)/gm;\n let data = {};\n for (let match; (match = row.exec(msg.payload)) !== null;) {\n data[match[1].trim()] = match[2].trim();\n if (match[1].trim()===\"Info\") {\n node.status({ fill: 'green', shape: 'ring', text: JSON.stringify(data) });\n const path = `${baseTopic}log.${data[\"Index\"]}`;\n Object.keys(data).forEach(key => {\n if (key !== 'Index') {\n sendVal(key, `${path}.${key.replaceAll(' ', '_').toLocaleLowerCase()}`, data[key]);\n }\n });\n data={};\n }\n }\n }\n}\n","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":1260,"y":520,"wires":[["3f1a6c3e7e5f8e9e","ad7fbdde0a611199"]]},{"id":"dada1eb1e02d85c4","type":"change","z":"c8efb1fdd535ecb6","name":"info 2","rules":[{"t":"set","p":"payload","pt":"msg","to":"info 2","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":300,"wires":[["6e84de1dc0b0e89a"]]},{"id":"2ce08c297a547c15","type":"change","z":"c8efb1fdd535ecb6","name":"info 3","rules":[{"t":"set","p":"payload","pt":"msg","to":"info 3","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":360,"wires":[["6e84de1dc0b0e89a"]]},{"id":"5972560db0257e0e","type":"change","z":"c8efb1fdd535ecb6","name":"info 4","rules":[{"t":"set","p":"payload","pt":"msg","to":"info 4","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":420,"wires":[["6e84de1dc0b0e89a"]]},{"id":"763851bf660a0908","type":"change","z":"c8efb1fdd535ecb6","d":true,"name":"info 5","rules":[{"t":"set","p":"payload","pt":"msg","to":"info 5","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":480,"wires":[["6e84de1dc0b0e89a"]]},{"id":"50ea64dfbd16eede","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":360,"wires":[["219ecee40d790bac","2ce08c297a547c15"]]},{"id":"219ecee40d790bac","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":420,"wires":[["90c49403c185dd66","5972560db0257e0e"]]},{"id":"90c49403c185dd66","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":480,"wires":[["d52b8181e8fbe7f8","763851bf660a0908"]]},{"id":"d52b8181e8fbe7f8","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":580,"wires":[["52eb196c22e0a202","07e346121af39488"]]},{"id":"fd8f0b0577bbe0f7","type":"inject","z":"c8efb1fdd535ecb6","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"300","crontab":"","once":true,"onceDelay":"2","topic":"","payload":"","payloadType":"date","x":350,"y":240,"wires":[["f8eecab391c1e1c6","752d78cddb20a26e"]]},{"id":"6a56d5e5a4b9c9af","type":"change","z":"c8efb1fdd535ecb6","name":"soh 2","rules":[{"t":"set","p":"payload","pt":"msg","to":"soh 2","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":1080,"wires":[["6e84de1dc0b0e89a"]]},{"id":"d15ab215db481e94","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":1080,"wires":[["6a56d5e5a4b9c9af","7de93a9b8ccb4b7e"]]},{"id":"7d044e585b21424c","type":"change","z":"c8efb1fdd535ecb6","name":"soh 3","rules":[{"t":"set","p":"payload","pt":"msg","to":"soh 3","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":1140,"wires":[["6e84de1dc0b0e89a"]]},{"id":"7de93a9b8ccb4b7e","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":1140,"wires":[["7d044e585b21424c","918b1ccb36ed0b75"]]},{"id":"a1be957fc5c665c7","type":"change","z":"c8efb1fdd535ecb6","name":"soh 4","rules":[{"t":"set","p":"payload","pt":"msg","to":"soh 4","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":1200,"wires":[["6e84de1dc0b0e89a"]]},{"id":"918b1ccb36ed0b75","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":1200,"wires":[["a1be957fc5c665c7","e4353cc1a4d8cb1d"]]},{"id":"e4353cc1a4d8cb1d","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":1260,"wires":[["d57057a0ca734148","fb3545f07873e002"]]},{"id":"d57057a0ca734148","type":"change","z":"c8efb1fdd535ecb6","d":true,"name":"soh 5","rules":[{"t":"set","p":"payload","pt":"msg","to":"soh 5","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":1260,"wires":[["6e84de1dc0b0e89a"]]},{"id":"ad7fbdde0a611199","type":"ioBroker out","z":"c8efb1fdd535ecb6","name":"","topic":"","ack":"false","autoCreate":"true","stateName":"","role":"","payloadType":"","readonly":"false","stateUnit":"","stateMin":"","stateMax":"","x":1460,"y":500,"wires":[]},{"id":"07e346121af39488","type":"change","z":"c8efb1fdd535ecb6","name":"pwr","rules":[{"t":"set","p":"payload","pt":"msg","to":"pwr","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":580,"wires":[["6e84de1dc0b0e89a"]]},{"id":"f8eecab391c1e1c6","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":300,"wires":[["50ea64dfbd16eede","dada1eb1e02d85c4"]]},{"id":"e87a352e45a92263","type":"inject","z":"c8efb1fdd535ecb6","name":"Set V24","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"300","crontab":"","once":true,"onceDelay":0.1,"topic":"","payload":"[126,50,48,48,49,52,54,56,50,67,48,48,52,56,53,50,48,70,67,67,51,13]","payloadType":"bin","x":740,"y":60,"wires":[["0b2aaed380713036"]]},{"id":"710ca3ffc929f193","type":"inject","z":"c8efb1fdd535ecb6","name":"Init","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"[13,10]","payloadType":"bin","x":750,"y":120,"wires":[["6e84de1dc0b0e89a"]]},{"id":"0b2aaed380713036","type":"serial request","z":"c8efb1fdd535ecb6","d":true,"name":"","serial":"5a8b7bd0fbe83ab7","x":1040,"y":60,"wires":[["c395ddc57f9d7259"]]},{"id":"c395ddc57f9d7259","type":"debug","z":"c8efb1fdd535ecb6","name":"debug 11","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":1280,"y":60,"wires":[]},{"id":"b7cac5e8450c2fbf","type":"inject","z":"c8efb1fdd535ecb6","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"","payloadType":"date","x":570,"y":180,"wires":[["cc33e73ade7ee234"]]},{"id":"cc33e73ade7ee234","type":"function","z":"c8efb1fdd535ecb6","name":"set Time","func":"function f2 (val) {\n return val.toString().padStart(2, \"0\")\n}\n\nlet d = new Date()\nmsg.payload = `time ${f2(d.getFullYear()%100)} ${f2(d.getMonth()+1)} ${f2(d.getDate())} ${f2(d.getHours())} ${f2(d.getMinutes())} ${f2(d.getSeconds())}`\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":740,"y":180,"wires":[["6e84de1dc0b0e89a"]]},{"id":"c421bf7a32139ffe","type":"change","z":"c8efb1fdd535ecb6","name":"log","rules":[{"t":"set","p":"payload","pt":"msg","to":"\"log\\n\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":750,"y":1360,"wires":[["6e84de1dc0b0e89a"]]},{"id":"fb3545f07873e002","type":"delay","z":"c8efb1fdd535ecb6","name":"","pauseType":"delay","timeout":"2","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"x":560,"y":1360,"wires":[["c421bf7a32139ffe"]]},{"id":"29b3711f40c93afe","type":"change","z":"c8efb1fdd535ecb6","name":"help","rules":[{"t":"set","p":"payload","pt":"msg","to":"\"pwr\\n\"","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1210,"y":660,"wires":[["6e84de1dc0b0e89a"]]},{"id":"260891a4b0a2e888","type":"inject","z":"c8efb1fdd535ecb6","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":true,"onceDelay":"1","topic":"","payload":"","payloadType":"date","x":1030,"y":660,"wires":[["29b3711f40c93afe"]]},{"id":"232a266f73d872dc","type":"inject","z":"c8efb1fdd535ecb6","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":460,"y":1440,"wires":[["c421bf7a32139ffe"]]},{"id":"4a956651a40d8e44","type":"serial-port","serialport":"/dev/ttyUSB_pylontech","serialbaud":"115200","databits":"8","parity":"none","stopbits":"1","waitfor":"","dtr":"none","rts":"none","cts":"none","dsr":"none","newline":"$$$$","bin":"false","out":"char","addchar":"\\n","responsetimeout":"1000"},{"id":"5a8b7bd0fbe83ab7","type":"serial-port","d":true,"serialport":"/dev/ttyUSB_pylontech","serialbaud":"1200","databits":"8","parity":"none","stopbits":"1","waitfor":"","dtr":"none","rts":"none","cts":"none","dsr":"none","newline":"\\n","bin":"false","out":"char","addchar":"","responsetimeout":"10000"}]
last update 28.08.2023
Den Function Block noch einmal einzeln
const baseTopic = 'pylontech.0.'; function convert(str) { const number = /^(-|\+)?\d+$/g; const numberP = /^(-|\+)?\d+%$/g; const numbermAH = /^(-|\+)?\d+ mAH$/g; const numbermA = /^(-|\+)?\d+mA$/g; if (number.test(str)) { return { payload: parseInt(str, 10) }; } if (numberP.test(str)) { return { payload: parseInt(str, 10), unit: '%' }; } if (numbermAH.test(str)) { return { payload: parseInt(str, 10), unit: 'mAh' }; } if (numbermA.test(str)) { return { payload: parseInt(str, 10), unit: 'mA' }; } return { payload: str }; } function sendVal(name, topic, val) { const r = convert(val); const msg = { payload: r.payload, stateName: name, stateReadonly: true, stateType: typeof r.payload, topic, ack: true, }; if (r.unit) { msg.stateUnit = r.unit; } node.status({ fill: 'green', shape: 'ring', text: JSON.stringify(msg) }); node.send(msg); } function processData(filter, mkPath, ignoreKeys) { const head = filter.exec(msg.payload); if (head) { for (let i = 1; i < head.length; i++) { head[i] = head[i].trim(); } for (let match; (match = filter.exec(msg.payload)) !== null;) { const dat = {}; for (let i = 1; i < match.length; i++) { if (match[i]) { dat[head[i]] = match[i].trim(); } } const spath = mkPath(dat); Object.keys(dat).forEach(key => { if (ignoreKeys(dat, key)) { sendVal(key, spath + key.replaceAll('.', '').replaceAll(' ', '_').toLocaleLowerCase(), dat[key]); } }); } } } const prompt = /(pylon>)(\S+)\s(\d+)/g; const cmd = prompt.exec(msg.payload); if (cmd && cmd[2] === 'info') { let ok = false; const row = /(.+\S)\s+:\s(.*)/gm; const data = {}; for (let match; (match = row.exec(msg.payload)) !== null;) { data[match[1]] = match[2]; } if (data.Barcode) { ok = true; const path = baseTopic + data.Barcode.replaceAll(' ', '_'); global.set(`pylontech${cmd[3]}`, path); Object.keys(data).forEach(key => { if (key !== 'Barcode') { sendVal(key, `${path}.info.${key.replaceAll(' ', '_').toLocaleLowerCase()}`, data[key]); } }); sendVal('Barcode', `${baseTopic}info${cmd[3]}.barcode`, data.Barcode); } sendVal('Verbunden', `${baseTopic}info${cmd[3]}.connected`, ok); } else if (cmd && cmd[2] === 'bat') { const path = global.get(`pylontech${cmd[3]}`); if (path) { processData( /^(.{9})(.{9})(.{9})(.{9})(.{13})(.{13})(.{13})(.{13})(.{12})(.{14})(.{1,3})/gm, dat => { return `${path}.battery${(parseInt(dat.Battery, 10) + 1).toString().padStart(2, '0')}.`; }, (dat, key) => { return !['Battery'].includes(key); } ); } } else if (cmd && cmd[2] === 'soh') { const path = global.get(`pylontech${cmd[3]}`); if (path) { processData( /^(.{11})(.{11})(.{11})(.{9})/gm, dat => { return `${path}.battery${(parseInt(dat.Battery, 10) + 1).toString().padStart(2, '0')}.`; }, (dat, key) => { return !['Battery', 'Voltage'].includes(key); } ); } } else { const promptS = /(pylon>)(\S+)/g; const cmd = promptS.exec(msg.payload); if (cmd && cmd[2] === 'pwr') { processData( /^(.{6})(.{7})(.{7})(.{7})(.{7})(.{7})(.{7})(.{7})(.{9})(.{9})(.{9})(.{9})(.{9})(.{21})(.{9})(.{9})?(.{8})?(.{7})?/gm, dat => { const path = global.get(`pylontech${dat.Power}`); return `${path}.power.`; }, (dat, key) => { return !(dat['Base.St'] && dat['Base.St'] === 'Absent') && !['Power'].includes(key) && dat[key] && dat[key] !== '-'; } ); } else if (cmd && cmd[2] === 'log') { const row = /(.+\S)\s+:\s(.*)/gm; let data = {}; for (let match; (match = row.exec(msg.payload)) !== null;) { data[match[1].trim()] = match[2].trim(); if (match[1].trim()==="Info") { node.status({ fill: 'green', shape: 'ring', text: JSON.stringify(data) }); const path = `${baseTopic}log.${data["Index"]}`; Object.keys(data).forEach(key => { if (key !== 'Index') { sendVal(key, `${path}.${key.replaceAll(' ', '_').toLocaleLowerCase()}`, data[key]); } }); data={}; } } } }
last update 28.08.2023
-
@plchome-0 sagte in Pylontech mit Nodered in den ioBroker:
Theoretisch kann ich auch einen Adapter daraus bauen.
Daran wäre ich sehr interessiert.
Im Moment lese ich per MultiSIBControl aus (und API Aufruf zur Übertragung). Einfach weil das das erste war was ich ausprobiert habe und dann gleich funktionierte. -
@bananajoe said in Pylontech mit Nodered in den ioBroker:
MultiSIBControl
Habe mir MultiSIBControl auf meinem PC installiert. Wie stelle ich die Verbindung zur Batterie her, welchen Adapter brauche ich?
-
@plastomer gehört hier zwar nicht her aber:
- Entweder hat dein PC eine serielle Schnittstelle die du mit der RS232 Schnittstelle der ersten Pylontech Batterie verbindest
- Oder einen USB zu RS232 Adapter mit dem du das gleiche tust
- oder - und den habe ich gerade in Betrieb - einen USB zu RS485 Adapter den du mit der RS485 Schnittstelle verbindest.
In MultiSIBControl musst du im Setup nur den COM-Port einstellen (Siehst du im Gerätemanager) und schon läuft das Ding.
Die Daten lasse ich mir zu ioBroker senden per "Device Control". Wird hier: https://forum.iobroker.net/topic/48483/traking-von-pylontech-batterien/18?_=1692997875055 ab etwa dem verlinkten Post erklärt.
Mein USB2RS485 Adapter habe ich mit einer aktiven USB-Verlängerung (5m) angeschlossen, die Batterie (ja, noch Einzahl) steht im Nebenraum ein paar Meter weiter. MultiSIBControl läuft auf einem Windows-Rechner den ich als Server nutze (Backupziel, Videoüberwachung, Jumpserver) und der deshlab sowieso die ganze Zeit läuft.
Leider (naja) bekommt man so nur den Ladezustand, Spannung, Strom, Momentane Leistung und die Temperatur. Im Programm selbst kann man die Spannung und Temperatur jeder Zelle sehen. Ob man das unbedingt braucht?
-
Hier gibt es den Adapter:
-
@plchome-0 sagte in Pylontech mit Nodered in den ioBroker (geschlossen):
was ist das dennich mach das mal richtig