Skip to content
  • Home
  • Recent
  • Tags
  • 0 Unread 0
  • Categories
  • Unreplied
  • Popular
  • GitHub
  • Docu
  • Hilfe
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
ioBroker Logo

Community Forum

donate donate
  1. ioBroker Community Home
  2. Deutsch
  3. Hardware
  4. Pylontech mit Nodered in den ioBroker (geschlossen)

NEWS

  • Monatsrückblick Januar/Februar 2026 ist online!
    BluefoxB
    Bluefox
    16
    1
    306

  • Jahresrückblick 2025 – unser neuer Blogbeitrag ist online! ✨
    BluefoxB
    Bluefox
    17
    1
    4.7k

  • Neuer Blogbeitrag: Monatsrückblick - Dezember 2025 🎄
    BluefoxB
    Bluefox
    13
    1
    1.3k

Pylontech mit Nodered in den ioBroker (geschlossen)

Scheduled Pinned Locked Moved Hardware
6 Posts 4 Posters 1.4k Views 4 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • PLCHome 0P Offline
    PLCHome 0P Offline
    PLCHome 0
    Developer
    wrote on last edited by PLCHome 0
    #1

    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.

    ed487816-fea6-48c2-b82e-9d06264d74a8-image.png

    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

    HomoranH 1 Reply Last reply
    1
    • BananaJoeB Online
      BananaJoeB Online
      BananaJoe
      Most Active
      wrote on last edited by
      #2

      @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.

      ioBroker@Ubuntu 24.04 LTS (VMware) für: >260 Geräte, 5 Switche, 7 AP, 10 IP-Cam, 1 NAS 42TB, 1 ESXi 15TB, 4 Proxmox 1TB, 1 Hyper-V 48TB, 14 x Echo, 5x FireTV, 5 x Tablett/Handy VIS || >=160 Tasmota/Shelly || >=95 ZigBee || PV 8.1kW / Akku 14kWh || 2x USV APC 750W kaskadiert || Creality CR-10 SE 3D-Drucker

      P 1 Reply Last reply
      0
      • BananaJoeB BananaJoe

        @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.

        P Offline
        P Offline
        plastomer
        wrote on last edited by
        #3

        @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?

        BananaJoeB 1 Reply Last reply
        0
        • P plastomer

          @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?

          BananaJoeB Online
          BananaJoeB Online
          BananaJoe
          Most Active
          wrote on last edited by BananaJoe
          #4

          @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?

          ioBroker@Ubuntu 24.04 LTS (VMware) für: >260 Geräte, 5 Switche, 7 AP, 10 IP-Cam, 1 NAS 42TB, 1 ESXi 15TB, 4 Proxmox 1TB, 1 Hyper-V 48TB, 14 x Echo, 5x FireTV, 5 x Tablett/Handy VIS || >=160 Tasmota/Shelly || >=95 ZigBee || PV 8.1kW / Akku 14kWh || 2x USV APC 750W kaskadiert || Creality CR-10 SE 3D-Drucker

          1 Reply Last reply
          0
          • PLCHome 0P Offline
            PLCHome 0P Offline
            PLCHome 0
            Developer
            wrote on last edited by
            #5

            Hier gibt es den Adapter:

            https://forum.iobroker.net/topic/68707

            1 Reply Last reply
            0
            • PLCHome 0P PLCHome 0

              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.

              ed487816-fea6-48c2-b82e-9d06264d74a8-image.png

              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

              HomoranH Do not disturb
              HomoranH Do not disturb
              Homoran
              Global Moderator Administrators
              wrote on last edited by Homoran
              #6

              @plchome-0 sagte in Pylontech mit Nodered in den ioBroker (geschlossen):
              was ist das denn :-)

              ich mach das mal richtig

              kein Support per PN! - Fragen im Forum stellen -
              Benutzt das Voting rechts unten im Beitrag wenn er euch geholfen hat.
              Das Forum freut sich über eine Spende. Benutzt dazu den Spendenbutton im Header. Danke!
              der Installationsfixer: curl -fsL https://iobroker.net/fix.sh | bash -

              1 Reply Last reply
              0
              Reply
              • Reply as topic
              Log in to reply
              • Oldest to Newest
              • Newest to Oldest
              • Most Votes


              Support us

              ioBroker
              Community Adapters
              Donate

              653

              Online

              32.7k

              Users

              82.5k

              Topics

              1.3m

              Posts
              Community
              Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
              ioBroker Community 2014-2025
              logo
              • Login

              • Don't have an account? Register

              • Login or register to search.
              • First post
                Last post
              0
              • Home
              • Recent
              • Tags
              • Unread 0
              • Categories
              • Unreplied
              • Popular
              • GitHub
              • Docu
              • Hilfe