diff --git a/.github/workflows/compile-all-batteries.yml b/.github/workflows/compile-all-batteries.yml index c0c1493e..7e2febc5 100644 --- a/.github/workflows/compile-all-batteries.yml +++ b/.github/workflows/compile-all-batteries.yml @@ -49,6 +49,7 @@ jobs: # - LUNA2000_MODBUS # - PYLON_CAN # - SMA_CAN +# - SMA_TRIPOWER_CAN # - SOFAR_CAN # - SOLAX_CAN diff --git a/.github/workflows/compile-all-combinations.yml b/.github/workflows/compile-all-combinations.yml index 7a507f58..e2c24be9 100644 --- a/.github/workflows/compile-all-combinations.yml +++ b/.github/workflows/compile-all-combinations.yml @@ -52,8 +52,10 @@ jobs: - LUNA2000_MODBUS - PYLON_CAN - SMA_CAN + - SMA_TRIPOWER_CAN - SOFAR_CAN - SOLAX_CAN + - SERIAL_LINK_TRANSMITTER # This is the platform GitHub will use to run our workflow. runs-on: ubuntu-latest diff --git a/.github/workflows/compile-all-inverters.yml b/.github/workflows/compile-all-inverters.yml index 954e263c..f9504af9 100644 --- a/.github/workflows/compile-all-inverters.yml +++ b/.github/workflows/compile-all-inverters.yml @@ -47,8 +47,10 @@ jobs: - LUNA2000_MODBUS - PYLON_CAN - SMA_CAN + - SMA_TRIPOWER_CAN - SOFAR_CAN - SOLAX_CAN + - SERIAL_LINK_TRANSMITTER # This is the platform GitHub will use to run our workflow. runs-on: ubuntu-latest diff --git a/Software/Software.ino b/Software/Software.ino index 5deca493..d238f3aa 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -22,8 +22,8 @@ #include "src/devboard/webserver/webserver.h" #endif -Preferences settings; // Store user settings -const char* version_number = "5.3.0"; // The current software version, shown on webserver +Preferences settings; // Store user settings +const char* version_number = "5.3.RC"; // The current software version, shown on webserver // Interval settings int intervalUpdateValues = 4800; // Interval at which to update inverter values / Modbus registers const int interval10 = 10; // Interval for 10ms tasks @@ -54,26 +54,27 @@ uint16_t mbPV[MB_RTU_NUM_VALUES]; // Process variable memory ModbusServerRTU MBserver(Serial2, 2000); #endif -// Common inverter parameters. Batteries map their values to these variables -uint16_t max_voltage = 5000; //V+1, 0-500.0 (0-5000) -uint16_t min_voltage = 2500; //V+1, 0-500.0 (0-5000) -uint16_t battery_voltage = 3700; //V+1, 0-500.0 (0-5000) -uint16_t battery_current = 0; -uint16_t SOC = 5000; //SOC%, 0-100.00 (0-10000) -uint16_t StateOfHealth = 9900; //SOH%, 0-100.00 (0-10000) -uint16_t capacity_Wh = BATTERY_WH_MAX; //Wh, 0-60000 -uint16_t remaining_capacity_Wh = BATTERY_WH_MAX; //Wh, 0-60000 -uint16_t max_target_discharge_power = 0; // 0W (0W > restricts to no discharge), Updates later on from CAN -uint16_t max_target_charge_power = 4312; // Init to 4.3kW, Updates later on from CAN -uint16_t temperature_max = 50; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -uint16_t temperature_min = 60; // Reads from battery later -uint8_t bms_status = ACTIVE; // ACTIVE - [0..5]<>[STANDBY,INACTIVE,DARKSTART,ACTIVE,FAULT,UPDATING] -uint16_t stat_batt_power = 0; // Power going in/out of battery -uint16_t cell_max_voltage = 3700; // Stores the highest cell voltage value in the system -uint16_t cell_min_voltage = 3700; // Stores the minimum cell voltage value in the system -uint16_t cellvoltages[120]; // Stores all cell voltages -uint8_t nof_cellvoltages = 0; // Total number of cell voltages, set by each battery. -bool LFP_Chemistry = false; +// Common system parameters. Batteries map their values to these variables +uint32_t system_capacity_Wh = BATTERY_WH_MAX; //Wh, 0-150000Wh +uint32_t system_remaining_capacity_Wh = BATTERY_WH_MAX; //Wh, 0-150000Wh +int16_t system_temperature_max_dC = 0; //C+1, -50.0 - 50.0 +int16_t system_temperature_min_dC = 0; //C+1, -50.0 - 50.0 +int16_t system_active_power_W = 0; //Watts, -32000 to 32000 +int16_t system_battery_current_dA = 0; //A+1, -1000 - 1000 +uint16_t system_battery_voltage_dV = 3700; //V+1, 0-500.0 (0-5000) +uint16_t system_max_design_voltage_dV = 5000; //V+1, 0-500.0 (0-5000) +uint16_t system_min_design_voltage_dV = 2500; //V+1, 0-500.0 (0-5000) +uint16_t system_scaled_SOC_pptt = 5000; //SOC%, 0-100.00 (0-10000) +uint16_t system_real_SOC_pptt = 5000; //SOC%, 0-100.00 (0-10000) +uint16_t system_SOH_pptt = 9900; //SOH%, 0-100.00 (0-10000) +uint16_t system_max_discharge_power_W = 0; //Watts, 0 to 65535 +uint16_t system_max_charge_power_W = 4312; //Watts, 0 to 65535 +uint16_t system_cell_max_voltage_mV = 3700; //mV, 0-5000 , Stores the highest cell millivolt value +uint16_t system_cell_min_voltage_mV = 3700; //mV, 0-5000, Stores the minimum cell millivolt value +uint16_t system_cellvoltages_mV[120]; //Array with all cell voltages in mV. Oversized to accomodate all setups +uint8_t system_bms_status = ACTIVE; //ACTIVE - [0..5]<>[STANDBY,INACTIVE,DARKSTART,ACTIVE,FAULT,UPDATING] +uint8_t system_number_of_cells = 0; //Total number of cell voltages, set by each battery +bool system_LFP_Chemistry = false; //Set to true or false depending on cell chemistry // Common charger parameters volatile float charger_setpoint_HV_VDC = 0.0f; @@ -185,6 +186,7 @@ void loop() { if (millis() - previousMillisUpdateVal >= intervalUpdateValues) // Every 4.8s { previousMillisUpdateVal = millis(); + update_SOC(); // Check if real or calculated SOC% value should be sent update_values(); // Update values heading towards inverter. Prepare for sending on CAN, or write directly to Modbus. if (DUMMY_EVENT_ENABLED) { set_event(EVENT_DUMMY_ERROR, (uint8_t)millis()); @@ -220,7 +222,7 @@ void init_stored_settings() { settings.clear(); // If this clear function is executed, no settings will be read from storage #endif - static uint16_t temp = 0; + static uint32_t temp = 0; temp = settings.getUInt("BATTERY_WH_MAX", false); if (temp != 0) { BATTERY_WH_MAX = temp; @@ -240,7 +242,10 @@ void init_stored_settings() { temp = settings.getUInt("MAXDISCHARGEAMP", false); if (temp != 0) { MAXDISCHARGEAMP = temp; - } + temp = settings.getBool("USE_SCALED_SOC", false); + USE_SCALED_SOC = temp; //This bool needs to be checked inside the temp!= block + } // No way to know if it wasnt reset otherwise + settings.end(); } @@ -357,9 +362,7 @@ void inform_user_on_inverter() { void init_battery() { // Inform user what battery is used and perform setup setup_battery(); -#ifdef SERIAL_LINK_RECEIVER - Serial.println("SERIAL_DATA_LINK_RECEIVER selected"); -#endif + #ifndef BATTERY_SELECTED #error No battery selected! Choose one from the USER_SETTINGS.h file #endif @@ -371,9 +374,11 @@ void receive_can() { // This section checks if we have a complete CAN message i CAN_frame_t rx_frame; if (xQueueReceive(CAN_cfg.rx_queue, &rx_frame, 3 * portTICK_PERIOD_MS) == pdTRUE) { if (rx_frame.FIR.B.FF == CAN_frame_std) { - //printf("New standard frame"); - // Battery +//printf("New standard frame"); +// Battery +#ifndef SERIAL_LINK_RECEIVER receive_can_battery(rx_frame); +#endif // Inverter #ifdef BYD_CAN receive_can_byd(rx_frame); @@ -517,7 +522,7 @@ void handle_LED_state() { #ifdef CONTACTOR_CONTROL void handle_contactors() { // First check if we have any active errors, incase we do, turn off the battery - if (bms_status == FAULT) { + if (system_bms_status == FAULT) { timeSpentInFaultedMode++; } else { timeSpentInFaultedMode = 0; @@ -600,6 +605,23 @@ void handle_contactors() { } #endif +void update_SOC() { + if (USE_SCALED_SOC) { //User has configred a SOC window. Calculate a SOC% to send towards inverter + static int16_t CalculatedSOC = 0; + CalculatedSOC = system_real_SOC_pptt; + CalculatedSOC = (10000) * (CalculatedSOC - (MINPERCENTAGE * 10)) / (MAXPERCENTAGE * 10 - MINPERCENTAGE * 10); + if (CalculatedSOC < 0) { //We are in the real SOC% range of 0-MINPERCENTAGE% + CalculatedSOC = 0; + } + if (CalculatedSOC > 10000) { //We are in the real SOC% range of MAXPERCENTAGE-100% + CalculatedSOC = 10000; + } + system_scaled_SOC_pptt = CalculatedSOC; + } else { // No SOC window wanted. Set scaled to same as real. + system_scaled_SOC_pptt = system_real_SOC_pptt; + } +} + void update_values() { // Battery update_values_battery(); // Map the fake values to the correct registers @@ -630,23 +652,22 @@ void update_values() { #endif } +#if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER) void runSerialDataLink() { static unsigned long updateTime = 0; unsigned long currentMillis = millis(); -#ifdef SERIAL_LINK_RECEIVER - if ((currentMillis - updateTime) > 1) { //Every 2ms - updateTime = currentMillis; - manageSerialLinkReceiver(); - } -#endif -#ifdef SERIAL_LINK_TRANSMITTER if ((currentMillis - updateTime) > 1) { //Every 2ms updateTime = currentMillis; - manageSerialLinkTransmitter(); - } +#ifdef SERIAL_LINK_RECEIVER + manageSerialLinkReceiver(); #endif +#ifdef SERIAL_LINK_TRANSMITTER + manageSerialLinkTransmitter(); +#endif + } } +#endif void init_serialDataLink() { #if defined(SERIAL_LINK_RECEIVER) || defined(SERIAL_LINK_TRANSMITTER) @@ -661,5 +682,7 @@ void storeSettings() { settings.putUInt("MINPERCENTAGE", MINPERCENTAGE); settings.putUInt("MAXCHARGEAMP", MAXCHARGEAMP); settings.putUInt("MAXDISCHARGEAMP", MAXDISCHARGEAMP); + settings.putBool("USE_SCALED_SOC", USE_SCALED_SOC); + settings.end(); } diff --git a/Software/USER_SETTINGS.cpp b/Software/USER_SETTINGS.cpp index bcc2a677..63fb6296 100644 --- a/Software/USER_SETTINGS.cpp +++ b/Software/USER_SETTINGS.cpp @@ -4,16 +4,17 @@ /* They can be defined here, or later on in the WebUI */ /* Battery settings */ -volatile uint16_t BATTERY_WH_MAX = - 30000; //Battery size in Wh (Maximum value for most inverters is 65000 [65kWh], you can use larger batteries but do not set value over 65000! +volatile bool USE_SCALED_SOC = + true; //Increases battery life. If true will rescale SOC between the configured min/max-percentage +volatile uint32_t BATTERY_WH_MAX = 30000; //Battery size in Wh volatile uint16_t MAXPERCENTAGE = - 800; //80.0% , Max percentage the battery will charge to (App will show 100% once this value is reached) + 800; //80.0% , Max percentage the battery will charge to (Inverter gets 100% when reached) volatile uint16_t MINPERCENTAGE = - 200; //20.0% , Min percentage the battery will discharge to (App will show 0% once this value is reached) + 200; //20.0% , Min percentage the battery will discharge to (Inverter gets 0% when reached) volatile uint16_t MAXCHARGEAMP = - 300; //30.0A , BYD CAN specific setting, Max charge speed in Amp (Some inverters needs to be artificially limited) + 300; //30.0A , BYD CAN specific setting, Max charge in Amp (Some inverters needs to be limited) volatile uint16_t MAXDISCHARGEAMP = - 300; //30.0A , BYD CAN specific setting, Max discharge speed in Amp (Some inverters needs to be artificially limited) + 300; //30.0A , BYD CAN specific setting, Max discharge in Amp (Some inverters needs to be limited) /* Charger settings (Optional, when generator charging) */ /* Charger settings */ diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 53a762cf..09dba6c4 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -30,7 +30,7 @@ //#define SOLAX_CAN //Enable this line to emulate a "SolaX Triple Power LFP" over CAN bus /* Other options */ -#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs +//#define DEBUG_VIA_USB //Enable this line to have the USB port output serial diagnostic data while program runs //#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting //#define CONTACTOR_CONTROL //Enable this line to have pins 25,32,33 handle automatic precharge/contactor+/contactor- closing sequence //#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM logic for contactors, which lower power consumption and heat generation @@ -38,7 +38,7 @@ //#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter) //#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery) #define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings. -// #define LOAD_SAVED_SETTINGS_ON_BOOT //Enable this line to read settings stored via the webserver on boot +//#define LOAD_SAVED_SETTINGS_ON_BOOT //Enable this line to read settings stored via the webserver on boot (overrides any battery settings set in USER_SETTINGS.cpp) /* MQTT options */ // #define MQTT // Enable this line to enable MQTT @@ -55,12 +55,13 @@ //#define NISSANLEAF_CHARGER //Enable this line to control a Nissan LEAF PDM connected to battery - for example, when generator charging /* Battery limits: These are set in the USER_SETTINGS.cpp file, or later on via the Webserver */ -extern volatile uint16_t BATTERY_WH_MAX; +extern volatile uint32_t BATTERY_WH_MAX; extern volatile uint16_t MAXPERCENTAGE; extern volatile uint16_t MINPERCENTAGE; extern volatile uint16_t MAXCHARGEAMP; extern volatile uint16_t MAXDISCHARGEAMP; extern volatile uint8_t AccessPointEnabled; +extern volatile bool USE_SCALED_SOC; /* Charger limits (Optional): Set in the USER_SETTINGS.cpp or later in the webserver */ extern volatile float charger_setpoint_HV_VDC; diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index f6efe68e..dfef51e3 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -47,11 +47,13 @@ #include "SERIAL-LINK-RECEIVER-FROM-BATTERY.h" //See this file for more Serial-battery settings #endif -#ifndef SERIAL_LINK_RECEIVER // The serial thing does its thing -void update_values_battery(); +#ifdef SERIAL_LINK_RECEIVER // The serial thing does its thing +void receive_can_battery(); +#else void receive_can_battery(CAN_frame_t rx_frame); +#endif +void update_values_battery(); void send_can_battery(); void setup_battery(void); -#endif #endif diff --git a/Software/src/battery/BMW-I3-BATTERY.cpp b/Software/src/battery/BMW-I3-BATTERY.cpp index 11c6794f..3ca7601c 100644 --- a/Software/src/battery/BMW-I3-BATTERY.cpp +++ b/Software/src/battery/BMW-I3-BATTERY.cpp @@ -16,9 +16,6 @@ static const int interval20 = 20; // interval (ms) at which send CAN static const int interval600 = 600; // interval (ms) at which send CAN Messages static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive -#define LB_MAX_SOC 1000 //BMS never goes over this value. We use this info to rescale SOC% sent to Inverter -#define LB_MIN_SOC 0 //BMS never goes below this value. We use this info to rescale SOC% sent to Inverter - CAN_frame_t BMW_10B = {.FIR = {.B = { .DLC = 3, @@ -58,47 +55,38 @@ static int16_t Battery_Power = 0; void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus //Calculate the SOC% value to send to inverter - Calculated_SOC = (Display_SOC * 10); //Increase decimal amount - Calculated_SOC = - LB_MIN_SOC + (LB_MAX_SOC - LB_MIN_SOC) * (Calculated_SOC - MINPERCENTAGE) / (MAXPERCENTAGE - MINPERCENTAGE); - if (Calculated_SOC < 0) { //We are in the real SOC% range of 0-20%, always set SOC sent to inverter as 0% - Calculated_SOC = 0; - } - if (Calculated_SOC > 1000) { //We are in the real SOC% range of 80-100%, always set SOC sent to inverter as 100% - Calculated_SOC = 1000; - } - SOC = (Calculated_SOC * 10); //increase LB_SOC range from 0-100.0 -> 100.00 + system_real_SOC_pptt = (Display_SOC * 100); //increase Display_SOC range from 0-100 -> 100.00 - battery_voltage = Battery_Volts; //Unit V+1 (5000 = 500.0V) + system_battery_voltage_dV = Battery_Volts; //Unit V+1 (5000 = 500.0V) - battery_current = Battery_Current; + system_battery_current_dA = Battery_Current; - capacity_Wh = BATTERY_WH_MAX; + system_capacity_Wh = BATTERY_WH_MAX; - remaining_capacity_Wh = (Battery_Capacity_kWh * 1000); + system_remaining_capacity_Wh = (Battery_Capacity_kWh * 1000); - if (SOC > 9900) //If Soc is over 99%, stop charging + if (system_scaled_SOC_pptt > 9900) //If Soc is over 99%, stop charging { - max_target_charge_power = 0; + system_max_charge_power_W = 0; } else { - max_target_charge_power = 5000; //Hardcoded value for testing. TODO: read real value from battery when discovered + system_max_charge_power_W = 5000; //Hardcoded value for testing. TODO: read real value from battery when discovered } - if (SOC < 500) //If Soc is under 5%, stop dicharging + if (system_scaled_SOC_pptt < 500) //If Soc is under 5%, stop dicharging { - max_target_discharge_power = 0; + system_max_discharge_power_W = 0; } else { - max_target_discharge_power = + system_max_discharge_power_W = 5000; //Hardcoded value for testing. TODO: read real value from battery when discovered } Battery_Power = (Battery_Current * (Battery_Volts / 10)); - stat_batt_power = Battery_Power; //TODO:, is mapping OK? + system_active_power_W = Battery_Power; //TODO:, is mapping OK? - temperature_min; //hardcoded to 5*C in startup, TODO:, find from battery CAN later + system_temperature_min_dC; //hardcoded to 5*C in startup, TODO:, find from battery CAN later - temperature_max; //hardcoded to 6*C in startup, TODO:, find from battery CAN later + system_temperature_max_dC; //hardcoded to 6*C in startup, TODO:, find from battery CAN later /* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/ if (!CANstillAlive) { @@ -112,15 +100,15 @@ void update_values_battery() { //This function maps all the values fetched via Serial.print("SOC% battery: "); Serial.print(Display_SOC); Serial.print(" SOC% sent to inverter: "); - Serial.print(SOC); + Serial.print(system_scaled_SOC_pptt); Serial.print(" Battery voltage: "); - Serial.print(battery_voltage); + Serial.print(system_battery_voltage_dV); Serial.print(" Remaining Wh: "); - Serial.print(remaining_capacity_Wh); + Serial.print(system_remaining_capacity_Wh); Serial.print(" Max charge power: "); - Serial.print(max_target_charge_power); + Serial.print(system_max_charge_power_W); Serial.print(" Max discharge power: "); - Serial.print(max_target_discharge_power); + Serial.print(system_max_discharge_power_W); #endif } @@ -196,8 +184,8 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup Serial.println("BMW i3 battery selected"); - max_voltage = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge) - min_voltage = 3100; // 310.0V under this, discharging further is disabled + system_max_design_voltage_dV = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge) + system_min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled } #endif diff --git a/Software/src/battery/BMW-I3-BATTERY.h b/Software/src/battery/BMW-I3-BATTERY.h index e2cea1c9..63203187 100644 --- a/Software/src/battery/BMW-I3-BATTERY.h +++ b/Software/src/battery/BMW-I3-BATTERY.h @@ -8,24 +8,26 @@ #define BATTERY_SELECTED // These parameters need to be mapped for the inverter -extern uint16_t max_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t min_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t SOC; //SOC%, 0-100.00 (0-10000) -extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000) -extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485) -extern uint16_t capacity_Wh; //Wh, 0-60000 -extern uint16_t remaining_capacity_Wh; //Wh, 0-60000 -extern uint16_t max_target_discharge_power; //W, 0-60000 -extern uint16_t max_target_charge_power; //W, 0-60000 -extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530) -extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t cell_max_voltage; //mV, 0-4350 -extern uint16_t cell_min_voltage; //mV, 0-4350 -extern uint16_t cellvoltages[120]; //mV 0-4350 per cell -extern uint8_t nof_cellvoltages; // Total number of cell voltages, set by each battery. -extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false +extern uint32_t system_capacity_Wh; //Wh, 0-150000Wh +extern uint32_t system_remaining_capacity_Wh; //Wh, 0-150000Wh +extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0 +extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0 +extern int16_t system_active_power_W; //W, -32000 to 32000 +extern int16_t system_battery_current_dA; //A+1, -1000 - 1000 +extern uint16_t system_battery_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_max_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_min_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000) +extern uint16_t system_max_discharge_power_W; //W, 0-65000 +extern uint16_t system_max_charge_power_W; //W, 0-65000 +extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value +extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value +extern uint16_t system_cellvoltages_mV[120]; //Array with all cell voltages in mV +extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery +extern uint8_t system_bms_status; //Enum 0-5 +extern bool batteryAllowsContactorClosing; //Bool, true/false void setup_battery(void); diff --git a/Software/src/battery/CHADEMO-BATTERY.cpp b/Software/src/battery/CHADEMO-BATTERY.cpp index dfabd72b..a6ff7c90 100644 --- a/Software/src/battery/CHADEMO-BATTERY.cpp +++ b/Software/src/battery/CHADEMO-BATTERY.cpp @@ -93,16 +93,16 @@ uint8_t HighVoltageControlStatus = 0; void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter - SOC = ChargingRate; + system_real_SOC_pptt = ChargingRate; - max_target_discharge_power = (MaximumDischargeCurrent * MaximumBatteryVoltage); //In Watts, Convert A to P + system_max_discharge_power_W = (MaximumDischargeCurrent * MaximumBatteryVoltage); //In Watts, Convert A to P - battery_voltage = TargetBatteryVoltage; //TODO: scaling? + system_battery_voltage_dV = TargetBatteryVoltage; //TODO: scaling? - capacity_Wh = ((RatedBatteryCapacity / 0.11) * - 1000); //(Added in CHAdeMO v1.0.1), maybe handle hardcoded on lower protocol version? + system_capacity_Wh = ((RatedBatteryCapacity / 0.11) * + 1000); //(Added in CHAdeMO v1.0.1), maybe handle hardcoded on lower protocol version? - remaining_capacity_Wh = (SOC / 100) * capacity_Wh; + system_remaining_capacity_Wh = (system_real_SOC_pptt / 100) * system_capacity_Wh; /* Check if the Vehicle is still sending CAN messages. If we go 60s without messages we raise an error*/ if (!CANstillAlive) { @@ -119,19 +119,19 @@ void update_values_battery() { //This function maps all the values fetched via Serial.println(errorCode); } Serial.print("BMS Status (3=OK): "); - Serial.println(bms_status); + Serial.println(system_bms_status); Serial.print("Max discharge power: "); - Serial.println(max_target_discharge_power); + Serial.println(system_max_discharge_power_W); Serial.print("Max charge power: "); - Serial.println(max_target_charge_power); + Serial.println(system_max_charge_power_W); Serial.print("SOH%: "); - Serial.println(StateOfHealth); + Serial.println(system_SOH_pptt); Serial.print("SOC% to Inverter: "); - Serial.println(SOC); + Serial.println(system_scaled_SOC_pptt); Serial.print("Temperature Min: "); - Serial.println(temperature_min); + Serial.println(system_temperature_min_dC); Serial.print("Temperature Max: "); - Serial.println(temperature_max); + Serial.println(system_temperature_max_dC); #endif } @@ -211,7 +211,7 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup Serial.println("Chademo battery selected"); - max_voltage = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge) - min_voltage = 2000; // 200.0V under this, discharging further is disabled + system_max_design_voltage_dV = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge) + system_min_design_voltage_dV = 2000; // 200.0V under this, discharging further is disabled } #endif diff --git a/Software/src/battery/CHADEMO-BATTERY.h b/Software/src/battery/CHADEMO-BATTERY.h index 0e27b44a..7675ad30 100644 --- a/Software/src/battery/CHADEMO-BATTERY.h +++ b/Software/src/battery/CHADEMO-BATTERY.h @@ -8,24 +8,26 @@ #define BATTERY_SELECTED // These parameters need to be mapped for the inverter -extern uint16_t max_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t min_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t SOC; //SOC%, 0-100.00 (0-10000) -extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000) -extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485) -extern uint16_t capacity_Wh; //Wh, 0-60000 -extern uint16_t remaining_capacity_Wh; //Wh, 0-60000 -extern uint16_t max_target_discharge_power; //W, 0-60000 -extern uint16_t max_target_charge_power; //W, 0-60000 -extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530) -extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t cell_max_voltage; //mV, 0-4350 -extern uint16_t cell_min_voltage; //mV, 0-4350 -extern uint16_t cellvoltages[120]; //mV 0-4350 per cell -extern uint8_t nof_cellvoltages; // Total number of cell voltages, set by each battery. -extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false +extern uint32_t system_capacity_Wh; //Wh, 0-150000Wh +extern uint32_t system_remaining_capacity_Wh; //Wh, 0-150000Wh +extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0 +extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0 +extern int16_t system_active_power_W; //W, -32000 to 32000 +extern int16_t system_battery_current_dA; //A+1, -1000 - 1000 +extern uint16_t system_battery_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_max_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_min_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000) +extern uint16_t system_max_discharge_power_W; //W, 0-65000 +extern uint16_t system_max_charge_power_W; //W, 0-65000 +extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value +extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value +extern uint16_t system_cellvoltages_mV[120]; //Array with all cell voltages in mV +extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery +extern uint8_t system_bms_status; //Enum 0-5 +extern bool batteryAllowsContactorClosing; //Bool, true/false void setup_battery(void); diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp index 7530c37e..24901cb0 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp @@ -9,8 +9,6 @@ //Figure out if CAN messages need to be sent to keep the system happy? /* Do not change code below unless you are sure what you are doing */ -#define BMU_MAX_SOC 1000 //BMS never goes over this value. We use this info to rescale SOC% sent to inverter -#define BMU_MIN_SOC 0 //BMS never goes below this value. We use this info to rescale SOC% sent to inverter static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive static uint8_t errorCode = 0; //stores if we have an error code active from battery control logic static uint8_t BMU_Detected = 0; @@ -43,30 +41,30 @@ static double max_temp_cel = 20.00; static double min_temp_cel = 19.00; void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus - SOC = (uint16_t)(BMU_SOC * 100); //increase BMU_SOC range from 0-100 -> 100.00 + system_real_SOC_pptt = (uint16_t)(BMU_SOC * 100); //increase BMU_SOC range from 0-100 -> 100.00 - battery_voltage = (uint16_t)(BMU_PackVoltage * 10); // Multiply by 10 and cast to uint16_t + system_battery_voltage_dV = (uint16_t)(BMU_PackVoltage * 10); // Multiply by 10 and cast to uint16_t - battery_current = (BMU_Current * 10); //Todo, scaling? + system_battery_current_dA = (BMU_Current * 10); //Todo, scaling? - capacity_Wh = BATTERY_WH_MAX; //Hardcoded to header value + system_capacity_Wh = BATTERY_WH_MAX; //Hardcoded to header value - remaining_capacity_Wh = (uint16_t)((SOC / 10000) * capacity_Wh); + system_remaining_capacity_Wh = (uint16_t)((system_real_SOC_pptt / 10000) * system_capacity_Wh); //We do not know if the max charge power is sent by the battery. So we estimate the value based on SOC% - if (SOC == 10000) { //100.00% - max_target_charge_power = 0; //When battery is 100% full, set allowed charge W to 0 + if (system_scaled_SOC_pptt == 10000) { //100.00% + system_max_charge_power_W = 0; //When battery is 100% full, set allowed charge W to 0 } else { - max_target_charge_power = 10000; //Otherwise we can push 10kW into the pack! + system_max_charge_power_W = 10000; //Otherwise we can push 10kW into the pack! } - if (SOC < 200) { //2.00% - max_target_discharge_power = 0; //When battery is empty (below 2%), set allowed discharge W to 0 + if (system_scaled_SOC_pptt < 200) { //2.00% + system_max_discharge_power_W = 0; //When battery is empty (below 2%), set allowed discharge W to 0 } else { - max_target_discharge_power = 10000; //Otherwise we can discharge 10kW from the pack! + system_max_discharge_power_W = 10000; //Otherwise we can discharge 10kW from the pack! } - stat_batt_power = BMU_Power; //TODO: Scaling? + system_active_power_W = BMU_Power; //TODO: Scaling? static int n = sizeof(cell_voltages) / sizeof(cell_voltages[0]); max_volt_cel = cell_voltages[0]; // Initialize max with the first element of the array @@ -98,13 +96,13 @@ void update_values_battery() { //This function maps all the values fetched via } } - cell_max_voltage = (uint16_t)(max_volt_cel * 1000); + system_cell_max_voltage_mV = (uint16_t)(max_volt_cel * 1000); - cell_min_voltage = (uint16_t)(min_volt_cel * 1000); + system_cell_min_voltage_mV = (uint16_t)(min_volt_cel * 1000); - temperature_min = (uint16_t)(min_temp_cel * 1000); + system_temperature_min_dC = (int16_t)(min_temp_cel * 1000); - temperature_max = (uint16_t)(max_temp_cel * 1000); + system_temperature_min_dC = (int16_t)(max_temp_cel * 1000); /* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/ if (!CANstillAlive) { @@ -140,25 +138,25 @@ void update_values_battery() { //This function maps all the values fetched via Serial.println("Values sent to inverter"); Serial.print("SOC% (0-100.00): "); - Serial.print(SOC); + Serial.print(system_scaled_SOC_pptt); Serial.print(" Voltage (0-400.0): "); - Serial.print(battery_voltage); + Serial.print(system_battery_voltage_dV); Serial.print(" Capacity WH full (0-60000): "); - Serial.print(capacity_Wh); + Serial.print(system_capacity_Wh); Serial.print(" Capacity WH remain (0-60000): "); - Serial.print(remaining_capacity_Wh); + Serial.print(system_remaining_capacity_Wh); Serial.print(" Max charge power W (0-10000): "); - Serial.print(max_target_charge_power); + Serial.print(system_max_charge_power_W); Serial.print(" Max discharge power W (0-10000): "); - Serial.print(max_target_discharge_power); + Serial.print(system_max_discharge_power_W); Serial.print(" Temp max "); - Serial.print(temperature_max); + Serial.print(system_temperature_max_dC); Serial.print(" Temp min "); - Serial.print(temperature_min); + Serial.print(system_temperature_min_dC); Serial.print(" Cell mV max "); - Serial.print(cell_max_voltage); + Serial.print(system_cell_max_voltage_mV); Serial.print(" Cell mV min "); - Serial.print(cell_min_voltage); + Serial.print(system_cell_min_voltage_mV); #endif } @@ -230,8 +228,8 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup Serial.println("Mitsubishi i-MiEV / Citroen C-Zero / Peugeot Ion battery selected"); - max_voltage = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge) - min_voltage = 3100; // 310.0V under this, discharging further is disabled + system_max_design_voltage_dV = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge) + system_min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled } #endif diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h index fcb4e3e7..c035a208 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h @@ -7,26 +7,28 @@ #define BATTERY_SELECTED -// These parameters need to be mapped for the Inverter -extern uint16_t max_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t min_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t SOC; //SOC%, 0-100.00 (0-10000) -extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000) -extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485) -extern uint16_t capacity_Wh; //Wh, 0-60000 -extern uint16_t remaining_capacity_Wh; //Wh, 0-60000 -extern uint16_t max_target_discharge_power; //W, 0-60000 -extern uint16_t max_target_charge_power; //W, 0-60000 -extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530) -extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t cell_max_voltage; //mV, 0-4350 -extern uint16_t cell_min_voltage; //mV, 0-4350 -extern uint16_t cellvoltages[120]; //mV 0-4350 per cell -extern uint8_t nof_cellvoltages; // Total number of cell voltages, set by each battery. -extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false -extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false +// These parameters need to be mapped for the inverter +extern uint32_t system_capacity_Wh; //Wh, 0-150000Wh +extern uint32_t system_remaining_capacity_Wh; //Wh, 0-150000Wh +extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0 +extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0 +extern int16_t system_active_power_W; //W, -32000 to 32000 +extern int16_t system_battery_current_dA; //A+1, -1000 - 1000 +extern uint16_t system_battery_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_max_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_min_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000) +extern uint16_t system_max_discharge_power_W; //W, 0-65000 +extern uint16_t system_max_charge_power_W; //W, 0-65000 +extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value +extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value +extern uint16_t system_cellvoltages_mV[120]; //Array with all cell voltages in mV +extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery +extern uint8_t system_bms_status; //Enum 0-5 +extern bool batteryAllowsContactorClosing; //Bool, true/false +extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false void setup_battery(void); diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index 4cb3a4cb..d9d7c448 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -12,8 +12,6 @@ static const int interval100 = 100; // interval (ms) at which send CAN static const int interval10ms = 10; // interval (ms) at which send CAN Messages static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive -#define MAX_SOC 1000 //BMS never goes over this value. We use this info to rescale SOC% sent to Inverter -#define MIN_SOC 0 //BMS never goes below this value. We use this info to rescale SOC% sent to Inverter #define MAX_CELL_VOLTAGE 4250 //Battery is put into emergency stop if one cell goes over this value #define MIN_CELL_VOLTAGE 2950 //Battery is put into emergency stop if one cell goes below this value #define MAX_CELL_DEVIATION 150 //LED turns yellow on the board if mv delta exceeds this value @@ -150,52 +148,43 @@ CAN_frame_t KIA64_7E4_ack = { void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus - //Calculate the SOC% value to send to inverter - soc_calculated = SOC_Display; - soc_calculated = MIN_SOC + (MAX_SOC - MIN_SOC) * (soc_calculated - MINPERCENTAGE) / (MAXPERCENTAGE - MINPERCENTAGE); - if (soc_calculated < 0) { //We are in the real SOC% range of 0-20%, always set SOC sent to Inverter as 0% - soc_calculated = 0; - } - if (soc_calculated > 1000) { //We are in the real SOC% range of 80-100%, always set SOC sent to Inverter as 100% - soc_calculated = 1000; - } - SOC = (soc_calculated * 10); //increase SOC range from 0-100.0 -> 100.00 + system_real_SOC_pptt = (SOC_Display * 10); //increase SOC range from 0-100.0 -> 100.00 - StateOfHealth = (batterySOH * 10); //Increase decimals from 100.0% -> 100.00% + system_SOH_pptt = (batterySOH * 10); //Increase decimals from 100.0% -> 100.00% - battery_voltage = batteryVoltage; //value is *10 (3700 = 370.0) + system_battery_voltage_dV = batteryVoltage; //value is *10 (3700 = 370.0) - battery_current = convertToUnsignedInt16(batteryAmps); //value is *10 (150 = 15.0) + system_battery_current_dA = batteryAmps; //value is *10 (150 = 15.0) - capacity_Wh = BATTERY_WH_MAX; + system_capacity_Wh = BATTERY_WH_MAX; - remaining_capacity_Wh = static_cast((static_cast(SOC) / 10000) * BATTERY_WH_MAX); + system_remaining_capacity_Wh = static_cast((static_cast(system_real_SOC_pptt) / 10000) * BATTERY_WH_MAX); - //max_target_charge_power = (uint16_t)allowedChargePower * 10; //From kW*100 to Watts + //system_max_charge_power_W = (uint16_t)allowedChargePower * 10; //From kW*100 to Watts //The allowed charge power is not available. We estimate this value - if (SOC == 10000) { // When scaled SOC is 100%, set allowed charge power to 0 - max_target_charge_power = 0; + if (system_scaled_SOC_pptt == 10000) { // When scaled SOC is 100%, set allowed charge power to 0 + system_max_charge_power_W = 0; } else { // No limits, max charging power allowed - max_target_charge_power = MAXCHARGEPOWERALLOWED; + system_max_charge_power_W = MAXCHARGEPOWERALLOWED; } - //max_target_discharge_power = (uint16_t)allowedDischargePower * 10; //From kW*100 to Watts - if (SOC < 100) { // When scaled SOC is <1%, set allowed charge power to 0 - max_target_discharge_power = 0; + //system_max_discharge_power_W = (uint16_t)allowedDischargePower * 10; //From kW*100 to Watts + if (system_scaled_SOC_pptt < 100) { // When scaled SOC is <1%, set allowed charge power to 0 + system_max_discharge_power_W = 0; } else { // No limits, max charging power allowed - max_target_discharge_power = MAXDISCHARGEPOWERALLOWED; + system_max_discharge_power_W = MAXDISCHARGEPOWERALLOWED; } powerWatt = ((batteryVoltage * batteryAmps) / 100); - stat_batt_power = convertToUnsignedInt16(powerWatt); //Power in watts, Negative = charging batt + system_active_power_W = powerWatt; //Power in watts, Negative = charging batt - temperature_min = convertToUnsignedInt16((int8_t)temperatureMin * 10); //Increase decimals, 17C -> 17.0C + system_temperature_min_dC = (int8_t)temperatureMin * 10; //Increase decimals, 17C -> 17.0C - temperature_max = convertToUnsignedInt16((int8_t)temperatureMax * 10); //Increase decimals, 18C -> 18.0C + system_temperature_max_dC = (int8_t)temperatureMax * 10; //Increase decimals, 18C -> 18.0C - cell_max_voltage = CellVoltMax_mV; + system_cell_max_voltage_mV = CellVoltMax_mV; - cell_min_voltage = CellVoltMin_mV; + system_cell_min_voltage_mV = CellVoltMin_mV; /* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/ if (!CANstillAlive) { @@ -214,12 +203,12 @@ void update_values_battery() { //This function maps all the values fetched via } // Check if cell voltages are within allowed range - cell_deviation_mV = (cell_max_voltage - cell_min_voltage); + cell_deviation_mV = (system_cell_max_voltage_mV - system_cell_min_voltage_mV); - if (cell_max_voltage >= MAX_CELL_VOLTAGE) { + if (CellVoltMax_mV >= MAX_CELL_VOLTAGE) { set_event(EVENT_CELL_OVER_VOLTAGE, 0); } - if (cell_min_voltage <= MIN_CELL_VOLTAGE) { + if (CellVoltMin_mV <= MIN_CELL_VOLTAGE) { set_event(EVENT_CELL_UNDER_VOLTAGE, 0); } if (cell_deviation_mV > MAX_CELL_DEVIATION) { @@ -228,9 +217,9 @@ void update_values_battery() { //This function maps all the values fetched via clear_event(EVENT_CELL_DEVIATION_HIGH); } - if (bms_status == FAULT) { //Incase we enter a critical fault state, zero out the allowed limits - max_target_charge_power = 0; - max_target_discharge_power = 0; + if (system_bms_status == FAULT) { //Incase we enter a critical fault state, zero out the allowed limits + system_max_charge_power_W = 0; + system_max_discharge_power_W = 0; } /* Safeties verified. Perform USB serial printout if configured to do so */ @@ -249,7 +238,7 @@ void update_values_battery() { //This function maps all the values fetched via Serial.print(" Amps | "); Serial.print((uint16_t)batteryVoltage / 10.0, 1); Serial.print(" Volts | "); - Serial.print((int16_t)stat_batt_power); + Serial.print((int16_t)system_active_power_W); Serial.println(" Watts"); Serial.print("Allowed Charge "); Serial.print((uint16_t)allowedChargePower * 10); @@ -364,53 +353,53 @@ void receive_can_battery(CAN_frame_t rx_frame) { allowedDischargePower = ((rx_frame.data.u8[5] << 8) + rx_frame.data.u8[6]); batteryRelay = rx_frame.data.u8[7]; } else if (poll_data_pid == 2) { - cellvoltages[0] = (rx_frame.data.u8[2] * 20); - cellvoltages[1] = (rx_frame.data.u8[3] * 20); - cellvoltages[2] = (rx_frame.data.u8[4] * 20); - cellvoltages[3] = (rx_frame.data.u8[5] * 20); - cellvoltages[4] = (rx_frame.data.u8[6] * 20); - cellvoltages[5] = (rx_frame.data.u8[7] * 20); + system_cellvoltages_mV[0] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[1] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[2] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[3] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[4] = (rx_frame.data.u8[6] * 20); + system_cellvoltages_mV[5] = (rx_frame.data.u8[7] * 20); } else if (poll_data_pid == 3) { - cellvoltages[32] = (rx_frame.data.u8[2] * 20); - cellvoltages[33] = (rx_frame.data.u8[3] * 20); - cellvoltages[34] = (rx_frame.data.u8[4] * 20); - cellvoltages[35] = (rx_frame.data.u8[5] * 20); - cellvoltages[36] = (rx_frame.data.u8[6] * 20); - cellvoltages[37] = (rx_frame.data.u8[7] * 20); + system_cellvoltages_mV[32] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[33] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[34] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[35] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[36] = (rx_frame.data.u8[6] * 20); + system_cellvoltages_mV[37] = (rx_frame.data.u8[7] * 20); } else if (poll_data_pid == 4) { - cellvoltages[64] = (rx_frame.data.u8[2] * 20); - cellvoltages[65] = (rx_frame.data.u8[3] * 20); - cellvoltages[66] = (rx_frame.data.u8[4] * 20); - cellvoltages[67] = (rx_frame.data.u8[5] * 20); - cellvoltages[68] = (rx_frame.data.u8[6] * 20); - cellvoltages[69] = (rx_frame.data.u8[7] * 20); + system_cellvoltages_mV[64] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[65] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[66] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[67] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[68] = (rx_frame.data.u8[6] * 20); + system_cellvoltages_mV[69] = (rx_frame.data.u8[7] * 20); } break; case 0x22: //Second datarow in PID group if (poll_data_pid == 2) { - cellvoltages[6] = (rx_frame.data.u8[1] * 20); - cellvoltages[7] = (rx_frame.data.u8[2] * 20); - cellvoltages[8] = (rx_frame.data.u8[3] * 20); - cellvoltages[9] = (rx_frame.data.u8[4] * 20); - cellvoltages[10] = (rx_frame.data.u8[5] * 20); - cellvoltages[11] = (rx_frame.data.u8[6] * 20); - cellvoltages[12] = (rx_frame.data.u8[7] * 20); + system_cellvoltages_mV[6] = (rx_frame.data.u8[1] * 20); + system_cellvoltages_mV[7] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[8] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[9] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[10] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[11] = (rx_frame.data.u8[6] * 20); + system_cellvoltages_mV[12] = (rx_frame.data.u8[7] * 20); } else if (poll_data_pid == 3) { - cellvoltages[38] = (rx_frame.data.u8[1] * 20); - cellvoltages[39] = (rx_frame.data.u8[2] * 20); - cellvoltages[40] = (rx_frame.data.u8[3] * 20); - cellvoltages[41] = (rx_frame.data.u8[4] * 20); - cellvoltages[42] = (rx_frame.data.u8[5] * 20); - cellvoltages[43] = (rx_frame.data.u8[6] * 20); - cellvoltages[44] = (rx_frame.data.u8[7] * 20); + system_cellvoltages_mV[38] = (rx_frame.data.u8[1] * 20); + system_cellvoltages_mV[39] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[40] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[41] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[42] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[43] = (rx_frame.data.u8[6] * 20); + system_cellvoltages_mV[44] = (rx_frame.data.u8[7] * 20); } else if (poll_data_pid == 4) { - cellvoltages[70] = (rx_frame.data.u8[1] * 20); - cellvoltages[71] = (rx_frame.data.u8[2] * 20); - cellvoltages[72] = (rx_frame.data.u8[3] * 20); - cellvoltages[73] = (rx_frame.data.u8[4] * 20); - cellvoltages[74] = (rx_frame.data.u8[5] * 20); - cellvoltages[75] = (rx_frame.data.u8[6] * 20); - cellvoltages[76] = (rx_frame.data.u8[7] * 20); + system_cellvoltages_mV[70] = (rx_frame.data.u8[1] * 20); + system_cellvoltages_mV[71] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[72] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[73] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[74] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[75] = (rx_frame.data.u8[6] * 20); + system_cellvoltages_mV[76] = (rx_frame.data.u8[7] * 20); } else if (poll_data_pid == 6) { batteryManagementMode = rx_frame.data.u8[5]; } @@ -420,29 +409,29 @@ void receive_can_battery(CAN_frame_t rx_frame) { temperature_water_inlet = rx_frame.data.u8[6]; CellVoltMax_mV = (rx_frame.data.u8[7] * 20); //(volts *50) *20 =mV } else if (poll_data_pid == 2) { - cellvoltages[13] = (rx_frame.data.u8[1] * 20); - cellvoltages[14] = (rx_frame.data.u8[2] * 20); - cellvoltages[15] = (rx_frame.data.u8[3] * 20); - cellvoltages[16] = (rx_frame.data.u8[4] * 20); - cellvoltages[17] = (rx_frame.data.u8[5] * 20); - cellvoltages[18] = (rx_frame.data.u8[6] * 20); - cellvoltages[19] = (rx_frame.data.u8[7] * 20); + system_cellvoltages_mV[13] = (rx_frame.data.u8[1] * 20); + system_cellvoltages_mV[14] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[15] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[16] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[17] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[18] = (rx_frame.data.u8[6] * 20); + system_cellvoltages_mV[19] = (rx_frame.data.u8[7] * 20); } else if (poll_data_pid == 3) { - cellvoltages[45] = (rx_frame.data.u8[1] * 20); - cellvoltages[46] = (rx_frame.data.u8[2] * 20); - cellvoltages[47] = (rx_frame.data.u8[3] * 20); - cellvoltages[48] = (rx_frame.data.u8[4] * 20); - cellvoltages[49] = (rx_frame.data.u8[5] * 20); - cellvoltages[50] = (rx_frame.data.u8[6] * 20); - cellvoltages[51] = (rx_frame.data.u8[7] * 20); + system_cellvoltages_mV[45] = (rx_frame.data.u8[1] * 20); + system_cellvoltages_mV[46] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[47] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[48] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[49] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[50] = (rx_frame.data.u8[6] * 20); + system_cellvoltages_mV[51] = (rx_frame.data.u8[7] * 20); } else if (poll_data_pid == 4) { - cellvoltages[77] = (rx_frame.data.u8[1] * 20); - cellvoltages[78] = (rx_frame.data.u8[2] * 20); - cellvoltages[79] = (rx_frame.data.u8[3] * 20); - cellvoltages[80] = (rx_frame.data.u8[4] * 20); - cellvoltages[81] = (rx_frame.data.u8[5] * 20); - cellvoltages[82] = (rx_frame.data.u8[6] * 20); - cellvoltages[83] = (rx_frame.data.u8[7] * 20); + system_cellvoltages_mV[77] = (rx_frame.data.u8[1] * 20); + system_cellvoltages_mV[78] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[79] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[80] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[81] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[82] = (rx_frame.data.u8[6] * 20); + system_cellvoltages_mV[83] = (rx_frame.data.u8[7] * 20); } else if (poll_data_pid == 5) { heatertemp = rx_frame.data.u8[7]; } @@ -453,56 +442,56 @@ void receive_can_battery(CAN_frame_t rx_frame) { CellVminNo = rx_frame.data.u8[3]; CellVoltMin_mV = (rx_frame.data.u8[2] * 20); //(volts *50) *20 =mV } else if (poll_data_pid == 2) { - cellvoltages[20] = (rx_frame.data.u8[1] * 20); - cellvoltages[21] = (rx_frame.data.u8[2] * 20); - cellvoltages[22] = (rx_frame.data.u8[3] * 20); - cellvoltages[23] = (rx_frame.data.u8[4] * 20); - cellvoltages[24] = (rx_frame.data.u8[5] * 20); - cellvoltages[25] = (rx_frame.data.u8[6] * 20); - cellvoltages[26] = (rx_frame.data.u8[7] * 20); + system_cellvoltages_mV[20] = (rx_frame.data.u8[1] * 20); + system_cellvoltages_mV[21] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[22] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[23] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[24] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[25] = (rx_frame.data.u8[6] * 20); + system_cellvoltages_mV[26] = (rx_frame.data.u8[7] * 20); } else if (poll_data_pid == 3) { - cellvoltages[52] = (rx_frame.data.u8[1] * 20); - cellvoltages[53] = (rx_frame.data.u8[2] * 20); - cellvoltages[54] = (rx_frame.data.u8[3] * 20); - cellvoltages[55] = (rx_frame.data.u8[4] * 20); - cellvoltages[56] = (rx_frame.data.u8[5] * 20); - cellvoltages[57] = (rx_frame.data.u8[6] * 20); - cellvoltages[58] = (rx_frame.data.u8[7] * 20); + system_cellvoltages_mV[52] = (rx_frame.data.u8[1] * 20); + system_cellvoltages_mV[53] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[54] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[55] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[56] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[57] = (rx_frame.data.u8[6] * 20); + system_cellvoltages_mV[58] = (rx_frame.data.u8[7] * 20); } else if (poll_data_pid == 4) { - cellvoltages[84] = (rx_frame.data.u8[1] * 20); - cellvoltages[85] = (rx_frame.data.u8[2] * 20); - cellvoltages[86] = (rx_frame.data.u8[3] * 20); - cellvoltages[87] = (rx_frame.data.u8[4] * 20); - cellvoltages[88] = (rx_frame.data.u8[5] * 20); - cellvoltages[89] = (rx_frame.data.u8[6] * 20); - cellvoltages[90] = (rx_frame.data.u8[7] * 20); + system_cellvoltages_mV[84] = (rx_frame.data.u8[1] * 20); + system_cellvoltages_mV[85] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[86] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[87] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[88] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[89] = (rx_frame.data.u8[6] * 20); + system_cellvoltages_mV[90] = (rx_frame.data.u8[7] * 20); } else if (poll_data_pid == 5) { batterySOH = ((rx_frame.data.u8[2] << 8) + rx_frame.data.u8[3]); } break; case 0x25: //Fifth datarow in PID group if (poll_data_pid == 2) { - cellvoltages[27] = (rx_frame.data.u8[1] * 20); - cellvoltages[28] = (rx_frame.data.u8[2] * 20); - cellvoltages[29] = (rx_frame.data.u8[3] * 20); - cellvoltages[30] = (rx_frame.data.u8[4] * 20); - cellvoltages[31] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[27] = (rx_frame.data.u8[1] * 20); + system_cellvoltages_mV[28] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[29] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[30] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[31] = (rx_frame.data.u8[5] * 20); } else if (poll_data_pid == 3) { - cellvoltages[59] = (rx_frame.data.u8[1] * 20); - cellvoltages[60] = (rx_frame.data.u8[2] * 20); - cellvoltages[61] = (rx_frame.data.u8[3] * 20); - cellvoltages[62] = (rx_frame.data.u8[4] * 20); - cellvoltages[63] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[59] = (rx_frame.data.u8[1] * 20); + system_cellvoltages_mV[60] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[61] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[62] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[63] = (rx_frame.data.u8[5] * 20); } else if (poll_data_pid == 4) { - cellvoltages[91] = (rx_frame.data.u8[1] * 20); - cellvoltages[92] = (rx_frame.data.u8[2] * 20); - cellvoltages[93] = (rx_frame.data.u8[3] * 20); - cellvoltages[94] = (rx_frame.data.u8[4] * 20); - cellvoltages[95] = (rx_frame.data.u8[5] * 20); + system_cellvoltages_mV[91] = (rx_frame.data.u8[1] * 20); + system_cellvoltages_mV[92] = (rx_frame.data.u8[2] * 20); + system_cellvoltages_mV[93] = (rx_frame.data.u8[3] * 20); + system_cellvoltages_mV[94] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[95] = (rx_frame.data.u8[5] * 20); } else if (poll_data_pid == 5) { - cellvoltages[96] = (rx_frame.data.u8[4] * 20); - cellvoltages[97] = (rx_frame.data.u8[5] * 20); - nof_cellvoltages = 98; + system_cellvoltages_mV[96] = (rx_frame.data.u8[4] * 20); + system_cellvoltages_mV[97] = (rx_frame.data.u8[5] * 20); + system_number_of_cells = 98; } break; case 0x26: //Sixth datarow in PID group @@ -591,19 +580,11 @@ void send_can_battery() { } } -uint16_t convertToUnsignedInt16(int16_t signed_value) { - if (signed_value < 0) { - return (65535 + signed_value); - } else { - return (uint16_t)signed_value; - } -} - void setup_battery(void) { // Performs one time setup at startup Serial.println("Kia Niro / Hyundai Kona 64kWh battery selected"); - max_voltage = 4040; // 404.0V, over this, charging is not possible (goes into forced discharge) - min_voltage = 3100; // 310.0V under this, discharging further is disabled + system_max_design_voltage_dV = 4040; // 404.0V, over this, charging is not possible (goes into forced discharge) + system_min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled } #endif diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h index 1df80166..0029b0f0 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h @@ -11,27 +11,28 @@ #define MAXDISCHARGEPOWERALLOWED 10000 // These parameters need to be mapped for the inverter -extern uint16_t max_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t min_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t SOC; //SOC%, 0-100.00 (0-10000) -extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000) -extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485) -extern uint16_t capacity_Wh; //Wh, 0-60000 -extern uint16_t remaining_capacity_Wh; //Wh, 0-60000 -extern uint16_t max_target_discharge_power; //W, 0-60000 -extern uint16_t max_target_charge_power; //W, 0-60000 -extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530) -extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t cell_max_voltage; //mV, 0-4350 -extern uint16_t cell_min_voltage; //mV, 0-4350 -extern uint16_t cellvoltages[120]; //mV 0-4350 per cell -extern uint8_t nof_cellvoltages; // Total number of cell voltages, set by each battery. -extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false -extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false +extern uint32_t system_capacity_Wh; //Wh, 0-150000Wh +extern uint32_t system_remaining_capacity_Wh; //Wh, 0-150000Wh +extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0 +extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0 +extern int16_t system_active_power_W; //W, -32000 to 32000 +extern int16_t system_battery_current_dA; //A+1, -1000 - 1000 +extern uint16_t system_battery_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_max_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_min_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000) +extern uint16_t system_max_discharge_power_W; //W, 0-65000 +extern uint16_t system_max_charge_power_W; //W, 0-65000 +extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value +extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value +extern uint16_t system_cellvoltages_mV[120]; //Array with all cell voltages in mV +extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery +extern uint8_t system_bms_status; //Enum 0-5 +extern bool batteryAllowsContactorClosing; //Bool, true/false +extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false -uint16_t convertToUnsignedInt16(int16_t signed_value); void setup_battery(void); #endif diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp index 08ef5499..746b6705 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -93,17 +93,14 @@ static uint8_t crctable[256] = { #define AZE0_BATTERY 1 #define ZE1_BATTERY 2 static uint8_t LEAF_Battery_Type = ZE0_BATTERY; -#define MAX_CELL_VOLTAGE 4250 //Battery is put into emergency stop if one cell goes over this value -#define MIN_CELL_VOLTAGE 2700 //Battery is put into emergency stop if one cell goes below this value -#define MAX_CELL_DEVIATION 500 //LED turns yellow on the board if mv delta exceeds this value -#define WH_PER_GID 77 //One GID is this amount of Watt hours -#define LB_MAX_SOC 1000 //LEAF BMS never goes over this value. We use this info to rescale SOC% sent to Fronius -#define LB_MIN_SOC 0 //LEAF BMS never goes below this value. We use this info to rescale SOC% sent to Fronius +#define MAX_CELL_VOLTAGE 4250 //Battery is put into emergency stop if one cell goes over this value +#define MIN_CELL_VOLTAGE 2700 //Battery is put into emergency stop if one cell goes below this value +#define MAX_CELL_DEVIATION 500 //LED turns yellow on the board if mv delta exceeds this value +#define WH_PER_GID 77 //One GID is this amount of Watt hours static uint16_t LB_Discharge_Power_Limit = 0; //Limit in kW static uint16_t LB_Charge_Power_Limit = 0; //Limit in kW static int16_t LB_MAX_POWER_FOR_CHARGER = 0; //Limit in kW static int16_t LB_SOC = 500; //0 - 100.0 % (0-1000) The real SOC% in the battery -static int16_t CalculatedSOC = 0; // Temporary value used for calculating SOC static uint16_t LB_TEMP = 0; //Temporary value used in status checks static uint16_t LB_Wh_Remaining = 0; //Amount of energy in battery, in Wh static uint16_t LB_GIDS = 273; //Startup in 24kWh mode @@ -170,94 +167,84 @@ void print_with_units(char* header, int value, char* units) { void update_values_battery() { /* This function maps all the values fetched via CAN to the correct parameters used for modbus */ /* Start with mapping all values */ - StateOfHealth = (LB_StateOfHealth * 100); //Increase range from 99% -> 99.00% + system_SOH_pptt = (LB_StateOfHealth * 100); //Increase range from 99% -> 99.00% - //Calculate the SOC% value to send to Fronius - CalculatedSOC = LB_SOC; - CalculatedSOC = - LB_MIN_SOC + (LB_MAX_SOC - LB_MIN_SOC) * (CalculatedSOC - MINPERCENTAGE) / (MAXPERCENTAGE - MINPERCENTAGE); - if (CalculatedSOC < 0) { //We are in the real SOC% range of 0-20%, always set SOC sent to Fronius as 0% - CalculatedSOC = 0; - } - if (CalculatedSOC > 1000) { //We are in the real SOC% range of 80-100%, always set SOC sent to Fronius as 100% - CalculatedSOC = 1000; - } - SOC = (CalculatedSOC * 10); //increase CalculatedSOC range from 0-100.0 -> 100.00 + system_real_SOC_pptt = (LB_SOC * 10); - battery_voltage = (LB_Total_Voltage2 * 5); //0.5V /bit, multiply by 5 to get Voltage+1decimal (350.5V = 701) + system_battery_voltage_dV = (LB_Total_Voltage2 * 5); //0.5V/bit, multiply by 5 to get Voltage+1decimal (350.5V = 701) - battery_current = convert2unsignedint16((LB_Current2 * 5)); //0.5A/bit, multiply by 5 to get Amp+1decimal (5,5A = 11) + system_battery_current_dA = (LB_Current2 * 5); //0.5A/bit, multiply by 5 to get Amp+1decimal (5,5A = 11) - capacity_Wh = (LB_Max_GIDS * WH_PER_GID); + system_capacity_Wh = (LB_Max_GIDS * WH_PER_GID); - remaining_capacity_Wh = LB_Wh_Remaining; + system_remaining_capacity_Wh = LB_Wh_Remaining; LB_Power = ((LB_Total_Voltage2 * LB_Current2) / 4); //P = U * I (Both values are 0.5 per bit so the math is non-intuitive) - stat_batt_power = convert2unsignedint16(LB_Power); //add sign if needed + + system_active_power_W = LB_Power; //Update temperature readings. Method depends on which generation LEAF battery is used if (LEAF_Battery_Type == ZE0_BATTERY) { //Since we only have average value, send the minimum as -1.0 degrees below average - temperature_min = - convert2unsignedint16((LB_AverageTemperature * 10) - 10); //add sign if negative and increase range - temperature_max = convert2unsignedint16((LB_AverageTemperature * 10)); + system_temperature_min_dC = ((LB_AverageTemperature * 10) - 10); //Increase range from C to C+1, remove 1.0C + system_temperature_max_dC = (LB_AverageTemperature * 10); //Increase range from C to C+1 } else if (LEAF_Battery_Type == AZE0_BATTERY) { //Use the value sent constantly via CAN in 5C0 (only available on AZE0) - temperature_min = - convert2unsignedint16((LB_HistData_Temperature_MIN * 10)); //add sign if negative and increase range - temperature_max = convert2unsignedint16((LB_HistData_Temperature_MAX * 10)); + system_temperature_min_dC = (LB_HistData_Temperature_MIN * 10); //Increase range from C to C+1 + system_temperature_max_dC = (LB_HistData_Temperature_MAX * 10); //Increase range from C to C+1 } else { // ZE1 (TODO: Once the muxed value in 5C0 becomes known, switch to using that instead of this complicated polled value) if (temp_raw_min != 0) //We have a polled value available { temp_polled_min = ((Temp_fromRAW_to_F(temp_raw_min) - 320) * 5) / 9; //Convert from F to C temp_polled_max = ((Temp_fromRAW_to_F(temp_raw_max) - 320) * 5) / 9; //Convert from F to C if (temp_polled_min < temp_polled_max) { //Catch any edge cases from Temp_fromRAW_to_F function - temperature_min = convert2unsignedint16((temp_polled_min)); - temperature_max = convert2unsignedint16((temp_polled_max)); + system_temperature_min_dC = temp_polled_min; + system_temperature_max_dC = temp_polled_max; } else { - temperature_min = convert2unsignedint16((temp_polled_max)); - temperature_max = convert2unsignedint16((temp_polled_min)); + system_temperature_min_dC = temp_polled_max; + system_temperature_max_dC = temp_polled_min; } } } // Define power able to be discharged from battery - if (LB_Discharge_Power_Limit > 30) { //if >30kW can be pulled from battery - max_target_discharge_power = 30000; //cap value so we don't go over the Fronius limits + if (LB_Discharge_Power_Limit > 60) { //if >60kW can be pulled from battery + system_max_discharge_power_W = 60000; //cap value so we don't go over uint16 value } else { - max_target_discharge_power = (LB_Discharge_Power_Limit * 1000); //kW to W + system_max_discharge_power_W = (LB_Discharge_Power_Limit * 1000); //kW to W } - if (SOC == 0) { //Scaled SOC% value is 0.00%, we should not discharge battery further - max_target_discharge_power = 0; + if (system_scaled_SOC_pptt == 0) { //Scaled SOC% value is 0.00%, we should not discharge battery further + system_max_discharge_power_W = 0; } // Define power able to be put into the battery - if (LB_Charge_Power_Limit > 30) { //if >30kW can be put into the battery - max_target_charge_power = 30000; //cap value so we don't go over the Fronius limits + if (LB_Charge_Power_Limit > 60) { //if >60kW can be put into the battery + system_max_charge_power_W = 60000; //cap value so we don't go over uint16 value } else { - max_target_charge_power = (LB_Charge_Power_Limit * 1000); //kW to W + system_max_charge_power_W = (LB_Charge_Power_Limit * 1000); //kW to W } - if (SOC == 10000) //Scaled SOC% value is 100.00% + if (system_scaled_SOC_pptt == 10000) //Scaled SOC% value is 100.00% { - max_target_charge_power = 0; //No need to charge further, set max power to 0 + system_max_charge_power_W = 0; //No need to charge further, set max power to 0 } //Map all cell voltages to the global array for (int i = 0; i < 96; ++i) { - cellvoltages[i] = cell_voltages[i]; + system_cellvoltages_mV[i] = cell_voltages[i]; } /*Extra safety functions below*/ - if (LB_GIDS < 6) //500Wh left in battery - { //Battery is running abnormally low, some discharge logic might have failed. Zero it all out. + if (LB_GIDS < 10) //700Wh left in battery! + { //Battery is running abnormally low, some discharge logic might have failed. Zero it all out. set_event(EVENT_BATTERY_EMPTY, 0); - SOC = 0; - max_target_discharge_power = 0; + system_real_SOC_pptt = 0; + system_max_discharge_power_W = 0; } //Check if SOC% is plausible - if (battery_voltage > (max_voltage - 100)) { // When pack voltage is close to max, and SOC% is still low, raise FAULT + if (system_battery_voltage_dV > + (system_max_design_voltage_dV - 100)) { // When pack voltage is close to max, and SOC% is still low, raise FAULT if (LB_SOC < 650) { set_event(EVENT_SOC_PLAUSIBILITY_ERROR, LB_SOC / 10); // Set event with the SOC as data } else { @@ -267,14 +254,14 @@ void update_values_battery() { /* This function maps all the values fetched via if (LB_Full_CHARGE_flag) { //Battery reports that it is fully charged stop all further charging incase it hasn't already set_event(EVENT_BATTERY_FULL, 0); - max_target_charge_power = 0; + system_max_charge_power_W = 0; } else { clear_event(EVENT_BATTERY_FULL); } if (LB_Capacity_Empty) { //Battery reports that it is fully discharged. Stop all further discharging incase it hasn't already set_event(EVENT_BATTERY_EMPTY, 0); - max_target_discharge_power = 0; + system_max_discharge_power_W = 0; } else { clear_event(EVENT_BATTERY_EMPTY); } @@ -285,8 +272,8 @@ void update_values_battery() { /* This function maps all the values fetched via #endif //Note, this is sometimes triggered during the night while idle, and the BMS recovers after a while. Removed latching from this scenario errorCode = 1; - max_target_discharge_power = 0; - max_target_charge_power = 0; + system_max_discharge_power_W = 0; + system_max_charge_power_W = 0; } if (LB_Failsafe_Status > 0) // 0 is normal, start charging/discharging @@ -367,9 +354,9 @@ void update_values_battery() { /* This function maps all the values fetched via set_event(EVENT_CAN_RX_WARNING, 0); } - if (bms_status == FAULT) { //Incase we enter a critical fault state, zero out the allowed limits - max_target_charge_power = 0; - max_target_discharge_power = 0; + if (system_bms_status == FAULT) { //Incase we enter a critical fault state, zero out the allowed limits + system_max_charge_power_W = 0; + system_max_discharge_power_W = 0; } /*Finally print out values to serial if configured to do so*/ @@ -379,16 +366,16 @@ void update_values_battery() { /* This function maps all the values fetched via Serial.println(errorCode); } Serial.println("Values going to inverter"); - print_with_units("SOH%: ", (StateOfHealth * 0.01), "% "); - print_with_units(", SOC% scaled: ", (SOC * 0.01), "% "); - print_with_units(", Voltage: ", (battery_voltage * 0.1), "V "); - print_with_units(", Max discharge power: ", max_target_discharge_power, "W "); - print_with_units(", Max charge power: ", max_target_charge_power, "W "); - print_with_units(", Max temp: ", ((int16_t)temperature_max * 0.1), "°C "); - print_with_units(", Min temp: ", ((int16_t)temperature_min * 0.1), "°C "); + print_with_units("SOH%: ", (system_SOH_pptt * 0.01), "% "); + print_with_units(", SOC% scaled: ", (system_scaled_SOC_pptt * 0.01), "% "); + print_with_units(", Voltage: ", (system_battery_voltage_dV * 0.1), "V "); + print_with_units(", Max discharge power: ", system_max_discharge_power_W, "W "); + print_with_units(", Max charge power: ", system_max_charge_power_W, "W "); + print_with_units(", Max temp: ", (system_temperature_max_dC * 0.1), "°C "); + print_with_units(", Min temp: ", (system_temperature_min_dC * 0.1), "°C "); Serial.println(""); Serial.print("BMS Status: "); - if (bms_status == 3) { + if (system_bms_status == 3) { Serial.print("Active, "); } else { Serial.print("FAULT, "); @@ -584,8 +571,8 @@ void receive_can_battery(CAN_frame_t rx_frame) { cell_deviation_mV = (min_max_voltage[1] - min_max_voltage[0]); - cell_max_voltage = min_max_voltage[1]; - cell_min_voltage = min_max_voltage[0]; + system_cell_max_voltage_mV = min_max_voltage[1]; + system_cell_min_voltage_mV = min_max_voltage[0]; if (cell_deviation_mV > MAX_CELL_DEVIATION) { set_event(EVENT_CELL_DEVIATION_HIGH, 0); @@ -861,14 +848,6 @@ void send_can_battery() { } } -uint16_t convert2unsignedint16(int16_t signed_value) { - if (signed_value < 0) { - return (65535 + signed_value); - } else { - return (uint16_t)signed_value; - } -} - bool is_message_corrupt(CAN_frame_t rx_frame) { uint8_t crc = 0; for (uint8_t j = 0; j < 7; j++) { @@ -911,9 +890,9 @@ uint16_t Temp_fromRAW_to_F(uint16_t temperature) { //This function feels horrib void setup_battery(void) { // Performs one time setup at startup Serial.println("Nissan LEAF battery selected"); - nof_cellvoltages = 96; - max_voltage = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge) - min_voltage = 2450; // 245.0V under this, discharging further is disabled + system_number_of_cells = 96; + system_max_design_voltage_dV = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge) + system_min_design_voltage_dV = 2600; // 260.0V under this, discharging further is disabled } #endif diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.h b/Software/src/battery/NISSAN-LEAF-BATTERY.h index 1d3ad7d1..d437ed73 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.h +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.h @@ -8,26 +8,27 @@ #define BATTERY_SELECTED // These parameters need to be mapped for the inverter -extern uint16_t max_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t min_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t SOC; //SOC%, 0-100.00 (0-10000) -extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000) -extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485) -extern uint16_t capacity_Wh; //Wh, 0-60000 -extern uint16_t remaining_capacity_Wh; //Wh, 0-60000 -extern uint16_t max_target_discharge_power; //W, 0-60000 -extern uint16_t max_target_charge_power; //W, 0-60000 -extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530) -extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t cell_max_voltage; //mV, 0-4350 -extern uint16_t cell_min_voltage; //mV, 0-4350 -extern uint16_t cellvoltages[120]; //mV 0-4350 per cell -extern uint8_t nof_cellvoltages; // Total number of cell voltages, set by each battery. -extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false +extern uint32_t system_capacity_Wh; //Wh, 0-150000Wh +extern uint32_t system_remaining_capacity_Wh; //Wh, 0-150000Wh +extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0 +extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0 +extern int16_t system_active_power_W; //W, -32000 to 32000 +extern int16_t system_battery_current_dA; //A+1, -1000 - 1000 +extern uint16_t system_battery_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_max_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_min_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000) +extern uint16_t system_max_discharge_power_W; //W, 0-65000 +extern uint16_t system_max_charge_power_W; //W, 0-65000 +extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value +extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value +extern uint16_t system_cellvoltages_mV[120]; //Array with all cell voltages in mV +extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery +extern uint8_t system_bms_status; //Enum 0-5 +extern bool batteryAllowsContactorClosing; //Bool, true/false -uint16_t convert2unsignedint16(int16_t signed_value); uint16_t Temp_fromRAW_to_F(uint16_t temperature); bool is_message_corrupt(CAN_frame_t rx_frame); void setup_battery(void); diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp index eee07cb8..36a3be3a 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp @@ -6,16 +6,12 @@ #include "RENAULT-KANGOO-BATTERY.h" /* Do not change code below unless you are sure what you are doing */ -#define LB_MAX_SOC 1000 //BMS never goes over this value. We use this info to rescale SOC% sent to Fronius -#define LB_MIN_SOC 0 //BMS never goes below this value. We use this info to rescale SOC% sent to Fronius - static uint32_t LB_Battery_Voltage = 3700; static uint32_t LB_Charge_Power_Limit_Watts = 0; static uint32_t LB_Discharge_Power_Limit_Watts = 0; static int32_t LB_Current = 0; static int16_t LB_MAX_TEMPERATURE = 0; static int16_t LB_MIN_TEMPERATURE = 0; -static uint16_t soc_calculated = 0; static uint16_t LB_SOC = 0; static uint16_t LB_SOH = 0; static uint16_t LB_Discharge_Power_Limit = 0; @@ -60,68 +56,56 @@ static const int interval100 = 100; // interval (ms) at which send CAN Messag static const int interval1000 = 1000; // interval (ms) at which send CAN Messages void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus - StateOfHealth = (LB_SOH * 100); //Increase range from 99% -> 99.00% - //Calculate the SOC% value to send to Fronius - soc_calculated = LB_SOC; - soc_calculated = - LB_MIN_SOC + (LB_MAX_SOC - LB_MIN_SOC) * (soc_calculated - MINPERCENTAGE) / (MAXPERCENTAGE - MINPERCENTAGE); - if (soc_calculated < 0) { //We are in the real SOC% range of 0-20%, always set SOC sent to Inverter as 0% - soc_calculated = 0; - } - if (soc_calculated > 1000) { //We are in the real SOC% range of 80-100%, always set SOC sent to Inverter as 100% - soc_calculated = 1000; - } - SOC = (soc_calculated * 10); //increase LB_SOC range from 0-100.0 -> 100.00 + system_real_SOC_pptt = (LB_SOC * 10); //increase LB_SOC range from 0-100.0 -> 100.00 - battery_voltage = LB_Battery_Voltage; + system_SOH_pptt = (LB_SOH * 100); //Increase range from 99% -> 99.00% - battery_current = LB_Current; + system_battery_voltage_dV = LB_Battery_Voltage; - capacity_Wh = BATTERY_WH_MAX; //Hardcoded to header value + system_battery_current_dA = LB_Current; - remaining_capacity_Wh = (uint16_t)((SOC / 10000) * capacity_Wh); + system_capacity_Wh = BATTERY_WH_MAX; //Hardcoded to header value + + system_remaining_capacity_Wh = (uint16_t)((system_real_SOC_pptt / 10000) * system_capacity_Wh); LB_Discharge_Power_Limit_Watts = (LB_Discharge_Power_Limit * 500); //Convert value fetched from battery to watts /* Define power able to be discharged from battery */ - if (LB_Discharge_Power_Limit_Watts > 30000) //if >30kW can be pulled from battery + if (LB_Discharge_Power_Limit_Watts > 60000) //if >60kW can be pulled from battery { - max_target_discharge_power = 30000; //cap value so we don't go over the Fronius limits + system_max_discharge_power_W = 60000; //cap value so we don't go over the uint16 limit } else { - max_target_discharge_power = LB_Discharge_Power_Limit_Watts; + system_max_discharge_power_W = LB_Discharge_Power_Limit_Watts; } - if (SOC == 0) //Scaled SOC% value is 0.00%, we should not discharge battery further + if (system_scaled_SOC_pptt == 0) //Scaled SOC% value is 0.00%, we should not discharge battery further { - max_target_discharge_power = 0; + system_max_discharge_power_W = 0; } LB_Charge_Power_Limit_Watts = (LB_Charge_Power_Limit * 500); //Convert value fetched from battery to watts /* Define power able to be put into the battery */ - if (LB_Charge_Power_Limit_Watts > 30000) //if >30kW can be put into the battery + if (LB_Charge_Power_Limit_Watts > 60000) //if >60kW can be put into the battery { - max_target_charge_power = 30000; //cap value so we don't go over the Fronius limits - } - if (LB_Charge_Power_Limit_Watts < 0) { - max_target_charge_power = 0; //cap calue so we dont do under the Fronius limits + system_max_charge_power_W = 60000; //cap value so we don't go over the uint16 limit } else { - max_target_charge_power = LB_Charge_Power_Limit_Watts; + system_max_charge_power_W = LB_Charge_Power_Limit_Watts; } - if (SOC == 10000) //Scaled SOC% value is 100.00% + if (system_scaled_SOC_pptt == 10000) //Scaled SOC% value is 100.00% { - max_target_charge_power = 0; //No need to charge further, set max power to 0 + system_max_charge_power_W = 0; //No need to charge further, set max power to 0 } - stat_batt_power = (battery_voltage * LB_Current); //TODO: check if scaling is OK + system_active_power_W = (system_battery_voltage_dV * LB_Current); //TODO: check if scaling is OK - temperature_min = convert2uint16(LB_MIN_TEMPERATURE * 10); + system_temperature_min_dC = (LB_MIN_TEMPERATURE * 10); - temperature_max = convert2uint16(LB_MAX_TEMPERATURE * 10); + system_temperature_max_dC = (LB_MAX_TEMPERATURE * 10); - cell_min_voltage = LB_Cell_Min_Voltage; + system_cell_min_voltage_mV = LB_Cell_Min_Voltage; - cell_max_voltage = LB_Cell_Max_Voltage; + system_cell_max_voltage_mV = LB_Cell_Max_Voltage; - cell_deviation_mV = (cell_max_voltage - cell_min_voltage); + cell_deviation_mV = (system_temperature_max_dC - system_temperature_min_dC); /* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/ if (!CANstillAlive) { @@ -146,21 +130,21 @@ void update_values_battery() { //This function maps all the values fetched via #ifdef DEBUG_VIA_USB Serial.println("Values going to inverter:"); Serial.print("SOH%: "); - Serial.print(StateOfHealth); + Serial.print(system_SOH_pptt); Serial.print(", SOC% scaled: "); - Serial.print(SOC); + Serial.print(system_scaled_SOC_pptt); Serial.print(", Voltage: "); - Serial.print(battery_voltage); + Serial.print(system_battery_voltage_dV); Serial.print(", Max discharge power: "); - Serial.print(max_target_discharge_power); + Serial.print(system_max_discharge_power_W); Serial.print(", Max charge power: "); - Serial.print(max_target_charge_power); + Serial.print(system_max_charge_power_W); Serial.print(", Max temp: "); - Serial.print(temperature_max); + Serial.print(system_temperature_max_dC); Serial.print(", Min temp: "); - Serial.print(temperature_min); + Serial.print(system_temperature_min_dC); Serial.print(", BMS Status (3=OK): "); - Serial.print(bms_status); + Serial.print(system_bms_status); Serial.println("Battery values: "); Serial.print("Real SOC: "); @@ -230,7 +214,7 @@ void receive_can_battery(CAN_frame_t rx_frame) //GKOE reworked } if (rx_frame.data.u8[0] == 0x24) { //5th response Bytes 24-31 LB_Discharge_Power_Limit = word(LB_Discharge_Power_Limit_Byte1, rx_frame.data.u8[1]) * 100; //OK! - LB_Battery_Voltage = word(rx_frame.data.u8[2], rx_frame.data.u8[3]) * 10; //OK! + LB_Battery_Voltage = word(rx_frame.data.u8[2], rx_frame.data.u8[3]) / 10; //OK! GVB_79B_Continue = false; } break; @@ -262,19 +246,11 @@ void send_can_battery() { } } -uint16_t convert2uint16(int16_t signed_value) { - if (signed_value < 0) { - return (65535 + signed_value); - } else { - return (uint16_t)signed_value; - } -} - void setup_battery(void) { // Performs one time setup at startup Serial.println("Renault Kangoo battery selected"); - max_voltage = 4040; // 404.0V, over this, charging is not possible (goes into forced discharge) - min_voltage = 3100; // 310.0V under this, discharging further is disabled + system_max_design_voltage_dV = 4040; // 404.0V, over this, charging is not possible (goes into forced discharge) + system_min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled } #endif diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.h b/Software/src/battery/RENAULT-KANGOO-BATTERY.h index 593811d9..69e3f207 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.h +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.h @@ -14,26 +14,28 @@ #define MAX_CELL_DEVIATION_MV 500 //LED turns yellow on the board if mv delta exceeds this value // These parameters need to be mapped for the inverter -extern uint16_t max_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t min_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t SOC; //SOC%, 0-100.00 (0-10000) -extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000) -extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485) -extern uint16_t capacity_Wh; //Wh, 0-60000 -extern uint16_t remaining_capacity_Wh; //Wh, 0-60000 -extern uint16_t max_target_discharge_power; //W, 0-60000 -extern uint16_t max_target_charge_power; //W, 0-60000 -extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530) -extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t cell_max_voltage; //mV, 0-4350 -extern uint16_t cell_min_voltage; //mV, 0-4350 -extern uint16_t CANerror; -extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false -extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false +extern uint32_t system_capacity_Wh; //Wh, 0-150000Wh +extern uint32_t system_remaining_capacity_Wh; //Wh, 0-150000Wh +extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0 +extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0 +extern int16_t system_active_power_W; //W, -32000 to 32000 +extern int16_t system_battery_current_dA; //A+1, -1000 - 1000 +extern uint16_t system_battery_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_max_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_min_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000) +extern uint16_t system_max_discharge_power_W; //W, 0-65000 +extern uint16_t system_max_charge_power_W; //W, 0-65000 +extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value +extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value +extern uint16_t system_cellvoltages_mV[120]; //Array with all cell voltages in mV +extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery +extern uint8_t system_bms_status; //Enum 0-5 +extern bool batteryAllowsContactorClosing; //Bool, true/false +extern bool inverterAllowsContactorClosing; //Bool, true/false -uint16_t convert2uint16(int16_t signed_value); void setup_battery(void); #endif diff --git a/Software/src/battery/RENAULT-ZOE-BATTERY.cpp b/Software/src/battery/RENAULT-ZOE-BATTERY.cpp index 1c718077..0aa0100a 100644 --- a/Software/src/battery/RENAULT-ZOE-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-BATTERY.cpp @@ -6,13 +6,9 @@ #include "RENAULT-ZOE-BATTERY.h" /* Do not change code below unless you are sure what you are doing */ -#define LB_MAX_SOC 1000 //BMS never goes over this value. We use this info to rescale SOC% sent to Fronius -#define LB_MIN_SOC 0 //BMS never goes below this value. We use this info to rescale SOC% sent to Fronius - static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive static uint8_t errorCode = 0; //stores if we have an error code active from battery control logic static uint16_t LB_SOC = 50; -static uint16_t soc_calculated = 0; static uint16_t LB_SOH = 99; static int16_t LB_MIN_TEMPERATURE = 0; static int16_t LB_MAX_TEMPERATURE = 0; @@ -45,44 +41,34 @@ static const int interval100 = 100; // interval (ms) at which send CAN Messag static const int interval1000 = 1000; // interval (ms) at which send CAN Messages void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus - StateOfHealth = (LB_SOH * 100); //Increase range from 99% -> 99.00% + system_SOH_pptt = (LB_SOH * 100); //Increase range from 99% -> 99.00% - //Calculate the SOC% value to send to Fronius - soc_calculated = LB_SOC; - soc_calculated = - LB_MIN_SOC + (LB_MAX_SOC - LB_MIN_SOC) * (soc_calculated - MINPERCENTAGE) / (MAXPERCENTAGE - MINPERCENTAGE); - if (soc_calculated < 0) { //We are in the real SOC% range of 0-20%, always set SOC sent to Inverter as 0% - soc_calculated = 0; - } - if (soc_calculated > 1000) { //We are in the real SOC% range of 80-100%, always set SOC sent to Inverter as 100% - soc_calculated = 1000; - } - SOC = (soc_calculated * 10); //increase LB_SOC range from 0-100.0 -> 100.00 + system_real_SOC_pptt = (LB_SOC * 10); //increase LB_SOC range from 0-100.0 -> 100.00 - battery_voltage = LB_Battery_Voltage; + system_battery_voltage_dV = LB_Battery_Voltage; - battery_current = LB_Current; + system_battery_current_dA = LB_Current; - capacity_Wh = BATTERY_WH_MAX; //Use the configured value to avoid overflows + system_capacity_Wh = BATTERY_WH_MAX; //Use the configured value to avoid overflows //Calculate the remaining Wh amount from SOC% and max Wh value. - remaining_capacity_Wh = static_cast((static_cast(SOC) / 10000) * BATTERY_WH_MAX); + system_remaining_capacity_Wh = static_cast((static_cast(system_real_SOC_pptt) / 10000) * BATTERY_WH_MAX); - max_target_discharge_power; + system_max_discharge_power_W; - max_target_charge_power; + system_max_charge_power_W; - stat_batt_power; + system_active_power_W; - temperature_min; + system_temperature_min_dC; - temperature_max; + system_temperature_max_dC; - cell_min_voltage; + system_cell_min_voltage_mV; - cell_max_voltage; + system_cell_max_voltage_mV; - cell_deviation_mV = (cell_max_voltage - cell_min_voltage); + cell_deviation_mV = (system_cell_max_voltage_mV - system_cell_min_voltage_mV); /* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/ if (!CANstillAlive) { @@ -107,21 +93,21 @@ void update_values_battery() { //This function maps all the values fetched via #ifdef DEBUG_VIA_USB Serial.println("Values going to inverter:"); Serial.print("SOH%: "); - Serial.print(StateOfHealth); + Serial.print(system_SOH_pptt); Serial.print(", SOC% scaled: "); - Serial.print(SOC); + Serial.print(system_scaled_SOC_pptt); Serial.print(", Voltage: "); - Serial.print(battery_voltage); + Serial.print(system_battery_voltage_dV); Serial.print(", Max discharge power: "); - Serial.print(max_target_discharge_power); + Serial.print(system_max_discharge_power_W); Serial.print(", Max charge power: "); - Serial.print(max_target_charge_power); + Serial.print(system_max_charge_power_W); Serial.print(", Max temp: "); - Serial.print(temperature_max); + Serial.print(system_temperature_max_dC); Serial.print(", Min temp: "); - Serial.print(temperature_min); + Serial.print(system_temperature_min_dC); Serial.print(", BMS Status (3=OK): "); - Serial.print(bms_status); + Serial.print(system_bms_status); Serial.println("Battery values: "); Serial.print("Real SOC: "); @@ -169,8 +155,8 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup Serial.println("Renault Zoe battery selected"); - max_voltage = 4040; // 404.0V, over this, charging is not possible (goes into forced discharge) - min_voltage = 3100; // 310.0V under this, discharging further is disabled + system_max_design_voltage_dV = 4040; // 404.0V, over this, charging is not possible (goes into forced discharge) + system_min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled } #endif diff --git a/Software/src/battery/RENAULT-ZOE-BATTERY.h b/Software/src/battery/RENAULT-ZOE-BATTERY.h index b5eef243..853e9b42 100644 --- a/Software/src/battery/RENAULT-ZOE-BATTERY.h +++ b/Software/src/battery/RENAULT-ZOE-BATTERY.h @@ -14,24 +14,27 @@ #define MAX_CELL_DEVIATION_MV 500 //LED turns yellow on the board if mv delta exceeds this value // These parameters need to be mapped for the inverter -extern uint16_t max_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t min_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t SOC; //SOC%, 0-100.00 (0-10000) -extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000) -extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485) -extern uint16_t capacity_Wh; //Wh, 0-60000 -extern uint16_t remaining_capacity_Wh; //Wh, 0-60000 -extern uint16_t max_target_discharge_power; //W, 0-60000 -extern uint16_t max_target_charge_power; //W, 0-60000 -extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530) -extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t cell_max_voltage; //mV, 0-4350 -extern uint16_t cell_min_voltage; //mV, 0-4350 -extern uint16_t CANerror; -extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false -extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false +extern uint32_t system_capacity_Wh; //Wh, 0-150000Wh +extern uint32_t system_remaining_capacity_Wh; //Wh, 0-150000Wh +extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0 +extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0 +extern int16_t system_active_power_W; //W, -32000 to 32000 +extern int16_t system_battery_current_dA; //A+1, -1000 - 1000 +extern uint16_t system_battery_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_max_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_min_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000) +extern uint16_t system_max_discharge_power_W; //W, 0-65000 +extern uint16_t system_max_charge_power_W; //W, 0-65000 +extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value +extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value +extern uint16_t system_cellvoltages_mV[120]; //Array with all cell voltages in mV +extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery +extern uint8_t system_bms_status; //Enum 0-5 +extern bool batteryAllowsContactorClosing; //Bool, true/false +extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false void setup_battery(void); diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp index f6717089..8458d55a 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp @@ -21,9 +21,6 @@ static const int interval10 = 10; // interval (ms) at which send CAN static const int interval100 = 100; // interval (ms) at which send CAN Messages static uint8_t CANstillAlive = 12; //counter for checking if CAN is still alive -#define LB_MAX_SOC 1000 //BMS never goes over this value. We use this info to rescale SOC% sent to Inverter -#define LB_MIN_SOC 0 //BMS never goes below this value. We use this info to rescale SOC% sent to Inverter - static int SOC_1 = 0; static int SOC_2 = 0; static int SOC_3 = 0; @@ -61,25 +58,25 @@ CAN_frame_t SANTAFE_523 = {.FIR = {.B = void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus - SOC; + system_real_SOC_pptt; - battery_voltage; + system_battery_voltage_dV; - battery_current; + system_battery_current_dA; - capacity_Wh = BATTERY_WH_MAX; + system_capacity_Wh = BATTERY_WH_MAX; - remaining_capacity_Wh; + system_remaining_capacity_Wh; - max_target_discharge_power; + system_max_discharge_power_W; - max_target_charge_power; + system_max_charge_power_W; - stat_batt_power; + system_active_power_W; - temperature_min; + system_temperature_min_dC; - temperature_max; + system_temperature_max_dC; /* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/ if (!CANstillAlive) { @@ -180,8 +177,8 @@ uint8_t CalculateCRC8(CAN_frame_t rx_frame) { void setup_battery(void) { // Performs one time setup at startup Serial.println("Hyundai Santa Fe PHEV battery selected"); - max_voltage = 4040; // 404.0V, over this, charging is not possible (goes into forced discharge) - min_voltage = 3100; // 310.0V under this, discharging further is disabled + system_max_design_voltage_dV = 4040; // 404.0V, over this, charging is not possible (goes into forced discharge) + system_min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled } #endif diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.h b/Software/src/battery/SANTA-FE-PHEV-BATTERY.h index ff136a48..da01cda1 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.h +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.h @@ -7,24 +7,27 @@ #define BATTERY_SELECTED -extern uint16_t max_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t min_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t SOC; //SOC%, 0-100.00 (0-10000) -extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000) -extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485) -extern uint16_t capacity_Wh; //Wh, 0-60000 -extern uint16_t remaining_capacity_Wh; //Wh, 0-60000 -extern uint16_t max_target_discharge_power; //W, 0-60000 -extern uint16_t max_target_charge_power; //W, 0-60000 -extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530) -extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t cell_max_voltage; //mV, 0-4350 -extern uint16_t cell_min_voltage; //mV, 0-4350 -extern uint16_t cellvoltages[120]; //mV 0-4350 per cell -extern uint8_t nof_cellvoltages; // Total number of cell voltages, set by each battery. -extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false +// These parameters need to be mapped for the inverter +extern uint32_t system_capacity_Wh; //Wh, 0-150000Wh +extern uint32_t system_remaining_capacity_Wh; //Wh, 0-150000Wh +extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0 +extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0 +extern int16_t system_active_power_W; //W, -32000 to 32000 +extern int16_t system_battery_current_dA; //A+1, -1000 - 1000 +extern uint16_t system_battery_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_max_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_min_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000) +extern uint16_t system_max_discharge_power_W; //W, 0-65000 +extern uint16_t system_max_charge_power_W; //W, 0-65000 +extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value +extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value +extern uint16_t system_cellvoltages_mV[120]; //Array with all cell voltages in mV +extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery +extern uint8_t system_bms_status; //Enum 0-5 +extern bool batteryAllowsContactorClosing; //Bool, true/false uint8_t CalculateCRC8(CAN_frame_t rx_frame); void setup_battery(void); diff --git a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp index 687776ff..8e6e5dc7 100644 --- a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp +++ b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp @@ -1,8 +1,8 @@ -// SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp - -#include "SERIAL-LINK-RECEIVER-FROM-BATTERY.h" +#include "BATTERIES.h" +#ifdef SERIAL_LINK_RECEIVER #include #include "../devboard/utils/events.h" +#include "SERIAL-LINK-RECEIVER-FROM-BATTERY.h" #define INVERTER_SEND_NUM_VARIABLES 1 #define INVERTER_RECV_NUM_VARIABLES 16 @@ -28,25 +28,25 @@ SerialDataLink dataLinkReceive(SerialReceiver, 0, 0x01, sendingNumVariables, static bool batteryFault = false; // used locally - mainly to indicate Battery CAN failure void __getData() { - SOC = (uint16_t)dataLinkReceive.getReceivedData(0); - StateOfHealth = (uint16_t)dataLinkReceive.getReceivedData(1); - battery_voltage = (uint16_t)dataLinkReceive.getReceivedData(2); - battery_current = (uint16_t)dataLinkReceive.getReceivedData(3); - capacity_Wh = (uint16_t)dataLinkReceive.getReceivedData(4); - remaining_capacity_Wh = (uint16_t)dataLinkReceive.getReceivedData(5); - max_target_discharge_power = (uint16_t)dataLinkReceive.getReceivedData(6); - max_target_charge_power = (uint16_t)dataLinkReceive.getReceivedData(7); - uint16_t _bms_status = (uint16_t)dataLinkReceive.getReceivedData(8); - stat_batt_power = (uint16_t)dataLinkReceive.getReceivedData(9); - temperature_min = (uint16_t)dataLinkReceive.getReceivedData(10); - temperature_max = (uint16_t)dataLinkReceive.getReceivedData(11); - cell_max_voltage = (uint16_t)dataLinkReceive.getReceivedData(12); - cell_min_voltage = (uint16_t)dataLinkReceive.getReceivedData(13); - LFP_Chemistry = (bool)dataLinkReceive.getReceivedData(14); - batteryAllowsContactorClosing = (uint16_t)dataLinkReceive.getReceivedData(15); + system_real_SOC_pptt = (uint16_t)dataLinkReceive.getReceivedData(0); + system_SOH_pptt = (uint16_t)dataLinkReceive.getReceivedData(1); + system_battery_voltage_dV = (uint16_t)dataLinkReceive.getReceivedData(2); + system_battery_current_dA = (int16_t)dataLinkReceive.getReceivedData(3); + system_capacity_Wh = (uint32_t)dataLinkReceive.getReceivedData(4); + system_remaining_capacity_Wh = (uint32_t)dataLinkReceive.getReceivedData(5); + system_max_discharge_power_W = (uint16_t)dataLinkReceive.getReceivedData(6); + system_max_charge_power_W = (uint16_t)dataLinkReceive.getReceivedData(7); + uint16_t _system_bms_status = (uint16_t)dataLinkReceive.getReceivedData(8); + system_active_power_W = (uint16_t)dataLinkReceive.getReceivedData(9); + system_temperature_min_dC = (int16_t)dataLinkReceive.getReceivedData(10); + system_temperature_max_dC = (int16_t)dataLinkReceive.getReceivedData(11); + system_cell_max_voltage_mV = (uint16_t)dataLinkReceive.getReceivedData(12); + system_cell_min_voltage_mV = (uint16_t)dataLinkReceive.getReceivedData(13); + system_LFP_Chemistry = (bool)dataLinkReceive.getReceivedData(14); + batteryAllowsContactorClosing = (bool)dataLinkReceive.getReceivedData(15); batteryFault = false; - if (_bms_status == FAULT) { + if (_system_bms_status == FAULT) { batteryFault = true; set_event(EVENT_SERIAL_TRANSMITTER_FAILURE, 0); } @@ -99,8 +99,8 @@ void manageSerialLinkReceiver() { { __getData(); reads++; - lastGoodMaxCharge = max_target_charge_power; - lastGoodMaxDischarge = max_target_discharge_power; + lastGoodMaxCharge = system_max_charge_power_W; + lastGoodMaxDischarge = system_max_discharge_power_W; //--- if BatteryFault then assume Data is stale if (!batteryFault) lastGood = currentTime; @@ -116,13 +116,13 @@ void manageSerialLinkReceiver() { if (minutesLost > 0 && lastGood > 0) { // lose 25% each minute of data loss if (minutesLost < 4) { - max_target_charge_power = (lastGoodMaxCharge * (4 - minutesLost)) / 4; - max_target_discharge_power = (lastGoodMaxDischarge * (4 - minutesLost)) / 4; + system_max_charge_power_W = (lastGoodMaxCharge * (4 - minutesLost)) / 4; + system_max_discharge_power_W = (lastGoodMaxDischarge * (4 - minutesLost)) / 4; set_event(EVENT_SERIAL_RX_WARNING, minutesLost); } else { // Times Up - - max_target_charge_power = 0; - max_target_discharge_power = 0; + system_max_charge_power_W = 0; + system_max_discharge_power_W = 0; set_event(EVENT_SERIAL_RX_FAILURE, uint8_t(min(minutesLost, 255uL))); //----- Throw Error } @@ -137,9 +137,9 @@ void manageSerialLinkReceiver() { } Serial.print(minutesLost); Serial.print(", max Charge = "); - Serial.print(max_target_charge_power); + Serial.print(system_max_charge_power_W); Serial.print(", max Discharge = "); - Serial.println(max_target_discharge_power); + Serial.println(system_max_discharge_power_W); } } @@ -176,35 +176,35 @@ void manageSerialLinkReceiver() { void update_values_serial_link() { Serial.println("Values from battery: "); Serial.print("SOC: "); - Serial.print(SOC); + Serial.print(system_real_SOC_pptt); Serial.print(" SOH: "); - Serial.print(StateOfHealth); + Serial.print(system_SOH_pptt); Serial.print(" Voltage: "); - Serial.print(battery_voltage); + Serial.print(system_battery_voltage_dV); Serial.print(" Current: "); - Serial.print(battery_current); + Serial.print(system_battery_current_dA); Serial.print(" Capacity: "); - Serial.print(capacity_Wh); + Serial.print(system_capacity_Wh); Serial.print(" Remain cap: "); - Serial.print(remaining_capacity_Wh); + Serial.print(system_remaining_capacity_Wh); Serial.print(" Max discharge W: "); - Serial.print(max_target_discharge_power); + Serial.print(system_max_discharge_power_W); Serial.print(" Max charge W: "); - Serial.print(max_target_charge_power); + Serial.print(system_max_charge_power_W); Serial.print(" BMS status: "); - Serial.print(bms_status); + Serial.print(system_bms_status); Serial.print(" Power: "); - Serial.print(stat_batt_power); + Serial.print(system_active_power_W); Serial.print(" Temp min: "); - Serial.print(temperature_min); + Serial.print(system_temperature_min_dC); Serial.print(" Temp max: "); - Serial.print(temperature_max); + Serial.print(system_temperature_max_dC); Serial.print(" Cell max: "); - Serial.print(cell_max_voltage); + Serial.print(system_cell_max_voltage_mV); Serial.print(" Cell min: "); - Serial.print(cell_min_voltage); + Serial.print(system_cell_min_voltage_mV); Serial.print(" LFP : "); - Serial.print(LFP_Chemistry); + Serial.print(system_LFP_Chemistry); Serial.print(" batteryAllowsContactorClosing: "); Serial.print(batteryAllowsContactorClosing); Serial.print(" inverterAllowsContactorClosing: "); @@ -212,3 +212,11 @@ void update_values_serial_link() { Serial.println(""); } + +void setup_battery(void) { + Serial.println("SERIAL_DATA_LINK_RECEIVER selected"); +} +void update_values_battery() {} +void send_can_battery() {} + +#endif diff --git a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.h b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.h index e0824825..8c4ab623 100644 --- a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.h +++ b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.h @@ -3,6 +3,8 @@ #ifndef SERIAL_LINK_RECEIVER_FROM_BATTERY_H #define SERIAL_LINK_RECEIVER_FROM_BATTERY_H +#define BATTERY_SELECTED + #include #include "../../USER_SETTINGS.h" #include "../devboard/config.h" // Needed for all defines @@ -10,33 +12,31 @@ // https://github.com/mackelec/SerialDataLink -// These parameters need to be mapped for the inverter -extern uint16_t max_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t min_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t SOC; //SOC%, 0-100.00 (0-10000) -extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000) -extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485) -extern uint16_t capacity_Wh; //Wh, 0-60000 -extern uint16_t remaining_capacity_Wh; //Wh, 0-60000 -extern uint16_t max_target_discharge_power; //W, 0-60000 -extern uint16_t max_target_charge_power; //W, 0-60000 -extern uint8_t bms_status; //Enum, 0-5 -extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530) -extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t cell_max_voltage; //mV, 0-4350 -extern uint16_t cell_min_voltage; //mV, 0-4350 - -extern bool LFP_Chemistry; -extern uint16_t CANerror; - -extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false +// These parameters need to be mapped on the battery side +extern uint16_t system_max_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_min_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000) +extern uint16_t system_battery_voltage_dV; //V+1, 0-500.0 (0-5000) +extern int16_t system_battery_current_dA; //A+1, -1000 - 1000 +extern uint32_t system_capacity_Wh; //Wh, 0-150000Wh +extern uint32_t system_remaining_capacity_Wh; //Wh, 0-150000Wh +extern uint16_t system_max_discharge_power_W; //W, 0-65000 +extern uint16_t system_max_charge_power_W; //W, 0-65000 +extern uint8_t system_bms_status; //Enum 0-5 +extern int16_t system_active_power_W; //W, -32000 to 32000 +extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0 +extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0 +extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value +extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value +extern bool system_LFP_Chemistry; //Set to true or false depending on cell chemistry +extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false // Parameters to send to the transmitter extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false void manageSerialLinkReceiver(); void update_values_serial_link(); +void setup_battery(void); #endif diff --git a/Software/src/battery/TESLA-MODEL-3-BATTERY.cpp b/Software/src/battery/TESLA-MODEL-3-BATTERY.cpp index f328a6d2..fc07d99d 100644 --- a/Software/src/battery/TESLA-MODEL-3-BATTERY.cpp +++ b/Software/src/battery/TESLA-MODEL-3-BATTERY.cpp @@ -60,7 +60,6 @@ static uint16_t output_current = 0; static uint16_t soc_min = 0; static uint16_t soc_max = 0; static uint16_t soc_vi = 0; -static uint16_t soc_calculated = 0; static uint16_t soc_ave = 0; static uint16_t cell_max_v = 3700; static uint16_t cell_min_v = 3700; @@ -153,8 +152,6 @@ static const char* hvilStatusState[] = {"NOT OK", "UNKNOWN(14)", "UNKNOWN(15)"}; -#define MAX_SOC 1000 //BMS never goes over this value. We use this info to rescale SOC% sent to inverter -#define MIN_SOC 0 //BMS never goes below this value. We use this info to rescale SOC% sent to inverter #define MAX_CELL_VOLTAGE_NCA_NCM 4250 //Battery is put into emergency stop if one cell goes over this value #define MIN_CELL_VOLTAGE_NCA_NCM 2950 //Battery is put into emergency stop if one cell goes below this value #define MAX_CELL_DEVIATION_NCA_NCM 500 //LED turns yellow on the board if mv delta exceeds this value @@ -169,66 +166,58 @@ void update_values_battery() { //This function maps all the values fetched via //After values are mapped, we perform some safety checks, and do some serial printouts //Calculate the SOH% to send to inverter if (bat_beginning_of_life != 0) { //div/0 safeguard - StateOfHealth = + system_SOH_pptt = static_cast((static_cast(nominal_full_pack_energy) / bat_beginning_of_life) * 10000.0); } //If the calculation went wrong, set SOH to 100% - if (StateOfHealth > 10000) { - StateOfHealth = 10000; + if (system_SOH_pptt > 10000) { + system_SOH_pptt = 10000; } //If the value is unavailable, set SOH to 99% if (nominal_full_pack_energy < REASONABLE_ENERGYAMOUNT) { - StateOfHealth = 9900; + system_SOH_pptt = 9900; } - //Calculate the SOC% value to send to inverter - soc_calculated = soc_vi; - soc_calculated = MIN_SOC + (MAX_SOC - MIN_SOC) * (soc_calculated - MINPERCENTAGE) / (MAXPERCENTAGE - MINPERCENTAGE); - if (soc_calculated < 0) { //We are in the real SOC% range of 0-20%, always set SOC sent to Inverter as 0% - soc_calculated = 0; - } - if (soc_calculated > 1000) { //We are in the real SOC% range of 80-100%, always set SOC sent to Inverter as 100% - soc_calculated = 1000; - } - SOC = (soc_calculated * 10); //increase SOC range from 0-100.0 -> 100.00 + system_real_SOC_pptt = (soc_vi * 10); //increase SOC range from 0-100.0 -> 100.00 - battery_voltage = (volts * 10); //One more decimal needed (370 -> 3700) + system_battery_voltage_dV = (volts * 10); //One more decimal needed (370 -> 3700) - battery_current = convert2unsignedInt16(amps); //13.0A + system_battery_current_dA = amps; //13.0A - capacity_Wh = BATTERY_WH_MAX; //Use the configured value to avoid overflows + system_capacity_Wh = BATTERY_WH_MAX; //Use the configured value to avoid overflows //Calculate the remaining Wh amount from SOC% and max Wh value. - remaining_capacity_Wh = static_cast((static_cast(SOC) / 10000) * BATTERY_WH_MAX); + system_remaining_capacity_Wh = + static_cast((static_cast(system_real_SOC_pptt) / 10000) * BATTERY_WH_MAX); // Define the allowed discharge power - max_target_discharge_power = (max_discharge_current * volts); + system_max_discharge_power_W = (max_discharge_current * volts); // Cap the allowed discharge power if battery is empty, or discharge power is higher than the maximum discharge power allowed - if (SOC == 0) { - max_target_discharge_power = 0; - } else if (max_target_discharge_power > MAXDISCHARGEPOWERALLOWED) { - max_target_discharge_power = MAXDISCHARGEPOWERALLOWED; + if (system_scaled_SOC_pptt == 0) { + system_max_discharge_power_W = 0; + } else if (system_max_discharge_power_W > MAXDISCHARGEPOWERALLOWED) { + system_max_discharge_power_W = MAXDISCHARGEPOWERALLOWED; } //The allowed charge power behaves strangely. We instead estimate this value - if (SOC == 10000) { // When scaled SOC is 100%, set allowed charge power to 0 - max_target_charge_power = 0; + if (system_scaled_SOC_pptt == 10000) { // When scaled SOC is 100%, set allowed charge power to 0 + system_max_charge_power_W = 0; } else if (soc_vi > 950) { // When real SOC is between 95-99.99%, ramp the value between Max<->0 - max_target_charge_power = MAXCHARGEPOWERALLOWED * (1 - (soc_vi - 950) / 50.0); + system_max_charge_power_W = MAXCHARGEPOWERALLOWED * (1 - (soc_vi - 950) / 50.0); } else { // No limits, max charging power allowed - max_target_charge_power = MAXCHARGEPOWERALLOWED; + system_max_charge_power_W = MAXCHARGEPOWERALLOWED; } power = ((volts / 10) * amps); - stat_batt_power = convert2unsignedInt16(power); + system_active_power_W = power; - temperature_min = convert2unsignedInt16(min_temp); + system_temperature_min_dC = min_temp; - temperature_max = convert2unsignedInt16(max_temp); + system_temperature_max_dC = max_temp; - cell_max_voltage = cell_max_v; + system_cell_max_voltage_mV = cell_max_v; - cell_min_voltage = cell_min_v; + system_cell_min_voltage_mV = cell_min_v; /* Value mapping is completed. Start to check all safeties */ @@ -251,30 +240,31 @@ void update_values_battery() { //This function maps all the values fetched via //Determine which chemistry battery pack is using (crude method, TODO: replace with real CAN identifier later) if (soc_vi > 900) { //When SOC% is over 90.0%, we can use max cell voltage to estimate what chemistry is used if (cell_max_v < 3450) { - LFP_Chemistry = true; + system_LFP_Chemistry = true; } if (cell_max_v > 3700) { - LFP_Chemistry = false; + system_LFP_Chemistry = false; } } // An even better way is to check how many cells are in the pack. NCM/A batteries have 96s, LFP has 102-106s - if (nof_cellvoltages > 101) { - LFP_Chemistry = true; + if (system_number_of_cells > 101) { + system_LFP_Chemistry = true; } //Once cell chemistry is determined, set maximum and minimum total pack voltage safety limits - if (LFP_Chemistry) { - max_voltage = 3880; - min_voltage = 2968; + if (system_LFP_Chemistry) { + system_max_design_voltage_dV = 3880; + system_min_design_voltage_dV = 2968; } else { // NCM/A chemistry - max_voltage = 4030; - min_voltage = 3100; + system_max_design_voltage_dV = 4030; + system_min_design_voltage_dV = 3100; } //Check if SOC% is plausible - if (battery_voltage > (max_voltage - 20)) { // When pack voltage is close to max, and SOC% is still low, raise FAULT - if (SOC < 5000) { //When SOC is less than 50.00% when approaching max voltage - set_event(EVENT_SOC_PLAUSIBILITY_ERROR, SOC / 100); + if (system_battery_voltage_dV > + (system_max_design_voltage_dV - 20)) { // When pack voltage is close to max, and SOC% is still low, raise FAULT + if (system_real_SOC_pptt < 5000) { //When SOC is less than 50.00% when approaching max voltage + set_event(EVENT_SOC_PLAUSIBILITY_ERROR, system_real_SOC_pptt / 100); } } @@ -288,7 +278,7 @@ void update_values_battery() { //This function maps all the values fetched via set_event(EVENT_KWH_PLAUSIBILITY_ERROR, nominal_full_pack_energy); } - if (LFP_Chemistry) { //LFP limits used for voltage safeties + if (system_LFP_Chemistry) { //LFP limits used for voltage safeties if (cell_max_v >= MAX_CELL_VOLTAGE_LFP) { set_event(EVENT_CELL_OVER_VOLTAGE, (cell_max_v - MAX_CELL_VOLTAGE_LFP)); } @@ -314,9 +304,9 @@ void update_values_battery() { //This function maps all the values fetched via } } - if (bms_status == FAULT) { //Incase we enter a critical fault state, zero out the allowed limits - max_target_charge_power = 0; - max_target_discharge_power = 0; + if (system_bms_status == FAULT) { //Incase we enter a critical fault state, zero out the allowed limits + system_max_charge_power_W = 0; + system_max_discharge_power_W = 0; } /* Safeties verified. Perform USB serial printout if configured to do so */ @@ -350,10 +340,9 @@ void update_values_battery() { //This function maps all the values fetched via Serial.print("YES, "); else Serial.print("NO, "); - if (LFP_Chemistry) { + if (system_LFP_Chemistry) { Serial.print("LFP chemistry detected!"); } - Serial.print(nof_cellvoltages); Serial.println(""); Serial.print("Cellstats, Max: "); Serial.print(cell_max_v); @@ -375,14 +364,14 @@ void update_values_battery() { //This function maps all the values fetched via Serial.println(""); Serial.println("Values passed to the inverter: "); - print_SOC(" SOC: ", SOC); - print_int_with_units(" Max discharge power: ", max_target_discharge_power, "W"); + print_SOC(" SOC: ", system_scaled_SOC_pptt); + print_int_with_units(" Max discharge power: ", system_max_discharge_power_W, "W"); Serial.print(", "); - print_int_with_units(" Max charge power: ", max_target_charge_power, "W"); + print_int_with_units(" Max charge power: ", system_max_charge_power_W, "W"); Serial.println(""); - print_int_with_units(" Max temperature: ", ((int16_t)temperature_max * 0.1), "°C"); + print_int_with_units(" Max temperature: ", ((int16_t)system_temperature_min_dC * 0.1), "°C"); Serial.print(", "); - print_int_with_units(" Min temperature: ", ((int16_t)temperature_min * 0.1), "°C"); + print_int_with_units(" Min temperature: ", ((int16_t)system_temperature_max_dC * 0.1), "°C"); Serial.println(""); #endif } @@ -478,11 +467,11 @@ void receive_can_battery(CAN_frame_t rx_frame) { { // Example, frame3=0x89,frame2=0x1D = 35101 / 10 = 3510mV volts = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) / 10; - cellvoltages[mux * 3] = volts; + system_cellvoltages_mV[mux * 3] = volts; volts = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[4]) / 10; - cellvoltages[1 + mux * 3] = volts; + system_cellvoltages_mV[1 + mux * 3] = volts; volts = ((rx_frame.data.u8[7] << 8) | rx_frame.data.u8[6]) / 10; - cellvoltages[2 + mux * 3] = volts; + system_cellvoltages_mV[2 + mux * 3] = volts; // Track the max value of mux. If we've seen two 0 values for mux, we've probably gathered all // cell voltages. Then, 2 + mux_max * 3 + 1 is the number of cell voltages. @@ -491,7 +480,7 @@ void receive_can_battery(CAN_frame_t rx_frame) { mux_zero_counter++; if (mux_zero_counter == 2u) { // The max index will be 2 + mux_max * 3 (see above), so "+ 1" for the number of cells - nof_cellvoltages = 2 + 3 * mux_max + 1; + system_number_of_cells = 2 + 3 * mux_max + 1; // Increase the counter arbitrarily another time to make the initial if-statement evaluate to false mux_zero_counter++; } @@ -591,12 +580,12 @@ the first, for a few cycles, then stop all messages which causes the contactor previousMillis30 = currentMillis; if (inverterAllowsContactorClosing == 1) { - if (bms_status == ACTIVE) { + if (system_bms_status == ACTIVE) { send221still = 50; batteryAllowsContactorClosing = true; ESP32Can.CANWriteFrame(&TESLA_221_1); ESP32Can.CANWriteFrame(&TESLA_221_2); - } else { //bms_status == FAULT or inverter requested opening contactors + } else { //system_bms_status == FAULT or inverter requested opening contactors if (send221still > 0) { batteryAllowsContactorClosing = false; ESP32Can.CANWriteFrame(&TESLA_221_1); @@ -606,13 +595,6 @@ the first, for a few cycles, then stop all messages which causes the contactor } } } -uint16_t convert2unsignedInt16(int16_t signed_value) { - if (signed_value < 0) { - return (65535 + signed_value); - } else { - return (uint16_t)signed_value; - } -} void print_int_with_units(char* header, int value, char* units) { Serial.print(header); @@ -708,8 +690,8 @@ void printDebugIfActive(uint8_t symbol, const char* message) { void setup_battery(void) { // Performs one time setup at startup Serial.println("Tesla Model 3 battery selected"); - max_voltage = 4030; // 403.0V, over this, charging is not possible (goes into forced discharge) - min_voltage = 3100; // 310.0V under this, discharging further is disabled + system_max_design_voltage_dV = 4030; // 403.0V, over this, charging is not possible (goes into forced discharge) + system_min_design_voltage_dV = 3100; // 310.0V under this, discharging further is disabled } #endif diff --git a/Software/src/battery/TESLA-MODEL-3-BATTERY.h b/Software/src/battery/TESLA-MODEL-3-BATTERY.h index 4432bef1..86e68f94 100644 --- a/Software/src/battery/TESLA-MODEL-3-BATTERY.h +++ b/Software/src/battery/TESLA-MODEL-3-BATTERY.h @@ -12,32 +12,33 @@ 60000 // 60000W we need to cap this value to max 60kW, most inverters overflow otherwise // These parameters need to be mapped for the inverter -extern uint16_t max_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t min_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t SOC; //SOC%, 0-100.00 (0-10000) -extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000) -extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485) -extern uint16_t capacity_Wh; //Wh, 0-60000 -extern uint16_t remaining_capacity_Wh; //Wh, 0-60000 -extern uint16_t max_target_discharge_power; //W, 0-60000 -extern uint16_t max_target_charge_power; //W, 0-60000 -extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530) -extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t cell_max_voltage; //mV, 0-4350 -extern uint16_t cell_min_voltage; //mV, 0-4350 -extern uint16_t cellvoltages[120]; //mV 0-4350 per cell -extern uint8_t nof_cellvoltages; // Total number of cell voltages, set by each battery. -extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false -extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false -extern bool LFP_Chemistry; +extern uint32_t system_capacity_Wh; //Wh, 0-150000Wh +extern uint32_t system_remaining_capacity_Wh; //Wh, 0-150000Wh +extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0 +extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0 +extern int16_t system_active_power_W; //W, -32000 to 32000 +extern int16_t system_battery_current_dA; //A+1, -1000 - 1000 +extern uint16_t system_battery_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_max_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_min_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000) +extern uint16_t system_max_discharge_power_W; //W, 0-65000 +extern uint16_t system_max_charge_power_W; //W, 0-65000 +extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value +extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value +extern uint16_t system_cellvoltages_mV[120]; //Array with all cell voltages in mV +extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery +extern uint8_t system_bms_status; //Enum 0-5 +extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false +extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false +extern bool system_LFP_Chemistry; //Bool, 1=true, 0=false void printFaultCodesIfActive(); void printDebugIfActive(uint8_t symbol, const char* message); void print_int_with_units(char* header, int value, char* units); void print_SOC(char* header, int SOC); -uint16_t convert2unsignedInt16(int16_t signed_value); void setup_battery(void); #endif diff --git a/Software/src/battery/TEST-FAKE-BATTERY.cpp b/Software/src/battery/TEST-FAKE-BATTERY.cpp index 045521f5..a4cec841 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.cpp +++ b/Software/src/battery/TEST-FAKE-BATTERY.cpp @@ -18,49 +18,49 @@ void print_units(char* header, int value, char* units) { Serial.print(units); } -void update_values_battery() { /* This function puts fake values onto the parameters sent towards the inverter */ - SOC = 5000; // 50.00% +void update_values_battery() { /* This function puts fake values onto the parameters sent towards the inverter */ + system_real_SOC_pptt = 5000; // 50.00% - StateOfHealth = 9900; // 99.00% + system_SOH_pptt = 9900; // 99.00% - //battery_voltage = 3700; // 370.0V , value set in startup in .ino file, editable via webUI + //system_battery_voltage_dV = 3700; // 370.0V , value set in startup in .ino file, editable via webUI - battery_current = 0; // 0 A + system_battery_current_dA = 0; // 0 A - capacity_Wh = 30000; // 30kWh + system_capacity_Wh = 30000; // 30kWh - remaining_capacity_Wh = 15000; // 15kWh + system_remaining_capacity_Wh = 15000; // 15kWh - cell_max_voltage = 3596; + system_cell_max_voltage_mV = 3596; - cell_min_voltage = 3500; + system_cell_min_voltage_mV = 3500; - stat_batt_power = 0; // 0W + system_active_power_W = 0; // 0W - temperature_min = 50; // 5.0*C + system_temperature_min_dC = 50; // 5.0*C - temperature_max = 60; // 6.0*C + system_temperature_max_dC = 60; // 6.0*C - max_target_discharge_power = 5000; // 5kW + system_max_discharge_power_W = 5000; // 5kW - max_target_charge_power = 5000; // 5kW + system_max_charge_power_W = 5000; // 5kW for (int i = 0; i < 97; ++i) { - cellvoltages[i] = 3500 + i; + system_cellvoltages_mV[i] = 3500 + i; } /*Finally print out values to serial if configured to do so*/ #ifdef DEBUG_VIA_USB Serial.println("FAKE Values going to inverter"); - print_units("SOH%: ", (StateOfHealth * 0.01), "% "); - print_units(", SOC%: ", (SOC * 0.01), "% "); - print_units(", Voltage: ", (battery_voltage * 0.1), "V "); - print_units(", Max discharge power: ", max_target_discharge_power, "W "); - print_units(", Max charge power: ", max_target_charge_power, "W "); - print_units(", Max temp: ", (temperature_max * 0.1), "°C "); - print_units(", Min temp: ", (temperature_min * 0.1), "°C "); - print_units(", Max cell voltage: ", cell_max_voltage, "mV "); - print_units(", Min cell voltage: ", cell_min_voltage, "mV "); + print_units("SOH%: ", (system_SOH_pptt * 0.01), "% "); + print_units(", SOC%: ", (system_scaled_SOC_pptt * 0.01), "% "); + print_units(", Voltage: ", (system_battery_voltage_dV * 0.1), "V "); + print_units(", Max discharge power: ", system_max_discharge_power_W, "W "); + print_units(", Max charge power: ", system_max_charge_power_W, "W "); + print_units(", Max temp: ", (system_temperature_max_dC * 0.1), "°C "); + print_units(", Min temp: ", (system_temperature_min_dC * 0.1), "°C "); + print_units(", Max cell voltage: ", system_cell_max_voltage_mV, "mV "); + print_units(", Min cell voltage: ", system_cell_min_voltage_mV, "mV "); Serial.println(""); #endif } @@ -85,8 +85,8 @@ void send_can_battery() { void setup_battery(void) { // Performs one time setup at startup Serial.println("Test mode with fake battery selected"); - max_voltage = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge) - min_voltage = 2450; // 245.0V under this, discharging further is disabled + system_max_design_voltage_dV = 4040; // 404.4V, over this, charging is not possible (goes into forced discharge) + system_min_design_voltage_dV = 2450; // 245.0V under this, discharging further is disabled } #endif diff --git a/Software/src/battery/TEST-FAKE-BATTERY.h b/Software/src/battery/TEST-FAKE-BATTERY.h index 991aaf2a..70c5b642 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.h +++ b/Software/src/battery/TEST-FAKE-BATTERY.h @@ -8,25 +8,27 @@ #define BATTERY_SELECTED // These parameters need to be mapped for the inverter -extern uint16_t max_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t min_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t SOC; //SOC%, 0-100.00 (0-10000) -extern uint16_t StateOfHealth; //SOH%, 0-100.00 (0-10000) -extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485) -extern uint16_t capacity_Wh; //Wh, 0-60000 -extern uint16_t remaining_capacity_Wh; //Wh, 0-60000 -extern uint16_t max_target_discharge_power; //W, 0-60000 -extern uint16_t max_target_charge_power; //W, 0-60000 -extern uint8_t bms_status; //Enum, 0-5 -extern uint16_t stat_batt_power; //W, Goes thru convert2unsignedint16 function (5W = 5, -5W = 65530) -extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t cell_max_voltage; //mV, 0-4350 -extern uint16_t cell_min_voltage; //mV, 0-4350 -extern uint16_t cellvoltages[120]; //mV 0-5000 per cell -extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false -extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false +extern uint32_t system_capacity_Wh; //Wh, 0-150000Wh +extern uint32_t system_remaining_capacity_Wh; //Wh, 0-150000Wh +extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0 +extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0 +extern int16_t system_active_power_W; //W, -32000 to 32000 +extern int16_t system_battery_current_dA; //A+1, -1000 - 1000 +extern uint16_t system_battery_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_max_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_min_design_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000) +extern uint16_t system_max_discharge_power_W; //W, 0-65000 +extern uint16_t system_max_charge_power_W; //W, 0-65000 +extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value +extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value +extern uint16_t system_cellvoltages_mV[120]; //Array with all cell voltages in mV +extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery +extern uint8_t system_bms_status; //Enum 0-5 +extern bool batteryAllowsContactorClosing; //Bool, true/false +extern bool inverterAllowsContactorClosing; //Bool, true/false void setup_battery(void); diff --git a/Software/src/charger/NISSAN-LEAF-CHARGER.cpp b/Software/src/charger/NISSAN-LEAF-CHARGER.cpp index 50e7a263..f4925b4e 100644 --- a/Software/src/charger/NISSAN-LEAF-CHARGER.cpp +++ b/Software/src/charger/NISSAN-LEAF-CHARGER.cpp @@ -227,12 +227,12 @@ void send_can_nissanleaf_charger() { } // if actual battery_voltage is less than setpoint got to max power set from web ui - if (battery_voltage < (CHARGER_SET_HV * 10)) { //battery_voltage = V+1, 0-500.0 (0-5000) + if (system_battery_voltage_dV < (CHARGER_SET_HV * 10)) { //system_battery_voltage_dV = V+1, 0-500.0 (0-5000) OBCpower = OBCpowerSetpoint; } // decrement charger power if volt setpoint is reached - if (battery_voltage >= (CHARGER_SET_HV * 10)) { + if (system_battery_voltage_dV >= (CHARGER_SET_HV * 10)) { if (OBCpower > 0x64) { OBCpower--; } diff --git a/Software/src/charger/NISSAN-LEAF-CHARGER.h b/Software/src/charger/NISSAN-LEAF-CHARGER.h index 691a7535..14152477 100644 --- a/Software/src/charger/NISSAN-LEAF-CHARGER.h +++ b/Software/src/charger/NISSAN-LEAF-CHARGER.h @@ -4,7 +4,7 @@ #include "../../USER_SETTINGS.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" -extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000) +extern uint16_t system_battery_voltage_dV; //V+1, 0-500.0 (0-5000) void send_can_nissanleaf_charger(); void receive_can_nissanleaf_charger(CAN_frame_t rx_frame); diff --git a/Software/src/devboard/mqtt/mqtt.cpp b/Software/src/devboard/mqtt/mqtt.cpp index 4700c59e..89a37123 100644 --- a/Software/src/devboard/mqtt/mqtt.cpp +++ b/Software/src/devboard/mqtt/mqtt.cpp @@ -37,7 +37,9 @@ static void publish_cell_voltages(void) { static JsonDocument doc; static const char* hostname = WiFi.getHostname(); static String state_topic = String("battery-emulator_") + String(hostname) + "/spec_data"; - if (nof_cellvoltages == 0u) { + + // If the cell voltage number isn't initialized... + if (system_number_of_cells == 0u) { return; } @@ -45,7 +47,7 @@ static void publish_cell_voltages(void) { mqtt_first_transmission = false; String topic = "homeassistant/sensor/battery-emulator/cell_voltage"; - for (int i = 0; i < nof_cellvoltages; i++) { + for (int i = 0; i < system_number_of_cells; i++) { int cellNumber = i + 1; doc["name"] = "Battery Cell Voltage " + String(cellNumber); doc["object_id"] = "battery_voltage_cell" + String(cellNumber); @@ -72,13 +74,13 @@ static void publish_cell_voltages(void) { doc.clear(); // clear after sending autoconfig } else { // If cell voltages haven't been populated... - if (nof_cellvoltages == 0u) { + if (system_number_of_cells == 0u) { return; } JsonArray cell_voltages = doc["cell_voltages"].to(); - for (size_t i = 0; i < nof_cellvoltages; ++i) { - cell_voltages.add(((float)cellvoltages[i]) / 1000.0); + for (size_t i = 0; i < system_number_of_cells; ++i) { + cell_voltages.add(((float)system_cellvoltages_mV[i]) / 1000.0); } serializeJson(doc, mqtt_msg, sizeof(mqtt_msg)); @@ -145,15 +147,16 @@ static void publish_common_info(void) { } doc.clear(); } else { - doc["SOC"] = ((float)SOC) / 100.0; - doc["state_of_health"] = ((float)StateOfHealth) / 100.0; - doc["temperature_min"] = ((float)((int16_t)temperature_min)) / 10.0; - doc["temperature_max"] = ((float)((int16_t)temperature_max)) / 10.0; - doc["stat_batt_power"] = ((float)((int16_t)stat_batt_power)); - doc["battery_current"] = ((float)((int16_t)battery_current)) / 10.0; - doc["cell_max_voltage"] = ((float)cell_max_voltage) / 1000.0; - doc["cell_min_voltage"] = ((float)cell_min_voltage) / 1000.0; - doc["battery_voltage"] = ((float)battery_voltage) / 10.0; + doc["SOC"] = ((float)system_scaled_SOC_pptt) / 100.0; + doc["SOC_real"] = ((float)system_real_SOC_pptt) / 100.0; + doc["state_of_health"] = ((float)system_SOH_pptt) / 100.0; + doc["temperature_min"] = ((float)((int16_t)system_temperature_min_dC)) / 10.0; + doc["temperature_max"] = ((float)((int16_t)system_temperature_max_dC)) / 10.0; + doc["stat_batt_power"] = ((float)((int16_t)system_active_power_W)); + doc["battery_current"] = ((float)((int16_t)system_battery_current_dA)) / 10.0; + doc["cell_max_voltage"] = ((float)system_cell_max_voltage_mV) / 1000.0; + doc["cell_min_voltage"] = ((float)system_cell_min_voltage_mV) / 1000.0; + doc["battery_voltage"] = ((float)system_battery_voltage_dV) / 10.0; serializeJson(doc, mqtt_msg); if (!mqtt_publish(state_topic.c_str(), mqtt_msg, false)) { diff --git a/Software/src/devboard/mqtt/mqtt.h b/Software/src/devboard/mqtt/mqtt.h index b622bc9b..4eeb307c 100644 --- a/Software/src/devboard/mqtt/mqtt.h +++ b/Software/src/devboard/mqtt/mqtt.h @@ -41,17 +41,18 @@ extern const char* version_number; // The current software version, used for mqtt -extern uint16_t SOC; -extern uint16_t StateOfHealth; -extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t temperature_max; //C+1, Goes thru convert2unsignedint16 function (15.0C = 150, -15.0C = 65385) -extern uint16_t cell_max_voltage; //mV, 0-4350 -extern uint16_t cell_min_voltage; //mV, 0-4350 -extern uint16_t cellvoltages[120]; //mV 0-4350 per cell -extern uint8_t nof_cellvoltages; // Total number of cell voltages, set by each battery. -extern uint16_t battery_voltage; //V+1, 0-500.0 (0-5000) -extern uint16_t battery_current; //A+1, Goes thru convert2unsignedint16 function (5.0A = 50, -5.0A = 65485) -extern uint16_t stat_batt_power; +extern int16_t system_temperature_min_dC; //C+1, -50.0 - 50.0 +extern int16_t system_temperature_max_dC; //C+1, -50.0 - 50.0 +extern int16_t system_active_power_W; //W, -32000 to 32000 +extern int16_t system_battery_current_dA; //A+1, -1000 - 1000 +extern uint16_t system_battery_voltage_dV; //V+1, 0-500.0 (0-5000) +extern uint16_t system_scaled_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_real_SOC_pptt; //SOC%, 0-100.00 (0-10000) +extern uint16_t system_SOH_pptt; //SOH%, 0-100.00 (0-10000) +extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000 , Stores the highest cell millivolt value +extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value +extern uint16_t system_cellvoltages_mV[120]; //Array with all cell voltages in mV +extern uint8_t system_number_of_cells; //Total number of cell voltages, set by each battery extern const char* mqtt_user; extern const char* mqtt_password; diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index 58c45f56..9bfb184b 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -137,6 +137,7 @@ void init_events(void) { events.entries[EVENT_LOW_SOH].level = EVENT_LEVEL_ERROR; events.entries[EVENT_HVIL_FAILURE].level = EVENT_LEVEL_ERROR; events.entries[EVENT_INTERNAL_OPEN_FAULT].level = EVENT_LEVEL_ERROR; + events.entries[EVENT_INVERTER_OPEN_CONTACTOR].level = EVENT_LEVEL_ERROR; events.entries[EVENT_CELL_UNDER_VOLTAGE].level = EVENT_LEVEL_ERROR; events.entries[EVENT_CELL_OVER_VOLTAGE].level = EVENT_LEVEL_ERROR; events.entries[EVENT_CELL_DEVIATION_HIGH].level = EVENT_LEVEL_WARNING; @@ -210,6 +211,8 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) { "disabled!"; case EVENT_INTERNAL_OPEN_FAULT: return "ERROR: High voltage cable removed while battery running. Opening contactors!"; + case EVENT_INVERTER_OPEN_CONTACTOR: + return "ERROR: Inverter requested contactors to open. Opening contactors!"; case EVENT_CELL_UNDER_VOLTAGE: return "ERROR: CELL UNDERVOLTAGE!!! Stopping battery charging and discharging. Inspect battery!"; case EVENT_CELL_OVER_VOLTAGE: @@ -299,13 +302,13 @@ static void update_bms_status(void) { case EVENT_LEVEL_INFO: case EVENT_LEVEL_WARNING: case EVENT_LEVEL_DEBUG: - bms_status = ACTIVE; + system_bms_status = ACTIVE; break; case EVENT_LEVEL_UPDATE: - bms_status = UPDATING; + system_bms_status = UPDATING; break; case EVENT_LEVEL_ERROR: - bms_status = FAULT; + system_bms_status = FAULT; break; default: break; diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index 83b0f499..13e67179 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -36,6 +36,7 @@ XX(EVENT_LOW_SOH) \ XX(EVENT_HVIL_FAILURE) \ XX(EVENT_INTERNAL_OPEN_FAULT) \ + XX(EVENT_INVERTER_OPEN_CONTACTOR) \ XX(EVENT_CELL_UNDER_VOLTAGE) \ XX(EVENT_CELL_OVER_VOLTAGE) \ XX(EVENT_CELL_DEVIATION_HIGH) \ @@ -99,6 +100,6 @@ void run_event_handling(void); void run_sequence_on_target(void); -extern uint8_t bms_status; //Enum, 0-5 +extern uint8_t system_bms_status; //Enum 0-5 #endif // __MYTIMER_H__ diff --git a/Software/src/devboard/utils/events_test_on_target.cpp b/Software/src/devboard/utils/events_test_on_target.cpp index 0af89304..3ecf0ee0 100644 --- a/Software/src/devboard/utils/events_test_on_target.cpp +++ b/Software/src/devboard/utils/events_test_on_target.cpp @@ -26,8 +26,8 @@ void run_sequence_on_target(void) { timer.set_interval(10000); events_test_state = ETOT_FIRST_WAIT; Serial.println("Events test: initialized"); - Serial.print("bms_status: "); - Serial.println(bms_status); + Serial.print("system_bms_status: "); + Serial.println(system_bms_status); break; case ETOT_FIRST_WAIT: if (timer.elapsed()) { @@ -36,8 +36,8 @@ void run_sequence_on_target(void) { set_event(EVENT_DUMMY_INFO, 123); set_event(EVENT_DUMMY_INFO, 234); // 234 should show, occurrence 1 Serial.println("Events test: info event set, data: 234"); - Serial.print("bms_status: "); - Serial.println(bms_status); + Serial.print("system_bms_status: "); + Serial.println(system_bms_status); } break; case ETOT_INFO: @@ -46,8 +46,8 @@ void run_sequence_on_target(void) { clear_event(EVENT_DUMMY_INFO); events_test_state = ETOT_INFO_CLEAR; Serial.println("Events test : info event cleared"); - Serial.print("bms_status: "); - Serial.println(bms_status); + Serial.print("system_bms_status: "); + Serial.println(system_bms_status); } break; case ETOT_INFO_CLEAR: @@ -57,8 +57,8 @@ void run_sequence_on_target(void) { set_event(EVENT_DUMMY_DEBUG, 111); set_event(EVENT_DUMMY_DEBUG, 222); // 222 should show, occurrence 1 Serial.println("Events test : debug event set, data: 222"); - Serial.print("bms_status: "); - Serial.println(bms_status); + Serial.print("system_bms_status: "); + Serial.println(system_bms_status); } break; case ETOT_DEBUG: @@ -67,8 +67,8 @@ void run_sequence_on_target(void) { clear_event(EVENT_DUMMY_DEBUG); events_test_state = ETOT_DEBUG_CLEAR; Serial.println("Events test : info event cleared"); - Serial.print("bms_status: "); - Serial.println(bms_status); + Serial.print("system_bms_status: "); + Serial.println(system_bms_status); } break; case ETOT_DEBUG_CLEAR: @@ -78,8 +78,8 @@ void run_sequence_on_target(void) { set_event(EVENT_DUMMY_WARNING, 234); set_event(EVENT_DUMMY_WARNING, 121); // 121 should show, occurrence 1 Serial.println("Events test : warning event set, data: 121"); - Serial.print("bms_status: "); - Serial.println(bms_status); + Serial.print("system_bms_status: "); + Serial.println(system_bms_status); } break; case ETOT_WARNING: @@ -88,8 +88,8 @@ void run_sequence_on_target(void) { clear_event(EVENT_DUMMY_WARNING); events_test_state = ETOT_WARNING_CLEAR; Serial.println("Events test : warning event cleared"); - Serial.print("bms_status: "); - Serial.println(bms_status); + Serial.print("system_bms_status: "); + Serial.println(system_bms_status); } break; case ETOT_WARNING_CLEAR: @@ -99,8 +99,8 @@ void run_sequence_on_target(void) { set_event(EVENT_DUMMY_ERROR, 221); set_event(EVENT_DUMMY_ERROR, 133); // 133 should show, occurrence 1 Serial.println("Events test : error event set, data: 133"); - Serial.print("bms_status: "); - Serial.println(bms_status); + Serial.print("system_bms_status: "); + Serial.println(system_bms_status); } break; case ETOT_ERROR: @@ -109,8 +109,8 @@ void run_sequence_on_target(void) { clear_event(EVENT_DUMMY_ERROR); events_test_state = ETOT_ERROR_CLEAR; Serial.println("Events test : error event cleared"); - Serial.print("bms_status: "); - Serial.println(bms_status); + Serial.print("system_bms_status: "); + Serial.println(system_bms_status); } break; case ETOT_ERROR_CLEAR: @@ -120,8 +120,8 @@ void run_sequence_on_target(void) { set_event_latched(EVENT_DUMMY_ERROR, 221); set_event_latched(EVENT_DUMMY_ERROR, 133); // 133 should show, occurrence 1 Serial.println("Events test : latched error event set, data: 133"); - Serial.print("bms_status: "); - Serial.println(bms_status); + Serial.print("system_bms_status: "); + Serial.println(system_bms_status); } break; case ETOT_ERROR_LATCHED: @@ -130,8 +130,8 @@ void run_sequence_on_target(void) { clear_event(EVENT_DUMMY_ERROR); events_test_state = ETOT_DONE; Serial.println("Events test : latched error event cleared?"); - Serial.print("bms_status: "); - Serial.println(bms_status); + Serial.print("system_bms_status: "); + Serial.println(system_bms_status); } break; case ETOT_DONE: diff --git a/Software/src/devboard/webserver/cellmonitor_html.cpp b/Software/src/devboard/webserver/cellmonitor_html.cpp index 1051e87c..627fef3d 100644 --- a/Software/src/devboard/webserver/cellmonitor_html.cpp +++ b/Software/src/devboard/webserver/cellmonitor_html.cpp @@ -18,9 +18,9 @@ String cellmonitor_processor(const String& var) { // Display max, min, and deviation voltage values content += "
"; - content += "Max Voltage: " + String(cell_max_voltage) + " mV
"; - content += "Min Voltage: " + String(cell_min_voltage) + " mV
"; - int deviation = cell_max_voltage - cell_min_voltage; + content += "Max Voltage: " + String(system_cell_max_voltage_mV) + " mV
"; + content += "Min Voltage: " + String(system_cell_min_voltage_mV) + " mV
"; + int deviation = system_cell_max_voltage_mV - system_cell_min_voltage_mV; content += "Voltage Deviation: " + String(deviation) + " mV"; content += "
"; @@ -28,14 +28,14 @@ String cellmonitor_processor(const String& var) { content += "
"; for (int i = 0; i < 120; ++i) { // Skip empty values - if (cellvoltages[i] == 0) { + if (system_cellvoltages_mV[i] == 0) { continue; } - String cellContent = "Cell " + String(i + 1) + "
" + String(cellvoltages[i]) + " mV"; + String cellContent = "Cell " + String(i + 1) + "
" + String(system_cellvoltages_mV[i]) + " mV"; // Check if the cell voltage is below 3000, apply red color - if (cellvoltages[i] < 3000) { + if (system_cellvoltages_mV[i] < 3000) { cellContent = "" + cellContent + ""; } diff --git a/Software/src/devboard/webserver/cellmonitor_html.h b/Software/src/devboard/webserver/cellmonitor_html.h index 0a3d4aa9..17b81b69 100644 --- a/Software/src/devboard/webserver/cellmonitor_html.h +++ b/Software/src/devboard/webserver/cellmonitor_html.h @@ -4,9 +4,9 @@ #include #include -extern uint16_t cell_max_voltage; //mV, 0-4350 -extern uint16_t cell_min_voltage; //mV, 0-4350 -extern uint16_t cellvoltages[120]; //mV 0-4350 per cell +extern uint16_t system_cell_max_voltage_mV; //mV, 0-5000, Stores the highest cell millivolt value +extern uint16_t system_cell_min_voltage_mV; //mV, 0-5000, Stores the minimum cell millivolt value +extern uint16_t system_cellvoltages_mV[120]; //Array with all cell voltages in mV /** * @brief Replaces placeholder with content section in web page diff --git a/Software/src/devboard/webserver/settings_html.cpp b/Software/src/devboard/webserver/settings_html.cpp index 35cbd113..dd824dc4 100644 --- a/Software/src/devboard/webserver/settings_html.cpp +++ b/Software/src/devboard/webserver/settings_html.cpp @@ -15,6 +15,8 @@ String settings_processor(const String& var) { // Show current settings with edit buttons and input fields content += "

Battery capacity: " + String(BATTERY_WH_MAX) + " Wh

"; + content += "

Rescale SOC: " + String(USE_SCALED_SOC) + + "

"; content += "

SOC max percentage: " + String(MAXPERCENTAGE / 10.0, 1) + "

"; content += "

SOC min percentage: " + String(MINPERCENTAGE / 10.0, 1) + @@ -29,7 +31,7 @@ String settings_processor(const String& var) { #ifdef TEST_FAKE_BATTERY // Start a new block with blue background color content += "
"; - float voltageFloat = static_cast(battery_voltage) / 10.0; // Convert to float and divide by 10 + float voltageFloat = static_cast(system_battery_voltage_dV) / 10.0; // Convert to float and divide by 10 content += "

Fake battery voltage: " + String(voltageFloat, 1) + " V

"; @@ -69,14 +71,26 @@ String settings_processor(const String& var) { content += "