Hi,
I recently wrote, as a non-proffessional programmer, a function to manage the charging of my solar battery based on rules and time periodes defined in a Google Sheet (for simple, external, manual control).
The code works as intended, but I feel that this needs improvement for better readability and I hope for some ideas on how to improve it.
I do know about the "switch" statement, but I do not think it would make it better, given the nested layers.
Also I am aware, that I still use the "var" declaration, which is not ideal. It's replacement by "let" is work in progress.
I included the full code below but the basic scheme is this:
if (condition A) {
if (condition AA) {
if (condition AAA) {
if (condition AAAA) { do AAAA }
} else {
if (condition AAAB) { do AAAB }
}
if (condition AAB) {
if (condition AABA) { do AABA }
} else {
if (condition AABB) { do AABB }
}
} else {
if (condition AB) {
if (condition ABA){ do ABA }
} else {
if (condition ABB) { do ABB}
}
}
}
Full code including all comments:
//This routine checks every "Threshold" minutes
//if Google Sheet Status = "NotStop", do nothing
//if we are in off peak periode and if the State of Charge (SoC) is above "MinSoc"
//if below MinSoc during off peak periode, discharge is stopped
//if below CutOffSoC, the battery needs to stop discharging for battery protection
//if a car is charging during LowCost period, which battery stops to save energy for later in the morning when tariff is more expensive
//if the battery needs to be replenished from the grid (typically during winter)
//if on high PV forecast the battery shall only start charging around noon (prevent grid overloading)
const CutOffSoC = 6; //SoC in % when battery is considered empty (inverter has turned of battery)
const MinBatAvgPower = 1000; //Minimal power in Watt required to stop the battery charging on high PV forcast
const MinSoC = parseInt(global.get("GoogleInstructions")[1][1]); //to get MinSoc from Google Sheet
const Threshold = 5; //return only every 5min
const RemoteControl = global.get("GoogleInstructions")[0][0]; //to get operating instructions from Google Sheet
const ChargePower = parseInt(global.get("GoogleInstructions")[0][1]); //to get charging power from Google Sheet;
const OffPeakStart = new Date(global.get("GoogleInstructions")[2][1]); //ex. 21:00
const OffPeakEnd = new Date(global.get("GoogleInstructions")[3][1]); // this should be in line with the end time of EV charging to prevent, that battery will be depleted through EV charging
const LowCostStart = new Date(global.get("GoogleInstructions")[4][1]); // Start of periode when actual tariff is lower than normal off peak tariff
const LowCostEnd = new Date(global.get("GoogleInstructions")[5][1]); // End of periode when actual tariff is lower than normal off peak tariff
const ReplenishStartTime = new Date(global.get("GoogleInstructions")[6][1]); //ex. 03:00 because of low usage of grid
const ReplenishEndTime = new Date(global.get("GoogleInstructions")[7][1]); //ex. 05:00 because grid load starts here
const BatteryStopCharging = new Date(global.get("GoogleInstructions")[8][1]); //on high PV forecast stops battery charging until noon
const BatteryStartCharging = new Date(global.get("GoogleInstructions")[9][1]);//on high PV forecast starts battery charging at around noon
const AvgBatPower = flow.get("BatPowerAvg")[1]; //The average bat power over the last x measurements
const EVChargingState = new Object(global.get("EVCharging")); //current charging power of all charging points in an array
const TotalChargingPower = Object.values(EVChargingState).reduce((a, b) => a + b, 0); //Sum of charging power of all charging points
var ActionArray = [];
var SoC = parseFloat(msg.payload["SOC_real"]);
var ActualCapacity = parseInt(msg.payload["total_capacity"])/1000/3600 * parseFloat(msg.payload["state_of_health"])/100 * SoC/100; //computes the actual capacity based on max capacity, SoH and SoC in kWh
var BatPower = parseFloat(msg.payload["stat_batt_power"]);
var CurrentTime = new Date();
var TimerSec = parseInt(new Date().getSeconds());
msg.payload = "";
//Execute only at full minute and only if in Google Sheet OpMode is not in "NotStop" or "Laden" state
if ((6 > TimerSec || TimerSec > 58) && RemoteControl != "NotStop") {
//Execute only during offpeak hours to not interfear with PV battery charging
if (CurrentTime >= OffPeakStart && CurrentTime < OffPeakEnd) {
//if during replenish hours, SoC is below minimal value and battery is not already set to charge
//this basically should not happen during all the situations below, but the battery might already be on low SoC
//when any of the below phases start
if (SoC < MinSoC && ReplenishStartTime <= CurrentTime && CurrentTime < ReplenishEndTime) {
if (RemoteControl != "Laden") { //write action only if status is not already set to "Laden"
flow.set("BatCapacityBeforeCharging", ActualCapacity); //store current battery capacity to compute charged energy later on
msg.payload = "Laden"; //Charge battery
}
} else { //if we are out of replenish hours or SoC is higher than MinSoC
if (RemoteControl == "Laden") { //only update status, if battery has been set to charge before
//we disable the battery here as it will be enabled when peak hours start by "Check Soc" function
var ChargedFromGrid = (ActualCapacity - parseInt(flow.get("BatCapacityBeforeCharging"))); //compute energy charged from grid in kWh
global.set("BatChargedFromGrid", ChargedFromGrid);
msg.payload = "KeineRegelung" ;
}
}
//if EV's are charging during low cost hours and SoC is below MinSoC, turn off battery to save energy for
//later in the morning when tariffs raise again
if ((CurrentTime > LowCostStart && CurrentTime < LowCostEnd) && TotalChargingPower > 0 && SoC < MinSoC) {
if (BatPower < 0) { //prevent update when battery is already disabled (0 Amp) or
//charging from grid (positive Amp value)
msg.payload = "KeineRegelung";
}
} else { //if we are out of low cost period or SoC is higher than CutOffSoC or no car is charging
//only update status, if battery has been set to idle before and SoC is below CutOff SoC (lowest possible SoC)
if (SoC > CutOffSoC && RemoteControl != "Laden" && RemoteControl != "Entladen" && RemoteControl != "Automatik") {
msg.payload = "Automatik";
}
}
} else {
//if we are in a high PV forcast period and battery level is above minimum, we want to delay battery charging until around noon
if (SoC > MinSoC && CurrentTime > BatteryStopCharging && CurrentTime < BatteryStartCharging && AvgBatPower > MinBatAvgPower) {
if (RemoteControl != "KeineRegelung"){ //prevent constant writing of Mode, cannot be included in
//in the if statement above (toggling)
msg.payload = "KeineRegelung";
}
} else {
//if we are out of offpeak period, battery can be charged and provide no other manual command in Google Sheet(RemoteControl).
//This is a copy from above, just to make sure that the battery operation has been released when leaving offpeak period
if (SoC > CutOffSoC && RemoteControl != "Laden" && RemoteControl != "Entladen" && RemoteControl != "Automatik") { //only update status, if battery has been set to idle before
msg.payload = "Automatik";
}
}
}
}
if (msg.payload != ""){
return msg;
}
Many thanks for your improvement suggestions.
Best regards
Heinz