Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Hardware
    4. Pylontech mit Nodered in den ioBroker (geschlossen)

    NEWS

    • [erledigt] 15. 05. Wartungsarbeiten am ioBroker Forum

    • ioBroker goes Matter ... Matter Adapter in Stable

    • Monatsrückblick - April 2025

    Pylontech mit Nodered in den ioBroker (geschlossen)

    This topic has been deleted. Only users with topic management privileges can see it.
    • PLCHome 0
      PLCHome 0 Developer last edited by 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

      Homoran 1 Reply Last reply Reply Quote 1
      • BananaJoe
        BananaJoe Most Active last edited by

        @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 1 Reply Last reply Reply Quote 0
        • P
          plastomer @BananaJoe last edited by

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

          BananaJoe 1 Reply Last reply Reply Quote 0
          • BananaJoe
            BananaJoe Most Active @plastomer last edited by BananaJoe

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

            1 Reply Last reply Reply Quote 0
            • PLCHome 0
              PLCHome 0 Developer last edited by

              Hier gibt es den Adapter:

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

              1 Reply Last reply Reply Quote 0
              • Homoran
                Homoran Global Moderator Administrators @PLCHome 0 last edited by Homoran

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

                ich mach das mal richtig

                1 Reply Last reply Reply Quote 0
                • First post
                  Last post

                Support us

                ioBroker
                Community Adapters
                Donate

                562
                Online

                31.6k
                Users

                79.5k
                Topics

                1.3m
                Posts

                4
                6
                837
                Loading More Posts
                • Oldest to Newest
                • Newest to Oldest
                • Most Votes
                Reply
                • Reply as topic
                Log in to reply
                Community
                Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                The ioBroker Community 2014-2023
                logo