irekzielinski / Pylontech-Battery-Monitoring

Adding WiFi monitoring to US2000B and US2000C batteries.
135 stars 57 forks source link

read cells voltage #14

Open mihaigsm2003 opened 2 years ago

mihaigsm2003 commented 2 years ago

I need to read voltage from each cell and send via mqtt, how to add to code?

commander-bln commented 1 year ago

i also need the cells voltage, the scetch only use the "pwr" Data (works fine), what have to be change to also get all the data from "bat" ??

have anybody tried this ???

gitisgreat2023 commented 3 weeks ago

I implemented reading out the individual cell voltages and saving them to MQTT topics using Node Red.

Here's the code [ { "id": "210ecc232aa515d1", "type": "tab", "label": "Pylontech", "disabled": false, "info": "", "env": [] }, { "id": "1a2b3c4d5e6f7g8h", "type": "http request", "z": "210ecc232aa515d1", "name": "Get Battery Data", "method": "GET", "ret": "txt", "paytoqs": "ignore", "url": "http://pylon.fritz.box/req?code=bat", "tls": "", "persist": false, "proxy": "", "insecureHTTPParser": false, "authType": "", "senderr": false, "headers": [], "x": 890, "y": 540, "wires": [ [ "2b3c4d5e6f7g8h9i" ] ] }, { "id": "2b3c4d5e6f7g8h9i", "type": "function", "z": "210ecc232aa515d1", "name": "Process Battery Data", "func": "// Get the HTML input from the HTTP request\nlet htmlInput = msg.payload;\n\n// Use a regular expression to extract voltage values from the provided HTML\nlet voltageRegex = /\\d+\\s+(\\d+)\\s+-?\\d+\\s+\\d+\\s+\\w+\\s+\\w+\\s+\\w+\\s+\\w+\\s+\\d+%\\s+\\d+\\s+\\w+/g;\nlet voltages = [];\nlet labels = [];\nlet match;\n\n// Loop through all matches and extract the voltage (second column)\nlet index = 0;\nwhile ((match = voltageRegex.exec(htmlInput)) !== null) {\n if (match[1] !== '-') { // Check if the voltage is not absent\n voltages.push(parseInt(match[1]));\n node.warn(\"C\" + (index + 1) +' '+voltages[index]+'mV')\n labels.push('C' + (index + 1) + ' ' + voltages[index] + 'mV'); // Create labels for each cell\n //labels.push(C${index + 1}${voltages[index]}); // Create labels for each cell\n index++;\n }\n}\n\n\n\n// Calculate the minimum and maximum voltages\nlet minVoltage = Math.min(...voltages);\nlet maxVoltage = Math.max(...voltages);\n\n// Calculate the average voltage\nlet averageVoltage = voltages.reduce((sum, voltage) => sum + voltage, 0) / voltages.length;\n\n//node.warn(\"voltages: \" + voltages)\n\n// Prepare the title for the bar chart with dynamic values divided by 1000\nmsg.title =Avg${(averageVoltage / 1000).toFixed(2)}V,Min:${(minVoltage / 1000).toFixed(2)}V,Max:${(maxVoltage / 1000).toFixed(2)}V,delta:${((maxVoltage - minVoltage)).toFixed(0)}mV;\n\nmsg.payload = [{\n \"labels\": labels,\n \"data\": [voltages],\n \"series\": [msg.title] \n}];\n\n//node.warn(\"title: \" + msg.title)\n\nconst messages = {};\n// Loop through each line and extract the voltage\nfor (let i = 0; i < 15; i++) {\n messages[cellv_${i + 1}] = voltages[i];\n}\nmessages['cellv_min'] = minVoltage;\nmessages['cellv_max'] = maxVoltage;\nmessages['cellv_delta'] = maxVoltage - minVoltage;\nmsg.mqtt = [messages];\n\nmsg.mqtt = [...voltages,minVoltage,maxVoltage,maxVoltage - minVoltage];\n\n// Set dynamic ymin and ymax for auto-zooming\nmsg.ui_control = {\n ymin: minVoltage - 2, // Optional padding\n ymax: maxVoltage + 2, // Optional padding\n title: msg.title\n};\n\n// Return the modified message\nreturn msg;", "outputs": 1, "timeout": "", "noerr": 0, "initialize": "", "finalize": "", "libs": [], "x": 1140, "y": 540, "wires": [ [ "3c4d5e6f7g8h9i0j", "967347af5d917976", "86c188e82de695c4" ] ] }, { "id": "3c4d5e6f7g8h9i0j", "type": "ui_chart", "z": "210ecc232aa515d1", "name": "Voltage Bar Chart", "group": "55d02026703d8522", "order": 0, "width": 0, "height": 0, "label": "Battery Voltages", "chartType": "bar", "legend": true, "xformat": "auto", "interpolate": false, "nodata": "No data", "dot": true, "ymin": "", "ymax": "", "removeOlder": 1, "removeOlderPoints": 1, "cutout": "", "useOneColor": false, "useUTC": false, "colors": [ "#1f77b4", "#aec7e8", "#ff7f0e", "#2ca02c", "#98df8a", "#d62728", "#ff9896", "#9467bd", "#c5b0d5" ], "outputs": 1, "useDifferentColor": false, "className": "", "x": 1470, "y": 500, "wires": [ [] ] }, { "id": "9f8e7d6c5b4a3b2a", "type": "inject", "z": "210ecc232aa515d1", "name": "Start Flow", "props": [], "repeat": "10", "crontab": "", "once": false, "onceDelay": 0.1, "topic": "", "x": 650, "y": 540, "wires": [ [ "1a2b3c4d5e6f7g8h" ] ] }, { "id": "62e960ed8536a2df", "type": "mqtt out", "z": "210ecc232aa515d1", "name": "", "topic": "", "qos": "", "retain": "", "respTopic": "", "contentType": "", "userProps": "", "correl": "", "expiry": "", "broker": "aa30341bcc52e33c", "x": 1370, "y": 900, "wires": [] }, { "id": "967347af5d917976", "type": "change", "z": "210ecc232aa515d1", "name": "", "rules": [ { "t": "set", "p": "payload", "pt": "msg", "to": "mqtt", "tot": "msg" } ], "action": "", "property": "", "from": "", "to": "", "reg": false, "x": 1120, "y": 700, "wires": [ [ "3187e6c77ed69e70", "1daa4a98bcddd0a3" ] ] }, { "id": "3187e6c77ed69e70", "type": "debug", "z": "210ecc232aa515d1", "name": "debug 35", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1390, "y": 760, "wires": [] }, { "id": "86c188e82de695c4", "type": "debug", "z": "210ecc232aa515d1", "name": "debug 36", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1380, "y": 600, "wires": [] }, { "id": "1daa4a98bcddd0a3", "type": "buffer-parser", "z": "210ecc232aa515d1", "name": "", "data": "payload", "dataType": "msg", "specification": "spec", "specificationType": "ui", "items": [ { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c1", "offset": 0, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c2", "offset": 2, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c3", "offset": 4, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c4", "offset": 6, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c5", "offset": 8, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c6", "offset": 10, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c7", "offset": 12, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c8", "offset": 14, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c9", "offset": 16, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c10", "offset": 18, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c11", "offset": 20, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c12", "offset": 22, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c13", "offset": 24, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c14", "offset": 26, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/c15", "offset": 28, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/cmin", "offset": 30, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/cmax", "offset": 32, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" }, { "type": "int16be", "name": "mqtt.0.pylontech5000nr1/cell/cdelta", "offset": 34, "length": 1, "offsetbit": 0, "scale": "1", "mask": "" } ], "swap1": "", "swap2": "", "swap3": "", "swap1Type": "swap", "swap2Type": "swap", "swap3Type": "swap", "msgProperty": "payload", "msgPropertyType": "str", "resultType": "value", "resultTypeType": "return", "multipleResult": true, "fanOutMultipleResult": false, "setTopic": true, "outputs": 1, "x": 950, "y": 880, "wires": [ [ "b1925c8e8f021db2", "62e960ed8536a2df" ] ] }, { "id": "b1925c8e8f021db2", "type": "debug", "z": "210ecc232aa515d1", "name": "debug 37", "active": false, "tosidebar": true, "console": false, "tostatus": false, "complete": "false", "statusVal": "", "statusType": "auto", "x": 1220, "y": 1000, "wires": [] }, { "id": "55d02026703d8522", "type": "ui_group", "name": "Dynamic Power Limiter", "tab": "e5b1aeb5977e428a", "order": 3, "disp": true, "width": "6", "collapse": false, "className": "" }, { "id": "aa30341bcc52e33c", "type": "mqtt-broker", "name": "io", "broker": "localhost", "port": "1884", "clientid": "", "autoConnect": true, "usetls": false, "protocolVersion": "4", "keepalive": "60", "cleansession": true, "autoUnsubscribe": true, "birthTopic": "", "birthQos": "0", "birthPayload": "", "birthMsg": {}, "closeTopic": "", "closeQos": "0", "closePayload": "", "closeMsg": {}, "willTopic": "", "willQos": "0", "willPayload": "", "willMsg": {}, "userProps": "", "sessionExpiry": "" }, { "id": "e5b1aeb5977e428a", "type": "ui_tab", "name": "Home", "icon": "dashboard", "order": 1, "disabled": false, "hidden": false } ]