question

alda avatar image
alda asked

How to calculate battery life with node red

I want calculate a battery life from actual (or average consumption after 1minute) and actual SoC.

But not sure how to calculate with data from two sources which are not sync.

Thank you for any idea and help


Node-RED
2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

4 Answers
smart-home avatar image
smart-home answered ·

I do just that......
I take the current battery SOC and subtract the set minimum SOC and then divide that by the current power (discharging) to arrive at a time the battery is estimated to be flat.
Similarly, you can calculate an estimate for time fully charged.
There was a useful date/time formatter node to add to the pallet to calculate the times. (node-red-contrib-moment2)


Try pasting this to save you some work....
(You probably don't need global variables that I have used in some cases.)


[{"id":"441c6c1cce05ddce","type":"switch","z":"bf1e31f330e69c5c","name":"","property":"payload","propertyType":"msg","rules":[{"t":"lt","v":"-100","vt":"num"},{"t":"btwn","v":"-100","vt":"num","v2":"10","v2t":"num"},{"t":"gt","v":"10","vt":"num"}],"checkall":"true","repair":false,"outputs":3,"x":965,"y":960,"wires":[["d1d3b8bce39a0e3c"],["772d6aa399d12bdb"],["87a61f5ca9c470e2"]]},{"id":"60643f4bafcb4690","type":"change","z":"bf1e31f330e69c5c","name":"< -100 (Discharging)","rules":[{"t":"set","p":"flat-time-mins","pt":"flow","to":"$round(($globalContext('battery-SOC')-$globalContext('battery-min'))*40*60/$flowContext('battery-power'),0)*-1","tot":"jsonata"},{"t":"set","p":"payload","pt":"msg","to":"$millis()+($flowContext('flat-time-mins')*60*1000)","tot":"jsonata"},{"t":"set","p":"copy-to-display-directly--not-used","pt":"msg","to":"\"<font color=yellow>Battery flat around \"&$fromMillis($millis()+($flowContext('Time-estimate')*60*1000),' [h#1]:[m01] [P]', '+1000')","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1330,"y":915,"wires":[["862d3e2030d077a9"]]},{"id":"fb9f4fc8b608b486","type":"change","z":"bf1e31f330e69c5c","name":"> 10 (Charging)","rules":[{"t":"set","p":"charge-time-mins","pt":"flow","to":"$round((100-$globalContext('battery-SOC'))*40*60/$flowContext('battery-power'),0)","tot":"jsonata"},{"t":"set","p":"payload","pt":"msg","to":"$millis()+($flowContext('charge-time-mins')*60*1000)","tot":"jsonata"}],"action":"","property":"","from":"","to":"","reg":false,"x":1310,"y":1005,"wires":[["23169a335dabda99"]]},{"id":"09c287effaba2b7e","type":"change","z":"bf1e31f330e69c5c","name":"-100 to 10 W (Idle)","rules":[{"t":"set","p":"payload","pt":"msg","to":"<font color=grey>=== Battery Idle ===","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1320,"y":960,"wires":[["70a751144c40ec0c"]]},{"id":"f2bf967b830e18a7","type":"StatusUltimate","z":"bf1e31f330e69c5c","name":"Status","property":"payload","x":1145,"y":840,"wires":[["a8d7f1c490d6db89"]]},{"id":"a8d7f1c490d6db89","type":"change","z":"bf1e31f330e69c5c","name":"set flow.battery-power","rules":[{"t":"set","p":"battery-power","pt":"flow","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1330,"y":840,"wires":[[]]},{"id":"d1d3b8bce39a0e3c","type":"StatusUltimate","z":"bf1e31f330e69c5c","name":"Status","property":"payload","x":1145,"y":915,"wires":[["60643f4bafcb4690"]]},{"id":"772d6aa399d12bdb","type":"StatusUltimate","z":"bf1e31f330e69c5c","name":"Status","property":"payload","x":1145,"y":960,"wires":[["09c287effaba2b7e"]]},{"id":"87a61f5ca9c470e2","type":"StatusUltimate","z":"bf1e31f330e69c5c","name":"Status","property":"payload","x":1145,"y":1005,"wires":[["fb9f4fc8b608b486"]]},{"id":"862d3e2030d077a9","type":"moment","z":"bf1e31f330e69c5c","name":"","topic":"","input":"","inputType":"msg","inTz":"Africa/Abidjan","adjAmount":0,"adjType":"days","adjDir":"add","format":"[<font color=yellow>Battery flat around ] h:mm a (ddd)","locale":"POSIX","output":"","outputType":"msg","outTz":"Australia/Melbourne","x":1600,"y":915,"wires":[["70a751144c40ec0c","5a6703fd90ea2abf"]]},{"id":"23169a335dabda99","type":"moment","z":"bf1e31f330e69c5c","name":"","topic":"","input":"","inputType":"msg","inTz":"Africa/Abidjan","adjAmount":0,"adjType":"days","adjDir":"add","format":"[<font color=green>Battery full around ] h:mm a (ddd)","locale":"POSIX","output":"","outputType":"msg","outTz":"Australia/Melbourne","x":1600,"y":1005,"wires":[["70a751144c40ec0c","19b1c41801612f0e"]]},{"id":"239ce9df032664ff","type":"smooth","z":"bf1e31f330e69c5c","name":"~ 15 sec average","property":"payload","action":"mean","count":"11","round":"0","mult":"single","reduce":true,"x":750,"y":840,"wires":[["441c6c1cce05ddce","f2bf967b830e18a7"]]},{"id":"72545a6ec8a2a8c5","type":"StatusUltimate","z":"bf1e31f330e69c5c","name":"Status","property":"payload","x":575,"y":840,"wires":[["239ce9df032664ff"]]},{"id":"ad02e7180b796eb7","type":"victron-input-battery","z":"bf1e31f330e69c5c","service":"com.victronenergy.battery.socketcan_can1","path":"/Soc","serviceObj":{"service":"com.victronenergy.battery.socketcan_can1","name":"BYD Premium LV battery","paths":[{"path":"/Dc/0/Voltage","type":"float","name":"Battery voltage (V)"},{"path":"/Dc/0/Current","type":"float","name":"Current (A)"},{"path":"/Soc","type":"float","name":"State of charge (%)"},{"path":"/Dc/0/Temperature","type":"float","name":"Battery temperature (C)"},{"path":"/Alarms/LowVoltage","type":"enum","name":"Low voltage alarm","enum":{"0":"No alarm","2":"Alarm"}},{"path":"/Alarms/HighVoltage","type":"enum","name":"High voltage alarm","enum":{"0":"No alarm","2":"Alarm"}},{"path":"/Alarms/LowTemperature","type":"enum","name":"Low battery temperature alarm","enum":{"0":"No alarm","2":"Alarm"}},{"path":"/Alarms/HighTemperature","type":"enum","name":"High battery temperature alarm","enum":{"0":"No alarm","2":"Alarm"}},{"path":"/Soh","type":"float","name":"State of health (%)"},{"path":"/Info/MaxChargeVoltage","type":"float","name":"CVL - Charge Voltage Limit (V)"},{"path":"/Info/MaxChargeCurrent","type":"float","name":"CCL - Charge Current Limit (A)"},{"path":"/Info/MaxDischargeCurrent","type":"float","name":"DCL - Discharge Current Limit (A)"},{"path":"/Alarms/CellImbalance","type":"enum","name":"Cell Imbalance alarm","enum":{"0":"No alarm","1":"Warning","2":"Alarm"}},{"path":"/Alarms/HighChargeCurrent","type":"enum","name":"High charge current alarm","enum":{"0":"No alarm","1":"Warning","2":"Alarm"}},{"path":"/Alarms/HighDischargeCurrent","type":"enum","name":"High discharge current alarm","enum":{"0":"No alarm","1":"Warning","2":"Alarm"}},{"path":"/Alarms/InternalFailure","type":"enum","name":"Internal error alarm","enum":{"0":"No alarm","1":"Warning","2":"Alarm"}},{"path":"/Alarms/HighChargeTemperature","type":"enum","name":"High charge temperature alarm","enum":{"0":"No alarm","1":"Warning","2":"Alarm"}},{"path":"/Alarms/LowChargeTemperature","type":"enum","name":"Low charge temperature alarm","enum":{"0":"No alarm","1":"Warning","2":"Alarm"}},{"path":"/Dc/0/Power","type":"float","name":"Battery power (W)"}]},"pathObj":{"path":"/Soc","type":"float","name":"State of charge (%)"},"name":"","x":170,"y":705,"wires":[["09dc839d87f22b25"]]},{"id":"09dc839d87f22b25","type":"rbe","z":"bf1e31f330e69c5c","name":"Block unless value changes","func":"rbe","gap":"","start":"","inout":"out","septopics":false,"property":"payload","topi":"topic","x":540,"y":705,"wires":[["0e5468367619f8e3"]]},{"id":"0e5468367619f8e3","type":"StatusUltimate","z":"bf1e31f330e69c5c","name":"Status","property":"payload","x":845,"y":705,"wires":[["b903bc215cbd7a69"]]},{"id":"b903bc215cbd7a69","type":"change","z":"bf1e31f330e69c5c","name":"set global.battery-SOC","rules":[{"t":"set","p":"battery-SOC","pt":"global","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":1060,"y":705,"wires":[["c4bad64373a5433f"]]},{"id":"c4bad64373a5433f","type":"change","z":"bf1e31f330e69c5c","name":"set topic: Battery SOC %","rules":[{"t":"set","p":"topic","pt":"msg","to":"Battery SOC %","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":1310,"y":705,"wires":[[]]},{"id":"0a90f2a7c0f5e204","type":"victron-input-battery","z":"bf1e31f330e69c5c","service":"com.victronenergy.battery.socketcan_can1","path":"/Dc/0/Power","serviceObj":{"service":"com.victronenergy.battery.socketcan_can1","name":"BYD Premium LV battery","paths":[{"path":"/Dc/0/Voltage","type":"float","name":"Battery voltage (V)"},{"path":"/Dc/0/Current","type":"float","name":"Current (A)"},{"path":"/Soc","type":"float","name":"State of charge (%)"},{"path":"/Dc/0/Temperature","type":"float","name":"Battery temperature (C)"},{"path":"/Alarms/LowVoltage","type":"enum","name":"Low voltage alarm","enum":{"0":"No alarm","2":"Alarm"}},{"path":"/Alarms/HighVoltage","type":"enum","name":"High voltage alarm","enum":{"0":"No alarm","2":"Alarm"}},{"path":"/Alarms/LowTemperature","type":"enum","name":"Low battery temperature alarm","enum":{"0":"No alarm","2":"Alarm"}},{"path":"/Alarms/HighTemperature","type":"enum","name":"High battery temperature alarm","enum":{"0":"No alarm","2":"Alarm"}},{"path":"/Soh","type":"float","name":"State of health (%)"},{"path":"/Info/MaxChargeVoltage","type":"float","name":"CVL - Charge Voltage Limit (V)"},{"path":"/Info/MaxChargeCurrent","type":"float","name":"CCL - Charge Current Limit (A)"},{"path":"/Info/MaxDischargeCurrent","type":"float","name":"DCL - Discharge Current Limit (A)"},{"path":"/Alarms/CellImbalance","type":"enum","name":"Cell Imbalance alarm","enum":{"0":"No alarm","1":"Warning","2":"Alarm"}},{"path":"/Alarms/HighChargeCurrent","type":"enum","name":"High charge current alarm","enum":{"0":"No alarm","1":"Warning","2":"Alarm"}},{"path":"/Alarms/HighDischargeCurrent","type":"enum","name":"High discharge current alarm","enum":{"0":"No alarm","1":"Warning","2":"Alarm"}},{"path":"/Alarms/InternalFailure","type":"enum","name":"Internal error alarm","enum":{"0":"No alarm","1":"Warning","2":"Alarm"}},{"path":"/Alarms/HighChargeTemperature","type":"enum","name":"High charge temperature alarm","enum":{"0":"No alarm","1":"Warning","2":"Alarm"}},{"path":"/Alarms/LowChargeTemperature","type":"enum","name":"Low charge temperature alarm","enum":{"0":"No alarm","1":"Warning","2":"Alarm"}},{"path":"/Dc/0/Power","type":"float","name":"Battery power (W)"}]},"pathObj":{"path":"/Dc/0/Power","type":"float","name":"Battery power (W)"},"name":"","x":170,"y":840,"wires":[["72545a6ec8a2a8c5"]]},{"id":"70a751144c40ec0c","type":"ui_text","z":"bf1e31f330e69c5c","group":"bba5452f.7c7ed","order":11,"width":7,"height":1,"name":"Time till flat or charged","label":"","format":"{ {msg.payload}}","layout":"row-center","x":1870,"y":960,"wires":[]},{"id":"5a6703fd90ea2abf","type":"StatusUltimate","z":"bf1e31f330e69c5c","name":"Status","property":"payload","x":1865,"y":915,"wires":[[]]},{"id":"19b1c41801612f0e","type":"StatusUltimate","z":"bf1e31f330e69c5c","name":"Status","property":"payload","x":1865,"y":1005,"wires":[[]]},{"id":"bba5452f.7c7ed","type":"ui_group","name":"Battery","tab":"263714fe.0cdaa4","order":5,"disp":false,"width":"15","collapse":false},{"id":"263714fe.0cdaa4","type":"ui_tab","name":"Solar Status","icon":"battery_charging_full","order":1,"disabled":false,"hidden":false}]






2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

alan-falck avatar image
alan-falck answered ·

Great project, following with interest, happy to help with any testing ... thanks

2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

Dierk Grossfeld avatar image
Dierk Grossfeld answered ·

Was exactly one of the first things I did for the liontron batteries that do not expose this values via can bus.


At first I set the soc as a global variable out of a

Venus System - Battery State of Charge (%)

Node with a function node with code:


global.set('soc', msg.payload)
return msg;


Then I use as input the

Venus System - Battery Power (W)

Node and a function node with this inside:


soc=global.get('soc');
watts=msg.payload;
capacity=51.2*(105+104+102+104); # Nominal Power of the Liontron Multiplied by the Ah sum of Capacity of the 4 Modules gives you the capacity in Watt Hours.
remain=soc/100*capacity;
rest=capacity-remain;

if (watts !=0 ) {
    if (watts <0) {
        timetogo=remain/watts*-3600;
        left=remain;
    } else {
        timetogo=rest/watts*3600;
        left=rest;
    }
    
} else {
    timetogo=864000;
    left=rest;
}

// Hours
var Hours = ((timetogo)/3600);
Hours = Math.floor(Hours);

// Minutes
var Minutes = (timetogo-(Hours*3600))/60;
Minutes = Math.floor(Minutes);

// Concatenate
var Time = ('0' +Hours).slice(-2)+':'+('0' +Minutes).slice(-2);

global.set('timetogo', timetogo);
global.set('watts', watts);

msg.payload=Time;
msg.soc=soc;
msg.watts=watts;
msg.capacity=capacity;
msg.remain=remain;
msg.rest=rest;
msg.timetogo=timetogo;
msg.hours=Hours;
msg.minutes=Minutes;
msg.left=left;

return msg;


As output you then have a msg object that has almost all necessary inside.

If you also want to subtract the set minimum soc to keep you can pick that also up by setting it as a global var and use it then by loading it into the function.


Hopefully that helps.

Kind regards,

Dierk

2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.

andy156 avatar image
andy156 answered ·

It's worth taking into account the efficiency of the inverter. I have a function that returns the 'assumed' efficiency based on the power. For my quattro 10k . At 1kW its maximum of 95% and then it linearly decays to 90% or less ( I forget the exact figures) at 8kW. Multiply the time to go by the calculated efficiency.

2 |3000

Up to 8 attachments (including images) can be used with a maximum of 190.8 MiB each and 286.6 MiB total.