Skip to content
  • Home
  • Aktuell
  • Tags
  • 0 Ungelesen 0
  • Kategorien
  • Unreplied
  • Beliebt
  • 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

  • Standard: (Kein Skin)
  • Kein Skin
Einklappen
ioBroker Logo

Community Forum

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

NEWS

  • UPDATE 31.10.: Amazon Alexa - ioBroker Skill läuft aus ?
    apollon77A
    apollon77
    48
    3
    8.5k

  • Monatsrückblick – September 2025
    BluefoxB
    Bluefox
    13
    1
    2.1k

  • Neues Video "KI im Smart Home" - ioBroker plus n8n
    BluefoxB
    Bluefox
    16
    1
    2.7k

Pylontech mit Nodered in den ioBroker (geschlossen)

Geplant Angeheftet Gesperrt Verschoben Hardware
6 Beiträge 4 Kommentatoren 1.2k Aufrufe 4 Watching
  • Älteste zuerst
  • Neuste zuerst
  • Meiste Stimmen
Antworten
  • In einem neuen Thema antworten
Anmelden zum Antworten
Dieses Thema wurde gelöscht. Nur Nutzer mit entsprechenden Rechten können es sehen.
  • PLCHome 0P Offline
    PLCHome 0P Offline
    PLCHome 0
    Developer
    schrieb am zuletzt editiert von 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 Antwort Letzte Antwort
    1
    • BananaJoeB Online
      BananaJoeB Online
      BananaJoe
      Most Active
      schrieb am zuletzt editiert von
      #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, 9 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 750W kaskadiert || Creality CR-10 SE 3D-Drucker

      P 1 Antwort Letzte Antwort
      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
        schrieb am zuletzt editiert von
        #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 Antwort Letzte Antwort
        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
          schrieb am zuletzt editiert von 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, 9 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 750W kaskadiert || Creality CR-10 SE 3D-Drucker

          1 Antwort Letzte Antwort
          0
          • PLCHome 0P Offline
            PLCHome 0P Offline
            PLCHome 0
            Developer
            schrieb am zuletzt editiert von
            #5

            Hier gibt es den Adapter:

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

            1 Antwort Letzte Antwort
            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 Nicht stören
              HomoranH Nicht stören
              Homoran
              Global Moderator Administrators
              schrieb am zuletzt editiert von 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 - es gibt fast nichts, was nicht auch für andere interessant ist.

              Benutzt das Voting rechts unten im Beitrag wenn er euch geholfen hat.

              der Installationsfixer: curl -fsL https://iobroker.net/fix.sh | bash -

              1 Antwort Letzte Antwort
              0
              Antworten
              • In einem neuen Thema antworten
              Anmelden zum Antworten
              • Älteste zuerst
              • Neuste zuerst
              • Meiste Stimmen


              Support us

              ioBroker
              Community Adapters
              Donate

              460

              Online

              32.4k

              Benutzer

              81.5k

              Themen

              1.3m

              Beiträge
              Community
              Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen | Einwilligungseinstellungen
              ioBroker Community 2014-2025
              logo
              • Anmelden

              • Du hast noch kein Konto? Registrieren

              • Anmelden oder registrieren, um zu suchen
              • Erster Beitrag
                Letzter Beitrag
              0
              • Home
              • Aktuell
              • Tags
              • Ungelesen 0
              • Kategorien
              • Unreplied
              • Beliebt
              • GitHub
              • Docu
              • Hilfe