Hello,
I was trying to figure out a bit how to read the battery temperature of every single lithium ng battery in my system(4 total batteries). I’ve dug up a bit and found out that on the touchscreen you can look at the single individual battery info (Cell voltage/Cell temperature/entire battery temperature etc).
The thing is that with Venus OS 3.75 I can check the battery temperature of one single battery at a time, from what I read, this is a known limitation of the Victron NG system.
I’ve come up with this flow after some digging, but I am not 100% satisfied with it.
[
{
"id": "flow_battery_temp_status",
"type": "tab",
"label": "Battery Temp Status",
"disabled": false,
"info": "Cycles the Lynx Smart BMS NG battery selector every 15s, reads Battery/1/Temperature, and maintains a running status object with the last known temperature per battery."
},
{
"id": "inject_keepalive",
"type": "inject",
"z": "flow_battery_temp_status",
"name": "Keepalive (every 50s)",
"props": [
{
"p": "payload"
}
],
"repeat": "50",
"crontab": "",
"once": true,
"onceDelay": "1",
"topic": "",
"payload": "",
"payloadType": "str",
"x": 160,
"y": 80,
"wires": [
[
"mqtt_out_keepalive"
]
]
},
{
"id": "mqtt_out_keepalive",
"type": "mqtt out",
"z": "flow_battery_temp_status",
"name": "R/keepalive trigger",
"topic": "R/PASTE_PORTAL_ID_HERE/system/0/Serial",
"qos": "0",
"retain": "false",
"broker": "mqtt_broker_venus",
"x": 420,
"y": 80,
"wires": []
},
{
"id": "inject_cycle",
"type": "inject",
"z": "flow_battery_temp_status",
"name": "Cycle every 15s",
"props": [
{
"p": "payload"
}
],
"repeat": "15",
"crontab": "",
"once": true,
"onceDelay": "3",
"topic": "",
"payload": "",
"payloadType": "date",
"x": 150,
"y": 180,
"wires": [
[
"fn_cycle_index"
]
]
},
{
"id": "fn_cycle_index",
"type": "function",
"z": "flow_battery_temp_status",
"name": "Cycle index & build write payload",
"func": "let idx = flow.get('batteryCycleIndex') || 0;\nidx = (idx % 4) + 1;\nflow.set('batteryCycleIndex', idx);\nflow.set('batteryCycleIndexTimestamp', Date.now());\n\nmsg.payload = JSON.stringify({ value: idx });\nreturn msg;",
"outputs": 1,
"x": 430,
"y": 180,
"wires": [
[
"mqtt_out_select"
]
]
},
{
"id": "mqtt_out_select",
"type": "mqtt out",
"z": "flow_battery_temp_status",
"name": "Write battery selection",
"topic": "W/PASTE_PORTAL_ID_HERE/battery/0/Battery/Request/Id",
"qos": "0",
"retain": "false",
"broker": "mqtt_broker_venus",
"x": 690,
"y": 180,
"wires": []
},
{
"id": "mqtt_in_temp",
"type": "mqtt in",
"z": "flow_battery_temp_status",
"name": "Subscribe Battery/1/Temperature",
"topic": "N/PASTE_PORTAL_ID_HERE/battery/0/Battery/1/Temperature",
"qos": "0",
"datatype": "json",
"broker": "mqtt_broker_venus",
"inputs": 0,
"x": 190,
"y": 300,
"wires": [
[
"fn_update_status",
"4a991ec1eda9dad4"
]
]
},
{
"id": "fn_update_status",
"type": "function",
"z": "flow_battery_temp_status",
"name": "Update temp status (kept in memory)",
"func": "// Which physical battery this reading belongs to\nconst idx = flow.get('batteryCycleIndex') || 0;\nconst selectedAt = flow.get('batteryCycleIndexTimestamp') || 0;\nconst readAt = Date.now();\n\nconst currentTopic = Number(msg.topic.split(\"/\")[5])\n\nif(currentTopic===idx && msg.payload && msg.payload.value!==null){\n const temperature = Math.round(msg.payload.value*100)/100;\n \n // Load persistent status object (survives across messages/deploys if using file-based context store)\n let status = global.get('batteryTempStatus') || {\n battery1: null, battery2: null, battery3: null, battery4: null,\n battery1_updatedAt: null, battery2_updatedAt: null, battery3_updatedAt: null, battery4_updatedAt: null\n };\n \n if (idx >= 1 && idx <= 4 && temperature!=null) {\n status['battery' + idx] = temperature;\n status['battery' + idx + '_updatedAt'] = readAt;\n }\n \n global.set('batteryTempStatus', status);\n \n msg.payload = status;\n msg.staleness_ms = readAt - selectedAt;\n return msg;\n}",
"outputs": 1,
"timeout": "",
"noerr": 0,
"initialize": "",
"finalize": "",
"libs": [],
"x": 790,
"y": 300,
"wires": [
[
"status_out"
]
]
},
{
"id": "status_out",
"type": "debug",
"z": "flow_battery_temp_status",
"name": "Battery temp status",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "payload",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 1170,
"y": 300,
"wires": []
},
{
"id": "4a991ec1eda9dad4",
"type": "debug",
"z": "flow_battery_temp_status",
"name": "debug 7",
"active": false,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "false",
"statusVal": "",
"statusType": "auto",
"x": 580,
"y": 400,
"wires": []
},
{
"id": "b4572d77a300dacd",
"type": "mqtt in",
"z": "flow_battery_temp_status",
"name": "Subscribe Battery/2/Temperature",
"topic": "N/PASTE_PORTAL_ID_HERE/battery/0/Battery/2/Temperature",
"qos": "0",
"datatype": "json",
"broker": "mqtt_broker_venus",
"nl": false,
"rap": false,
"inputs": 0,
"x": 190,
"y": 360,
"wires": [
[
"4a991ec1eda9dad4",
"fn_update_status"
]
]
},
{
"id": "4a772fea3c386aad",
"type": "mqtt in",
"z": "flow_battery_temp_status",
"name": "Subscribe Battery/3/Temperature",
"topic": "N/PASTE_PORTAL_ID_HERE/battery/0/Battery/3/Temperature",
"qos": "0",
"datatype": "json",
"broker": "mqtt_broker_venus",
"nl": false,
"rap": false,
"inputs": 0,
"x": 190,
"y": 420,
"wires": [
[
"4a991ec1eda9dad4",
"fn_update_status"
]
]
},
{
"id": "28b0ce1007da3b05",
"type": "mqtt in",
"z": "flow_battery_temp_status",
"name": "Subscribe Battery/4/Temperature",
"topic": "N/PASTE_PORTAL_ID_HERE/battery/0/Battery/4/Temperature",
"qos": "0",
"datatype": "json",
"broker": "mqtt_broker_venus",
"nl": false,
"rap": false,
"inputs": 0,
"x": 190,
"y": 480,
"wires": [
[
"4a991ec1eda9dad4",
"fn_update_status"
]
]
},
{
"id": "mqtt_broker_venus",
"type": "mqtt-broker",
"name": "Venus MQTT",
"broker": "127.0.0.1",
"port": "1883",
"clientid": "",
"autoConnect": true,
"usetls": false,
"protocolVersion": "4",
"keepalive": "60",
"cleansession": true,
"autoUnsubscribe": true,
"birthQos": "0",
"willQos": "0"
}
]
I think this flow it is a bit messy, it gets the job done, but it is not really straightforward. Also I think it is kinda experimental.
Are there any plans to have a node that gets the battery temperature for every single battery in the system? Having to retrieve the information from one battery at a time is kinda limiting. Is there a problem with having the stream information from all the batteries at the same time?
I can imagine that with more batteries it could become challenging if the data cables cannot support that stream of data.
I also don’t know if this solution has any drawbacks regarding resources used to poll for information, not that I can think of.
Any feedback is appreciated! Thanks!