It does make quite a bit of sense and as per usual there are more than one way to do this.
If you would like to use the batteries only as a backup and not for energy saving a another way would be to limit the battery discharge when on grid to something like 95% . That way , if you have a bad weather day , batteries wont get discharged more than that amount as long as the grid is available.
Then use the Solar Output and Battery watts to adjust the ESS you could add a factor in to ensure that the batteries never discharges during daytime. I use Node Red , located on the Venus GX and the script has been running for almost a year and half with no issues.
One advantage is that should the script go belly up you will still have the Min Soc setting to “protect” the batteries.
The other is that you do not need time as the panels output determines the cutoff and startup time.
[{“id”:“eeffa000.c4b4e”,“type”:“victron-input-battery”,“z”:“9b1de2c7.ff15”,“service”:“com.victronenergy.battery.ttyO4”,“path”:“/Dc/0/Power”,“serviceObj”:{“service”:“com.victronenergy.battery.ttyO4”,“name”:“BMV-702”,“paths”:[{“path”:“/Dc/0/Voltage”,“type”:“float”,“name”:“Battery voltage (V)”},{“path”:“/Dc/1/Voltage”,“type”:“float”,“name”:“Starter battery voltage (V)”},{“path”:“/Dc/0/Current”,“type”:“float”,“name”:“Current (A)”},{“path”:“/ConsumedAmphours”,“type”:“float”,“name”:“Consumed Amphours (Ah)”},{“path”:“/Soc”,“type”:“float”,“name”:“State of charge (%)”},{“path”:“/TimeToGo”,“type”:“float”,“name”:“Time to go (h)”},{“path”:“/Relay/0/State”,“type”:“enum”,“name”:“Relay status”,“enum”:{“0”:“Open”,“1”:“Closed”}},{“path”:“/Dc/0/Temperature”,“type”:“float”,“name”:“Battery temperature (C)”},{“path”:“/Dc/0/MidVoltage”,“type”:“float”,“name”:“Mid-point voltage of the battery bank (V)”},{“path”:“/Dc/0/MidVoltageDeviation”,“type”:“float”,“name”:“Mid-point deviation of the battery bank (%)”},{“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/LowStarterVoltage”,“type”:“enum”,“name”:“Low starter-voltage alarm”,“enum”:{“0”:“No alarm”,“2”:“Alarm”}},{“path”:“/Alarms/HighStarterVoltage”,“type”:“enum”,“name”:“High starter-voltage alarm”,“enum”:{“0”:“No alarm”,“2”:“Alarm”}},{“path”:“/Alarms/LowSoc”,“type”:“enum”,“name”:“Low state-of-charge 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”:“/Alarms/MidVoltage”,“type”:“enum”,“name”:“Mid-voltage alarm”,“enum”:{“0”:“No alarm”,“2”:“Alarm”}},{“path”:“/Dc/0/Power”,“type”:“float”,“name”:“Battery power (W)”}]},“pathObj”:{“path”:“/Dc/0/Power”,“type”:“float”,“name”:“Battery power (W)”},“name”:“BMV Watts”,“x”:100,“y”:380,“wires”:[[“7275330e.fb869c”,“ff2f0f32.e74ed”]]},{“id”:“7275330e.fb869c”,“type”:“delay”,“z”:“9b1de2c7.ff15”,“name”:“”,“pauseType”:“rate”,“timeout”:“1”,“timeoutUnits”:“seconds”,“rate”:“1”,“nbRateUnits”:“15”,“rateUnits”:“second”,“randomFirst”:“1”,“randomLast”:“5”,“randomUnits”:“seconds”,“drop”:true,“x”:190,“y”:430,“wires”:[[“1df46a74.dab466”]]},{“id”:“1df46a74.dab466”,“type”:“function”,“z”:“9b1de2c7.ff15”,“name”:“Calculate”,“func”:“b = msg.payload.toFixed(0)\n\nvar batw = b1 ;\nvar sol = flow.get("solarw")1\nvar maxstate = flow.get("maxstate"); // Max Dischage Value\nvar maxstatesw = "ON";\n\n\nminEss = 250 // Min Battery Discharge value for ESS \nMaxBattDc = -250 // Battery Discharge value before Activation \nfactor = 1 // Factor by with the ESS vaule is set - this is to ensure that the pannels match the dischrge\nMaxBattCh = 150 // Battery is charging and can adjust the Max discharge \n\nif (sol <= minEss){\nnewMax = minEss; \n}else{\nnewMax = (Math.ceil(sol / 10) * 10) ; //-(solfactor) - round to 10\n}\n\n\n// Debug Info\nif (maxstatesw == "ON"){\ncolor = "green" \n}else if (maxstatesw === "OFF"){\ncolor = "red" \n}\n\n\n\n\nnode.status({fill:color,shape:"ring",text:"Bw:"+batw+" Ess:"+maxstate + " Sol:"+sol}); \n\n if(maxstatesw=="ON"){ // Check if Switch is ON\n if (batw <= MaxBattDc && maxstate > minEss || maxstate < minEss ) { // Battery is Discharging and ESS is still to high\n msg.payload = (newMax1).toFixed(0)1;\n return msg; \n } else if (batw >= MaxBattCh ){ // Solar is enough to sustain the curr house load load\n msg.payload = (newMax1).toFixed(0)*1;\n return msg; \n }\n \n }\n”,“outputs”:1,“noerr”:0,“initialize”:“”,“finalize”:“”,“x”:350,“y”:430,“wires”:[[“9f11fe50.5c2c4”]]},{“id”:“9f11fe50.5c2c4”,“type”:“rbe”,“z”:“9b1de2c7.ff15”,“name”:“”,“func”:“rbe”,“gap”:“”,“start”:“”,“inout”:“out”,“property”:“payload”,“x”:510,“y”:430,“wires”:[[“c00e69c7.7a1058”]]},{“id”:“c00e69c7.7a1058”,“type”:“victron-output-ess”,“z”:“9b1de2c7.ff15”,“service”:“com.victronenergy.settings”,“path”:“/Settings/CGwacs/MaxDischargePower”,“serviceObj”:{“service”:“com.victronenergy.settings”,“name”:“ESS System Settings”,“paths”:[{“path”:“/Settings/CGwacs/AcPowerSetPoint”,“type”:“integer”,“name”:“Grid set-point (W)”,“writable”:true},{“path”:“/Settings/CGwacs/BatteryLife/MinimumSocLimit”,“type”:“integer”,“name”:“Minimum Discharge SOC (%)”,“writable”:true},{“path”:“/Settings/CGwacs/BatteryLife/State”,“type”:“enum”,“name”:“ESS state”,“enum”:{“1”:“BatteryLife enabled (GUI controlled)”,“2”:“Optimized Mode /w BatteryLife: self consumption”,“3”:“Optimized Mode /w BatteryLife: self consumption, SoC exceeds 85%”,“4”:“Optimized Mode /w BatteryLife: self consumption, SoC at 100%”,“5”:“Optimized Mode /w BatteryLife: SoC below dynamic SoC limit”,“6”:“Optimized Mode /w BatteryLife: SoC has been below SoC limit for more than 24 hours. Charging the battery (5A)”,“7”:“Optimized Mode /w BatteryLife: Inverter/Charger is in sustain mode”,“8”:“Optimized Mode /w BatteryLife: recharging, SoC dropped by 5% or more below the minimum SoC”,“9”:“‘Keep batteries charged’ mode is enabled”,“10”:“Optimized mode w/o BatteryLife: self consumption, SoC at or above minimum SoC”,“11”:“Optimized mode w/o BatteryLife: self consumption, SoC is below minimum SoC”,“12”:“Optimized mode w/o BatteryLife: recharging, SoC dropped by 5% or more below minimum SoC”},“writable”:true},{“path”:“/Settings/CGwacs/Hub4Mode”,“type”:“enum”,“name”:“ESS mode”,“enum”:{“1”:“Optimized mode or ‘keep batteries charged’ and phase compensation enabled”,“2”:“Optimized mode or ‘keep batteries charged’ and phase compensation disabled”,“3”:“External control”},“writable”:true},{“path”:“/Settings/CGwacs/MaxDischargePower”,“type”:“integer”,“name”:“Max inverter power (W)”,“writable”:true},{“path”:“/Settings/CGwacs/OvervoltageFeedIn”,“type”:“enum”,“name”:“Feed-in excess solar charger power”,“enum”:{“0”:“No”,“1”:“Yes”},“writable”:true},{“path”:“/Settings/CGwacs/PreventFeedback”,“type”:“enum”,“name”:“PV Inverter zero feed-in (on/off)”,“enum”:{“0”:“No”,“1”:“Yes”},“writable”:true},{“path”:“/Settings/SystemSetup/MaxChargeCurrent”,“type”:“float”,“name”:“Charge current limit (A)”,“writable”:true}]},“pathObj”:{“path”:“/Settings/CGwacs/MaxDischargePower”,“type”:“integer”,“name”:“Max inverter power (W)”,“writable”:true},“initial”:“”,“name”:“Max Power”,“x”:690,“y”:430,“wires”:}]