diff --git a/Software/Software.ino b/Software/Software.ino index 7f24a2ca..b8c75dd9 100644 --- a/Software/Software.ino +++ b/Software/Software.ino @@ -54,9 +54,9 @@ ModbusServerRTU MBserver(Serial2, 2000); #endif // Common inverter parameters. Batteries map their values to these variables -uint16_t max_voltage = ABSOLUTE_MAX_VOLTAGE; // If higher charging is not possible (goes into forced discharge) -uint16_t min_voltage = ABSOLUTE_MIN_VOLTAGE; // If lower disables discharging battery -uint16_t battery_voltage = 3700; //V+1, 0-500.0 (0-5000) +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) @@ -144,11 +144,7 @@ void setup() { inform_user_on_inverter(); - inform_user_on_battery(); - -#ifdef BATTERY_HAS_INIT init_battery(); -#endif // BOOT button at runtime is used as an input for various things pinMode(0, INPUT_PULLUP); @@ -344,6 +340,9 @@ void inform_user_on_inverter() { #ifdef SMA_CAN Serial.println("SMA CAN protocol selected"); #endif +#ifdef SMA_TRIPOWER_CAN + Serial.println("SMA Tripower CAN protocol selected"); +#endif #ifdef SOFAR_CAN Serial.println("SOFAR CAN protocol selected"); #endif @@ -354,42 +353,13 @@ void inform_user_on_inverter() { #endif } -void inform_user_on_battery() { - // Inform user what battery is used -#ifdef BMW_I3_BATTERY - Serial.println("BMW i3 battery selected"); -#endif -#ifdef CHADEMO_BATTERY - Serial.println("Chademo battery selected"); -#endif -#ifdef IMIEV_CZERO_ION_BATTERY - Serial.println("Mitsubishi i-MiEV / Citroen C-Zero / Peugeot Ion battery selected"); -#endif -#ifdef KIA_HYUNDAI_64_BATTERY - Serial.println("Kia Niro / Hyundai Kona 64kWh battery selected"); -#endif -#ifdef NISSAN_LEAF_BATTERY - Serial.println("Nissan LEAF battery selected"); -#endif -#ifdef RENAULT_KANGOO_BATTERY - Serial.println("Renault Kangoo battery selected"); -#endif -#ifdef SANTA_FE_PHEV_BATTERY - Serial.println("Hyundai Santa Fe PHEV battery selected"); -#endif -#ifdef RENAULT_ZOE_BATTERY - Serial.println("Renault Zoe battery selected"); -#endif -#ifdef TESLA_MODEL_3_BATTERY - Serial.println("Tesla Model 3 battery selected"); -#endif -#ifdef TEST_FAKE_BATTERY - Serial.println("Test mode with fake battery selected"); -#endif +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 -#if !defined(ABSOLUTE_MAX_VOLTAGE) +#ifndef BATTERY_SELECTED #error No battery selected! Choose one from the USER_SETTINGS.h file #endif } @@ -402,42 +372,16 @@ void receive_can() { // This section checks if we have a complete CAN message i if (rx_frame.FIR.B.FF == CAN_frame_std) { //printf("New standard frame"); // Battery -#ifdef BMW_I3_BATTERY - receive_can_i3_battery(rx_frame); -#endif -#ifdef CHADEMO_BATTERY - receive_can_chademo_battery(rx_frame); -#endif -#ifdef IMIEV_CZERO_ION_BATTERY - receive_can_imiev_battery(rx_frame); -#endif -#ifdef KIA_HYUNDAI_64_BATTERY - receive_can_kiaHyundai_64_battery(rx_frame); -#endif -#ifdef NISSAN_LEAF_BATTERY - receive_can_leaf_battery(rx_frame); -#endif -#ifdef RENAULT_KANGOO_BATTERY - receive_can_kangoo_battery(rx_frame); -#endif -#ifdef SANTA_FE_PHEV_BATTERY - receive_can_santafe_phev_battery(rx_frame); -#endif -#ifdef RENAULT_ZOE_BATTERY - receive_can_zoe_battery(rx_frame); -#endif -#ifdef TESLA_MODEL_3_BATTERY - receive_can_tesla_model_3_battery(rx_frame); -#endif -#ifdef TEST_FAKE_BATTERY - receive_can_test_battery(rx_frame); -#endif + receive_can_battery(rx_frame); // Inverter #ifdef BYD_CAN receive_can_byd(rx_frame); #endif #ifdef SMA_CAN receive_can_sma(rx_frame); +#endif +#ifdef SMA_TRIPOWER_CAN + receive_can_sma_tripower(rx_frame); #endif // Charger #ifdef CHEVYVOLT_CHARGER @@ -470,40 +414,14 @@ void send_can() { #ifdef SMA_CAN send_can_sma(); #endif +#ifdef SMA_TRIPOWER_CAN + send_can_sma_tripower(); +#endif #ifdef SOFAR_CAN send_can_sofar(); #endif // Battery -#ifdef BMW_I3_BATTERY - send_can_i3_battery(); -#endif -#ifdef CHADEMO_BATTERY - send_can_chademo_battery(); -#endif -#ifdef IMIEV_CZERO_ION_BATTERY - send_can_imiev_battery(); -#endif -#ifdef KIA_HYUNDAI_64_BATTERY - send_can_kiaHyundai_64_battery(); -#endif -#ifdef NISSAN_LEAF_BATTERY - send_can_leaf_battery(); -#endif -#ifdef RENAULT_KANGOO_BATTERY - send_can_kangoo_battery(); -#endif -#ifdef SANTA_FE_PHEV_BATTERY - send_can_santafe_phev_battery(); -#endif -#ifdef RENAULT_ZOE_BATTERY - send_can_zoe_battery(); -#endif -#ifdef TESLA_MODEL_3_BATTERY - send_can_tesla_model_3_battery(); -#endif -#ifdef TEST_FAKE_BATTERY - send_can_test_battery(); -#endif + send_can_battery(); #ifdef CHEVYVOLT_CHARGER send_can_chevyvolt_charger(); #endif @@ -683,36 +601,7 @@ void handle_contactors() { void update_values() { // Battery -#ifdef BMW_I3_BATTERY - update_values_i3_battery(); // Map the values to the correct registers -#endif -#ifdef CHADEMO_BATTERY - update_values_chademo_battery(); // Map the values to the correct registers -#endif -#ifdef IMIEV_CZERO_ION_BATTERY - update_values_imiev_battery(); // Map the values to the correct registers -#endif -#ifdef KIA_HYUNDAI_64_BATTERY - update_values_kiaHyundai_64_battery(); // Map the values to the correct registers -#endif -#ifdef NISSAN_LEAF_BATTERY - update_values_leaf_battery(); // Map the values to the correct registers -#endif -#ifdef RENAULT_KANGOO_BATTERY - update_values_kangoo_battery(); // Map the values to the correct registers -#endif -#ifdef SANTA_FE_PHEV_BATTERY - update_values_santafe_phev_battery(); // Map the values to the correct registers -#endif -#ifdef RENAULT_ZOE_BATTERY - update_values_zoe_battery(); // Map the values to the correct registers -#endif -#ifdef TESLA_MODEL_3_BATTERY - update_values_tesla_model_3_battery(); // Map the values to the correct registers -#endif -#ifdef TEST_FAKE_BATTERY - update_values_test_battery(); // Map the fake values to the correct registers -#endif + update_values_battery(); // Map the fake values to the correct registers // Inverter #ifdef BYD_CAN update_values_can_byd(); @@ -729,6 +618,9 @@ void update_values() { #ifdef SMA_CAN update_values_can_sma(); #endif +#ifdef SMA_TRIPOWER_CAN + update_values_can_sma_tripower(); +#endif #ifdef SOFAR_CAN update_values_can_sofar(); #endif diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 373922c8..53a762cf 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -12,7 +12,7 @@ //#define CHADEMO_BATTERY //#define IMIEV_CZERO_ION_BATTERY //#define KIA_HYUNDAI_64_BATTERY -// #define NISSAN_LEAF_BATTERY +//#define NISSAN_LEAF_BATTERY //#define RENAULT_KANGOO_BATTERY //#define RENAULT_ZOE_BATTERY //#define SANTA_FE_PHEV_BATTERY @@ -21,10 +21,11 @@ /* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki */ //#define BYD_CAN //Enable this line to emulate a "BYD Battery-Box Premium HVS" over CAN Bus -// #define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU +//#define BYD_MODBUS //Enable this line to emulate a "BYD 11kWh HVM battery" over Modbus RTU //#define LUNA2000_MODBUS //Enable this line to emulate a "Luna2000 battery" over Modbus RTU //#define PYLON_CAN //Enable this line to emulate a "Pylontech battery" over CAN bus //#define SMA_CAN //Enable this line to emulate a "BYD Battery-Box H 8.9kWh, 7 mod" over CAN bus +//#define SMA_TRIPOWER_CAN //Enable this line to emulate a "SMA Home Storage battery" over CAN bus //#define SOFAR_CAN //Enable this line to emulate a "Sofar Energy Storage Inverter High Voltage BMS General Protocol (Extended Frame)" over CAN bus //#define SOLAX_CAN //Enable this line to emulate a "SolaX Triple Power LFP" over CAN bus diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index 2f823ab3..f6efe68e 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -21,7 +21,6 @@ #ifdef NISSAN_LEAF_BATTERY #include "NISSAN-LEAF-BATTERY.h" //See this file for more LEAF battery settings -#define BATTERY_HAS_INIT #endif #ifdef RENAULT_KANGOO_BATTERY @@ -48,4 +47,11 @@ #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(); +void receive_can_battery(CAN_frame_t rx_frame); +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 5d53c10e..11c6794f 100644 --- a/Software/src/battery/BMW-I3-BATTERY.cpp +++ b/Software/src/battery/BMW-I3-BATTERY.cpp @@ -1,10 +1,12 @@ -#include "BMW-I3-BATTERY.h" +#include "BATTERIES.h" +#ifdef BMW_I3_BATTERY #include "../devboard/utils/events.h" #include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" +#include "BMW-I3-BATTERY.h" //TODO: before using -// Map the final values in update_values_i3_battery, set some to static values if not available (current, discharge max , charge max) +// Map the final values in update_values_battery, set some to static values if not available (current, discharge max , charge max) // Check if I3 battery stays alive with only 10B and 512. If not, add 12F. If that doesn't help, add more from CAN log (ask Dala) /* Do not change code below unless you are sure what you are doing */ @@ -54,7 +56,7 @@ static uint16_t Battery_Status = 0; static uint16_t DC_link = 0; static int16_t Battery_Power = 0; -void update_values_i3_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus +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 = @@ -122,7 +124,7 @@ void update_values_i3_battery() { //This function maps all the values fetched v #endif } -void receive_can_i3_battery(CAN_frame_t rx_frame) { +void receive_can_battery(CAN_frame_t rx_frame) { CANstillAlive = 12; switch (rx_frame.MsgID) { case 0x431: //Battery capacity [200ms] @@ -168,7 +170,7 @@ void receive_can_i3_battery(CAN_frame_t rx_frame) { break; } } -void send_can_i3_battery() { +void send_can_battery() { unsigned long currentMillis = millis(); // Send 600ms CAN Message if (currentMillis - previousMillis600 >= interval600) { @@ -190,3 +192,12 @@ void send_can_i3_battery() { ESP32Can.CANWriteFrame(&BMW_10B); } } + +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 +} + +#endif diff --git a/Software/src/battery/BMW-I3-BATTERY.h b/Software/src/battery/BMW-I3-BATTERY.h index 882d8721..e2cea1c9 100644 --- a/Software/src/battery/BMW-I3-BATTERY.h +++ b/Software/src/battery/BMW-I3-BATTERY.h @@ -5,28 +5,28 @@ #include "../devboard/config.h" // Needed for all defines #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" -#define ABSOLUTE_MAX_VOLTAGE \ - 4040 // 404.4V,if battery voltage goes over this, charging is not possible (goes into forced discharge) -#define ABSOLUTE_MIN_VOLTAGE 3100 // 310.0V if battery voltage goes under this, discharging further is disabled +#define BATTERY_SELECTED // These parameters need to be mapped for the inverter -extern uint16_t SOC; -extern uint16_t StateOfHealth; -extern uint16_t battery_voltage; -extern uint16_t battery_current; -extern uint16_t capacity_Wh; -extern uint16_t remaining_capacity_Wh; -extern uint16_t max_target_discharge_power; -extern uint16_t max_target_charge_power; -extern uint16_t stat_batt_power; -extern uint16_t temperature_min; -extern uint16_t temperature_max; -extern uint16_t CANerror; -extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false -extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false +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 -void update_values_i3_battery(); -void receive_can_i3_battery(CAN_frame_t rx_frame); -void send_can_i3_battery(); +void setup_battery(void); #endif diff --git a/Software/src/battery/CHADEMO-BATTERY.cpp b/Software/src/battery/CHADEMO-BATTERY.cpp index 17ec4b1a..dfabd72b 100644 --- a/Software/src/battery/CHADEMO-BATTERY.cpp +++ b/Software/src/battery/CHADEMO-BATTERY.cpp @@ -1,7 +1,9 @@ -#include "CHADEMO-BATTERY.h" +#include "BATTERIES.h" +#ifdef CHADEMO_BATTERY #include "../devboard/utils/events.h" #include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" +#include "CHADEMO-BATTERY.h" /* Do not change code below unless you are sure what you are doing */ static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send @@ -89,7 +91,7 @@ uint8_t DynamicControlStatus = 0; uint8_t HighCurrentControlStatus = 0; uint8_t HighVoltageControlStatus = 0; -void update_values_chademo_battery() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter +void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for the inverter SOC = ChargingRate; @@ -133,7 +135,7 @@ void update_values_chademo_battery() { //This function maps all the values fetc #endif } -void receive_can_chademo_battery(CAN_frame_t rx_frame) { +void receive_can_battery(CAN_frame_t rx_frame) { CANstillAlive == 12; //We are getting CAN messages from the vehicle, inform the watchdog switch (rx_frame.MsgID) { @@ -189,7 +191,7 @@ void receive_can_chademo_battery(CAN_frame_t rx_frame) { break; } } -void send_can_chademo_battery() { +void send_can_battery() { unsigned long currentMillis = millis(); // Send 100ms CAN Message if (currentMillis - previousMillis100 >= interval100) { @@ -205,3 +207,11 @@ void send_can_chademo_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 +} +#endif diff --git a/Software/src/battery/CHADEMO-BATTERY.h b/Software/src/battery/CHADEMO-BATTERY.h index 4f65a4ec..0e27b44a 100644 --- a/Software/src/battery/CHADEMO-BATTERY.h +++ b/Software/src/battery/CHADEMO-BATTERY.h @@ -5,29 +5,28 @@ #include "../devboard/config.h" // Needed for all defines #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" -#define ABSOLUTE_MAX_VOLTAGE \ - 4040 // 404.4V,if battery voltage goes over this, charging is not possible (goes into forced discharge) -#define ABSOLUTE_MIN_VOLTAGE 3100 // 310.0V if battery voltage goes under this, discharging further is disabled +#define BATTERY_SELECTED -// These parameters need to be mapped -extern uint16_t SOC; -extern uint16_t StateOfHealth; -extern uint16_t battery_voltage; -extern uint16_t battery_current; -extern uint16_t capacity_Wh; -extern uint16_t remaining_capacity_Wh; -extern uint16_t max_target_discharge_power; -extern uint16_t max_target_charge_power; -extern uint8_t bms_status; -extern uint16_t stat_batt_power; -extern uint16_t temperature_min; -extern uint16_t temperature_max; -extern uint16_t CANerror; -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 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 -void update_values_chademo_battery(); -void receive_can_chademo_battery(CAN_frame_t rx_frame); -void send_can_chademo_battery(); +void setup_battery(void); #endif diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp index e2e68a3d..7530c37e 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.cpp @@ -1,7 +1,9 @@ -#include "IMIEV-CZERO-ION-BATTERY.h" +#include "BATTERIES.h" +#ifdef IMIEV_CZERO_ION_BATTERY #include "../devboard/utils/events.h" #include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" +#include "IMIEV-CZERO-ION-BATTERY.h" //Code still work in progress, TODO: //Figure out if CAN messages need to be sent to keep the system happy? @@ -40,7 +42,7 @@ static double min_volt_cel = 3.70; static double max_temp_cel = 20.00; static double min_temp_cel = 19.00; -void update_values_imiev_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus +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 battery_voltage = (uint16_t)(BMU_PackVoltage * 10); // Multiply by 10 and cast to uint16_t @@ -161,7 +163,7 @@ void update_values_imiev_battery() { //This function maps all the values fetche #endif } -void receive_can_imiev_battery(CAN_frame_t rx_frame) { +void receive_can_battery(CAN_frame_t rx_frame) { CANstillAlive = 12; //TODO: move this inside a known message ID to prevent CAN inverter from keeping battery alive detection going switch (rx_frame.MsgID) { @@ -217,10 +219,19 @@ void receive_can_imiev_battery(CAN_frame_t rx_frame) { } } -void send_can_imiev_battery() { +void send_can_battery() { unsigned long currentMillis = millis(); // Send 100ms CAN Message if (currentMillis - previousMillis100 >= interval100) { previousMillis100 = currentMillis; } } + +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 +} + +#endif diff --git a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h index 6d3141e0..fcb4e3e7 100644 --- a/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h +++ b/Software/src/battery/IMIEV-CZERO-ION-BATTERY.h @@ -5,30 +5,29 @@ #include "../devboard/config.h" // Needed for all defines #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" -#define ABSOLUTE_MAX_VOLTAGE \ - 4040 // 404.4V,if battery voltage goes over this, charging is not possible (goes into forced discharge) -#define ABSOLUTE_MIN_VOLTAGE 3100 // 310.0V if battery voltage goes under this, discharging further is disabled +#define BATTERY_SELECTED -// These parameters need to be mapped for the Gen24 -extern uint16_t SOC; -extern uint16_t StateOfHealth; -extern uint16_t battery_voltage; -extern uint16_t battery_current; -extern uint16_t capacity_Wh; -extern uint16_t remaining_capacity_Wh; -extern uint16_t max_target_discharge_power; -extern uint16_t max_target_charge_power; -extern uint16_t stat_batt_power; -extern uint16_t temperature_min; -extern uint16_t temperature_max; -extern uint16_t CANerror; -extern uint16_t cell_max_voltage; -extern uint16_t cell_min_voltage; +// 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 -void update_values_imiev_battery(); -void receive_can_imiev_battery(CAN_frame_t rx_frame); -void send_can_imiev_battery(); +void setup_battery(void); #endif diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index d2011e36..4cb3a4cb 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -1,7 +1,9 @@ -#include "KIA-HYUNDAI-64-BATTERY.h" +#include "BATTERIES.h" +#ifdef KIA_HYUNDAI_64_BATTERY #include "../devboard/utils/events.h" #include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" +#include "KIA-HYUNDAI-64-BATTERY.h" /* Do not change code below unless you are sure what you are doing */ static unsigned long previousMillis100 = 0; // will store last time a 100ms CAN Message was send @@ -146,7 +148,7 @@ CAN_frame_t KIA64_7E4_ack = { .MsgID = 0x7E4, .data = {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; //Ack frame, correct PID is returned -void update_values_kiaHyundai_64_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus +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; @@ -293,7 +295,7 @@ void update_values_kiaHyundai_64_battery() { //This function maps all the value #endif } -void receive_can_kiaHyundai_64_battery(CAN_frame_t rx_frame) { +void receive_can_battery(CAN_frame_t rx_frame) { switch (rx_frame.MsgID) { case 0x4DE: break; @@ -523,7 +525,7 @@ void receive_can_kiaHyundai_64_battery(CAN_frame_t rx_frame) { } } -void send_can_kiaHyundai_64_battery() { +void send_can_battery() { unsigned long currentMillis = millis(); //Send 100ms message if (currentMillis - previousMillis100 >= interval100) { @@ -596,3 +598,12 @@ uint16_t convertToUnsignedInt16(int16_t signed_value) { 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 +} + +#endif diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h index 68f483da..1df80166 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h @@ -5,13 +5,14 @@ #include "../devboard/config.h" // Needed for all defines #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" -#define ABSOLUTE_MAX_VOLTAGE \ - 4040 // 404.4V,if battery voltage goes over this, charging is not possible (goes into forced discharge) -#define ABSOLUTE_MIN_VOLTAGE 3100 // 310.0V if battery voltage goes under this, discharging further is disabled +#define BATTERY_SELECTED + #define MAXCHARGEPOWERALLOWED 10000 #define MAXDISCHARGEPOWERALLOWED 10000 -// These parameters need to be mapped for the Gen24 +// 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) @@ -30,9 +31,7 @@ extern uint8_t nof_cellvoltages; // Total number of cell voltages, set by eac extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false -void update_values_kiaHyundai_64_battery(); -void receive_can_kiaHyundai_64_battery(CAN_frame_t rx_frame); -void send_can_kiaHyundai_64_battery(); 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 45a460c4..08ef5499 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.cpp +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.cpp @@ -1,3 +1,5 @@ +#include "BATTERIES.h" +#ifdef NISSAN_LEAF_BATTERY #include "NISSAN-LEAF-BATTERY.h" #ifdef MQTT #include "../devboard/mqtt/mqtt.h" @@ -165,7 +167,7 @@ void print_with_units(char* header, int value, char* units) { Serial.print(units); } -void update_values_leaf_battery() { /* This function maps all the values fetched via CAN to the correct parameters used for modbus */ +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% @@ -255,8 +257,7 @@ void update_values_leaf_battery() { /* This function maps all the values fetched } //Check if SOC% is plausible - if (battery_voltage > - (ABSOLUTE_MAX_VOLTAGE - 100)) { // When pack voltage is close to max, and SOC% is still low, raise FAULT + if (battery_voltage > (max_voltage - 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 { @@ -412,7 +413,7 @@ void update_values_leaf_battery() { /* This function maps all the values fetched #endif } -void receive_can_leaf_battery(CAN_frame_t rx_frame) { +void receive_can_battery(CAN_frame_t rx_frame) { switch (rx_frame.MsgID) { case 0x1DB: if (is_message_corrupt(rx_frame)) { @@ -676,7 +677,7 @@ void receive_can_leaf_battery(CAN_frame_t rx_frame) { break; } } -void send_can_leaf_battery() { +void send_can_battery() { unsigned long currentMillis = millis(); // Send 100ms CAN Message if (currentMillis - previousMillis100 >= interval100) { @@ -907,6 +908,12 @@ uint16_t Temp_fromRAW_to_F(uint16_t temperature) { //This function feels horrib return static_cast(1094 + (309 - temperature) * 2.5714285714285715); } -void init_battery(void) { +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 } + +#endif diff --git a/Software/src/battery/NISSAN-LEAF-BATTERY.h b/Software/src/battery/NISSAN-LEAF-BATTERY.h index 14cc9a8f..1d3ad7d1 100644 --- a/Software/src/battery/NISSAN-LEAF-BATTERY.h +++ b/Software/src/battery/NISSAN-LEAF-BATTERY.h @@ -5,11 +5,11 @@ #include "../devboard/config.h" // Needed for all defines #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" -#define ABSOLUTE_MAX_VOLTAGE \ - 4040 // 404.4V,if battery voltage goes over this, charging is not possible (goes into forced discharge) -#define ABSOLUTE_MIN_VOLTAGE 3100 // 310.0V if battery voltage goes under this, discharging further is disabled +#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) @@ -27,13 +27,9 @@ 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 -void update_values_leaf_battery(); -void receive_can_leaf_battery(CAN_frame_t rx_frame); -void send_can_leaf_battery(); 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 init_battery(void); +void setup_battery(void); #endif diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp index 1173cd21..eee07cb8 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.cpp @@ -1,7 +1,9 @@ -#include "RENAULT-KANGOO-BATTERY.h" +#include "BATTERIES.h" +#ifdef RENAULT_KANGOO_BATTERY #include "../devboard/utils/events.h" #include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" +#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 @@ -57,7 +59,7 @@ static const int interval10 = 10; // interval (ms) at which send CAN Messag static const int interval100 = 100; // interval (ms) at which send CAN Messages static const int interval1000 = 1000; // interval (ms) at which send CAN Messages -void update_values_kangoo_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus +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 @@ -175,7 +177,7 @@ void update_values_kangoo_battery() { //This function maps all the values fetch #endif } -void receive_can_kangoo_battery(CAN_frame_t rx_frame) //GKOE reworked +void receive_can_battery(CAN_frame_t rx_frame) //GKOE reworked { switch (rx_frame.MsgID) { @@ -237,7 +239,7 @@ void receive_can_kangoo_battery(CAN_frame_t rx_frame) //GKOE reworked } } -void send_can_kangoo_battery() { +void send_can_battery() { unsigned long currentMillis = millis(); // Send 100ms CAN Message (for 2.4s, then pause 10s) if ((currentMillis - previousMillis100) >= (interval100 + GVL_pause)) { @@ -267,3 +269,12 @@ uint16_t convert2uint16(int16_t signed_value) { 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 +} + +#endif diff --git a/Software/src/battery/RENAULT-KANGOO-BATTERY.h b/Software/src/battery/RENAULT-KANGOO-BATTERY.h index fc4a7af5..593811d9 100644 --- a/Software/src/battery/RENAULT-KANGOO-BATTERY.h +++ b/Software/src/battery/RENAULT-KANGOO-BATTERY.h @@ -5,16 +5,17 @@ #include "../devboard/config.h" // Needed for defines #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" -#define ABSOLUTE_MAX_VOLTAGE \ - 4040 // 404.4V,if battery voltage goes over this, charging is not possible (goes into forced discharge) -#define ABSOLUTE_MIN_VOLTAGE 3100 // 310.0V if battery voltage goes under this, discharging further is disabled +#define BATTERY_SELECTED + #define ABSOLUTE_CELL_MAX_VOLTAGE \ 4100 // Max Cell Voltage mV! if voltage goes over this, charging is not possible (goes into forced discharge) #define ABSOLUTE_CELL_MIN_VOLTAGE \ 3000 // Min Cell Voltage mV! if voltage goes under this, discharging further is disabled #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 Gen24 +// 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) @@ -32,9 +33,7 @@ extern uint16_t CANerror; extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false -void update_values_kangoo_battery(); -void receive_can_kangoo_battery(CAN_frame_t rx_frame); -void send_can_kangoo_battery(); 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 bf9c7b4a..1c718077 100644 --- a/Software/src/battery/RENAULT-ZOE-BATTERY.cpp +++ b/Software/src/battery/RENAULT-ZOE-BATTERY.cpp @@ -1,7 +1,9 @@ -#include "RENAULT-ZOE-BATTERY.h" +#include "BATTERIES.h" +#ifdef RENAULT_ZOE_BATTERY #include "../devboard/utils/events.h" #include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" +#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 @@ -42,7 +44,7 @@ static const int interval10 = 10; // interval (ms) at which send CAN Messag static const int interval100 = 100; // interval (ms) at which send CAN Messages static const int interval1000 = 1000; // interval (ms) at which send CAN Messages -void update_values_zoe_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus +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 @@ -136,7 +138,7 @@ void update_values_zoe_battery() { //This function maps all the values fetched #endif } -void receive_can_zoe_battery(CAN_frame_t rx_frame) { +void receive_can_battery(CAN_frame_t rx_frame) { switch (rx_frame.MsgID) { case 0x42E: //HV SOC & Battery Temp & Charging Power @@ -150,7 +152,7 @@ void receive_can_zoe_battery(CAN_frame_t rx_frame) { } } -void send_can_zoe_battery() { +void send_can_battery() { unsigned long currentMillis = millis(); // Send 100ms CAN Message if (currentMillis - previousMillis100 >= interval100) { @@ -163,3 +165,12 @@ void send_can_zoe_battery() { //ESP32Can.CANWriteFrame(&ZOE_423); } } + +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 +} + +#endif diff --git a/Software/src/battery/RENAULT-ZOE-BATTERY.h b/Software/src/battery/RENAULT-ZOE-BATTERY.h index bb34f4c0..b5eef243 100644 --- a/Software/src/battery/RENAULT-ZOE-BATTERY.h +++ b/Software/src/battery/RENAULT-ZOE-BATTERY.h @@ -5,16 +5,17 @@ #include "../devboard/config.h" // Needed for all defines #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" -#define ABSOLUTE_MAX_VOLTAGE \ - 4040 // 404.4V,if battery voltage goes over this, charging is not possible (goes into forced discharge) -#define ABSOLUTE_MIN_VOLTAGE 3100 // 310.0V if battery voltage goes under this, discharging further is disabled +#define BATTERY_SELECTED + #define ABSOLUTE_CELL_MAX_VOLTAGE \ 4100 // Max Cell Voltage mV! if voltage goes over this, charging is not possible (goes into forced discharge) #define ABSOLUTE_CELL_MIN_VOLTAGE \ 3000 // Min Cell Voltage mV! if voltage goes under this, discharging further is disabled #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 Gen24 +// 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) @@ -32,8 +33,6 @@ extern uint16_t CANerror; extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false -void update_values_zoe_battery(); -void receive_can_zoe_battery(CAN_frame_t rx_frame); -void send_can_zoe_battery(); +void setup_battery(void); #endif diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp index 1e7b2b94..f6717089 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.cpp @@ -1,7 +1,9 @@ -#include "SANTA-FE-PHEV-BATTERY.h" +#include "BATTERIES.h" +#ifdef SANTA_FE_PHEV_BATTERY #include "../devboard/utils/events.h" #include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" +#include "SANTA-FE-PHEV-BATTERY.h" /* Credits go to maciek16c for these findings! https://github.com/maciek16c/hyundai-santa-fe-phev-battery @@ -57,7 +59,7 @@ CAN_frame_t SANTAFE_523 = {.FIR = {.B = .MsgID = 0x523, .data = {0x60, 0x00, 0x60, 0, 0, 0, 0, 0}}; -void update_values_santafe_phev_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus +void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus SOC; @@ -92,7 +94,7 @@ void update_values_santafe_phev_battery() { //This function maps all the values #endif } -void receive_can_santafe_phev_battery(CAN_frame_t rx_frame) { +void receive_can_battery(CAN_frame_t rx_frame) { CANstillAlive = 12; switch (rx_frame.MsgID) { case 0x200: @@ -127,7 +129,7 @@ void receive_can_santafe_phev_battery(CAN_frame_t rx_frame) { break; } } -void send_can_santafe_phev_battery() { +void send_can_battery() { unsigned long currentMillis = millis(); //Send 10ms message if (currentMillis - previousMillis10 >= interval10) { @@ -174,3 +176,12 @@ uint8_t CalculateCRC8(CAN_frame_t rx_frame) { } return (uint8_t)crc; } + +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 +} + +#endif diff --git a/Software/src/battery/SANTA-FE-PHEV-BATTERY.h b/Software/src/battery/SANTA-FE-PHEV-BATTERY.h index 03bd0ab4..ff136a48 100644 --- a/Software/src/battery/SANTA-FE-PHEV-BATTERY.h +++ b/Software/src/battery/SANTA-FE-PHEV-BATTERY.h @@ -5,29 +5,28 @@ #include "../devboard/config.h" // Needed for all defines #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" -#define ABSOLUTE_MAX_VOLTAGE \ - 4030 // 403.0V,if battery voltage goes over this, charging is not possible (goes into forced discharge) -#define ABSOLUTE_MIN_VOLTAGE 3100 // 310.0V if battery voltage goes under this, discharging further is disabled +#define BATTERY_SELECTED -// These parameters need to be mapped for the Gen24 -extern uint16_t SOC; -extern uint16_t StateOfHealth; -extern uint16_t battery_voltage; -extern uint16_t battery_current; -extern uint16_t capacity_Wh; -extern uint16_t remaining_capacity_Wh; -extern uint16_t max_target_discharge_power; -extern uint16_t max_target_charge_power; -extern uint16_t stat_batt_power; -extern uint16_t temperature_min; -extern uint16_t temperature_max; -extern uint16_t CANerror; -extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false -extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false +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 -void update_values_santafe_phev_battery(); -void receive_can_santafe_phev_battery(CAN_frame_t rx_frame); -void send_can_santafe_phev_battery(); uint8_t CalculateCRC8(CAN_frame_t rx_frame); +void setup_battery(void); #endif diff --git a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.h b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.h index c1ec844a..e0824825 100644 --- a/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.h +++ b/Software/src/battery/SERIAL-LINK-RECEIVER-FROM-BATTERY.h @@ -10,11 +10,9 @@ // https://github.com/mackelec/SerialDataLink -#define ABSOLUTE_MAX_VOLTAGE \ - 4040 // 404.4V,if battery voltage goes over this, charging is not possible (goes into forced discharge) -#define ABSOLUTE_MIN_VOLTAGE 3100 // 310.0V if battery voltage goes under this, discharging further is disabled - // 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) diff --git a/Software/src/battery/TESLA-MODEL-3-BATTERY.cpp b/Software/src/battery/TESLA-MODEL-3-BATTERY.cpp index 3e9508a7..ce9df946 100644 --- a/Software/src/battery/TESLA-MODEL-3-BATTERY.cpp +++ b/Software/src/battery/TESLA-MODEL-3-BATTERY.cpp @@ -1,7 +1,9 @@ -#include "TESLA-MODEL-3-BATTERY.h" +#include "BATTERIES.h" +#ifdef TESLA_MODEL_3_BATTERY #include "../devboard/utils/events.h" #include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" +#include "TESLA-MODEL-3-BATTERY.h" /* Do not change code below unless you are sure what you are doing */ /* Credits: Most of the code comes from Per Carlen's bms_comms_tesla_model3.py (https://gitlab.com/pelle8/batt2gen24/) */ @@ -48,10 +50,10 @@ static uint16_t regenerative_limit = 0; static uint16_t discharge_limit = 0; static uint16_t max_heat_park = 0; static uint16_t hvac_max_power = 0; -static uint16_t min_voltage = 0; static uint16_t max_discharge_current = 0; static uint16_t max_charge_current = 0; -static uint16_t max_voltage = 0; +static uint16_t bms_max_voltage = 0; +static uint16_t bms_min_voltage = 0; static uint16_t high_voltage = 0; static uint16_t low_voltage = 0; static uint16_t output_current = 0; @@ -163,7 +165,7 @@ static const char* hvilStatusState[] = {"NOT OK", #define REASONABLE_ENERGYAMOUNT 20 //When the BMS stops making sense on some values, they are always <20 -void update_values_tesla_model_3_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus +void update_values_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus //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 @@ -242,7 +244,7 @@ void update_values_tesla_model_3_battery() { //This function maps all the value cell_deviation_mV = (cell_max_v - cell_min_v); - //Determine which chemistry battery pack is using (crude method, TODO: replace with real CAN data later) + //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; @@ -251,11 +253,23 @@ void update_values_tesla_model_3_battery() { //This function maps all the value 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; + } + + //Once cell chemistry is determined, set maximum and minimum total pack voltage safety limits + if (LFP_Chemistry) { + max_voltage = 3640; + min_voltage = 2450; + } else { // NCM/A chemistry + max_voltage = 4030; + min_voltage = 3100; + } //Check if SOC% is plausible - if (battery_voltage > - (ABSOLUTE_MAX_VOLTAGE - 100)) { // When pack voltage is close to max, and SOC% is still low, raise FAULT - if (SOC < 6500) { //When SOC is less than 65.00% when approaching max voltage + if (battery_voltage > (max_voltage - 100)) { // When pack voltage is close to max, and SOC% is still low, raise FAULT + if (SOC < 6500) { //When SOC is less than 65.00% when approaching max voltage set_event(EVENT_SOC_PLAUSIBILITY_ERROR, SOC / 100); } } @@ -335,6 +349,7 @@ void update_values_tesla_model_3_battery() { //This function maps all the value if (LFP_Chemistry) { Serial.print("LFP chemistry detected!"); } + Serial.print(nof_cellvoltages); Serial.println(""); Serial.print("Cellstats, Max: "); Serial.print(cell_max_v); @@ -368,7 +383,7 @@ void update_values_tesla_model_3_battery() { //This function maps all the value #endif } -void receive_can_tesla_model_3_battery(CAN_frame_t rx_frame) { +void receive_can_battery(CAN_frame_t rx_frame) { static int mux = 0; static int temp = 0; @@ -481,8 +496,10 @@ void receive_can_tesla_model_3_battery(CAN_frame_t rx_frame) { break; case 0x2d2: //Min / max limits - min_voltage = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * 0.01 * 2; //Example 24148mv * 0.01 = 241.48 V - max_voltage = ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * 0.01 * 2; //Example 40282mv * 0.01 = 402.82 V + bms_min_voltage = + ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[0]) * 0.01 * 2; //Example 24148mv * 0.01 = 241.48 V + bms_max_voltage = + ((rx_frame.data.u8[3] << 8) | rx_frame.data.u8[2]) * 0.01 * 2; //Example 40282mv * 0.01 = 402.82 V max_charge_current = (((rx_frame.data.u8[5] & 0x3F) << 8) | rx_frame.data.u8[4]) * 0.1; //Example 1301? * 0.1 = 130.1? max_discharge_current = @@ -558,7 +575,7 @@ void receive_can_tesla_model_3_battery(CAN_frame_t rx_frame) { break; } } -void send_can_tesla_model_3_battery() { +void send_can_battery() { /*From bielec: My fist 221 message, to close the contactors is 0x41, 0x11, 0x01, 0x00, 0x00, 0x00, 0x20, 0x96 and then, to cause "hv_up_for_drive" I send an additional 221 message 0x61, 0x15, 0x01, 0x00, 0x00, 0x00, 0x20, 0xBA so two 221 messages are being continuously transmitted. When I want to shut down, I stop the second message and only send @@ -683,3 +700,12 @@ void printDebugIfActive(uint8_t symbol, const char* message) { Serial.println(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 +} + +#endif diff --git a/Software/src/battery/TESLA-MODEL-3-BATTERY.h b/Software/src/battery/TESLA-MODEL-3-BATTERY.h index 0d1fa9b8..4432bef1 100644 --- a/Software/src/battery/TESLA-MODEL-3-BATTERY.h +++ b/Software/src/battery/TESLA-MODEL-3-BATTERY.h @@ -5,14 +5,15 @@ #include "../devboard/config.h" // Needed for all defines #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" -#define ABSOLUTE_MAX_VOLTAGE \ - 4030 // 403.0V,if battery voltage goes over this, charging is not possible (goes into forced discharge) -#define ABSOLUTE_MIN_VOLTAGE 2450 // 245.0V if battery voltage goes under this, discharging further is disabled +#define BATTERY_SELECTED + #define MAXCHARGEPOWERALLOWED 15000 // 15000W we use a define since the value supplied by Tesla is always 0 #define MAXDISCHARGEPOWERALLOWED \ 60000 // 60000W we need to cap this value to max 60kW, most inverters overflow otherwise -// These parameters need to be mapped for the Inverter +// 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) @@ -32,13 +33,11 @@ extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false extern bool LFP_Chemistry; -void update_values_tesla_model_3_battery(); -void receive_can_tesla_model_3_battery(CAN_frame_t rx_frame); -void send_can_tesla_model_3_battery(); 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 dcce6e04..045521f5 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.cpp +++ b/Software/src/battery/TEST-FAKE-BATTERY.cpp @@ -1,6 +1,8 @@ -#include "TEST-FAKE-BATTERY.h" +#include "BATTERIES.h" +#ifdef TEST_FAKE_BATTERY #include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" +#include "TEST-FAKE-BATTERY.h" /* Do not change code below unless you are sure what you are doing */ static unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was send @@ -16,8 +18,8 @@ void print_units(char* header, int value, char* units) { Serial.print(units); } -void update_values_test_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 */ + SOC = 5000; // 50.00% StateOfHealth = 9900; // 99.00% @@ -63,7 +65,7 @@ void update_values_test_battery() { /* This function puts fake values onto the p #endif } -void receive_can_test_battery(CAN_frame_t rx_frame) { +void receive_can_battery(CAN_frame_t rx_frame) { switch (rx_frame.MsgID) { case 0xABC: break; @@ -71,7 +73,7 @@ void receive_can_test_battery(CAN_frame_t rx_frame) { break; } } -void send_can_test_battery() { +void send_can_battery() { unsigned long currentMillis = millis(); // Send 100ms CAN Message if (currentMillis - previousMillis100 >= interval100) { @@ -79,3 +81,12 @@ void send_can_test_battery() { // Put fake messages here incase you want to test sending CAN } } + +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 +} + +#endif diff --git a/Software/src/battery/TEST-FAKE-BATTERY.h b/Software/src/battery/TEST-FAKE-BATTERY.h index b6bfb209..991aaf2a 100644 --- a/Software/src/battery/TEST-FAKE-BATTERY.h +++ b/Software/src/battery/TEST-FAKE-BATTERY.h @@ -5,11 +5,11 @@ #include "../devboard/config.h" // Needed for all defines #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" -#define ABSOLUTE_MAX_VOLTAGE \ - 4040 // 404.4V,if battery voltage goes over this, charging is not possible (goes into forced discharge) -#define ABSOLUTE_MIN_VOLTAGE 3100 // 310.0V if battery voltage goes under this, discharging further is disabled +#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) @@ -28,8 +28,6 @@ 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 -void update_values_test_battery(); -void receive_can_test_battery(CAN_frame_t rx_frame); -void send_can_test_battery(); +void setup_battery(void); #endif diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index 9862bcde..58c45f56 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -142,6 +142,7 @@ void init_events(void) { events.entries[EVENT_CELL_DEVIATION_HIGH].level = EVENT_LEVEL_WARNING; events.entries[EVENT_UNKNOWN_EVENT_SET].level = EVENT_LEVEL_ERROR; events.entries[EVENT_OTA_UPDATE].level = EVENT_LEVEL_UPDATE; + events.entries[EVENT_OTA_UPDATE_TIMEOUT].level = EVENT_LEVEL_INFO; events.entries[EVENT_DUMMY_INFO].level = EVENT_LEVEL_INFO; events.entries[EVENT_DUMMY_DEBUG].level = EVENT_LEVEL_DEBUG; events.entries[EVENT_DUMMY_WARNING].level = EVENT_LEVEL_WARNING; @@ -235,6 +236,8 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) { return "Error in serial function: Some ERROR level fault in transmitter, received by receiver"; case EVENT_OTA_UPDATE: return "OTA update started!"; + case EVENT_OTA_UPDATE_TIMEOUT: + return "OTA update timed out!"; case EVENT_EEPROM_WRITE: return "Info: The EEPROM was written"; default: diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index 633c076f..83b0f499 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -41,6 +41,7 @@ XX(EVENT_CELL_DEVIATION_HIGH) \ XX(EVENT_UNKNOWN_EVENT_SET) \ XX(EVENT_OTA_UPDATE) \ + XX(EVENT_OTA_UPDATE_TIMEOUT) \ XX(EVENT_DUMMY_INFO) \ XX(EVENT_DUMMY_DEBUG) \ XX(EVENT_DUMMY_WARNING) \ diff --git a/Software/src/devboard/webserver/webserver.cpp b/Software/src/devboard/webserver/webserver.cpp index 30dd8105..babd9770 100644 --- a/Software/src/devboard/webserver/webserver.cpp +++ b/Software/src/devboard/webserver/webserver.cpp @@ -1,6 +1,7 @@ #include "webserver.h" #include #include "../utils/events.h" +#include "../utils/timer.h" // Create AsyncWebServer object on port 80 AsyncWebServer server(80); @@ -21,6 +22,9 @@ enum WifiState { WifiState wifi_state = INIT; +MyTimer ota_timeout_timer = MyTimer(5000); +bool ota_active = false; + unsigned const long WIFI_MONITOR_INTERVAL_TIME = 15000; unsigned const long INIT_WIFI_CONNECT_TIMEOUT = 8000; // Timeout for initial WiFi connect in milliseconds unsigned const long DEFAULT_WIFI_RECONNECT_INTERVAL = 1000; // Default WiFi reconnect interval in ms @@ -299,6 +303,14 @@ void wifi_monitor() { Serial.println(" Hostname: " + String(WiFi.getHostname())); } } + + if (ota_active && ota_timeout_timer.elapsed()) { + // OTA timeout, try to restore can and clear the update event + ESP32Can.CANInit(); + clear_event(EVENT_OTA_UPDATE); + set_event(EVENT_OTA_UPDATE_TIMEOUT, 0); + ota_active = false; + } } void init_WiFi_STA(const char* ssid, const char* password, const uint8_t wifi_channel) { @@ -635,6 +647,11 @@ void onOTAStart() { // Log when OTA has started ESP32Can.CANStop(); set_event(EVENT_OTA_UPDATE, 0); + + // If already set, make a new attempt + clear_event(EVENT_OTA_UPDATE_TIMEOUT); + ota_active = true; + ota_timeout_timer.reset(); } void onOTAProgress(size_t current, size_t final) { @@ -642,6 +659,9 @@ void onOTAProgress(size_t current, size_t final) { if (millis() - ota_progress_millis > 1000) { ota_progress_millis = millis(); Serial.printf("OTA Progress Current: %u bytes, Final: %u bytes\n", current, final); + + // Reset the "watchdog" + ota_timeout_timer.reset(); } } @@ -651,7 +671,11 @@ void onOTAEnd(bool success) { Serial.println("OTA update finished successfully!"); } else { Serial.println("There was an error during OTA update!"); + + // If we fail without a timeout, try to restore CAN + ESP32Can.CANInit(); } + ota_active = false; clear_event(EVENT_OTA_UPDATE); } diff --git a/Software/src/inverter/INVERTERS.h b/Software/src/inverter/INVERTERS.h index 01a9d550..979051de 100644 --- a/Software/src/inverter/INVERTERS.h +++ b/Software/src/inverter/INVERTERS.h @@ -21,6 +21,10 @@ #include "SMA-CAN.h" #endif +#ifdef SMA_TRIPOWER_CAN +#include "SMA-TRIPOWER-CAN.h" +#endif + #ifdef SOFAR_CAN #include "SOFAR-CAN.h" #endif diff --git a/Software/src/inverter/SMA-CAN.cpp b/Software/src/inverter/SMA-CAN.cpp index 5ec6554e..abd73c70 100644 --- a/Software/src/inverter/SMA-CAN.cpp +++ b/Software/src/inverter/SMA-CAN.cpp @@ -2,6 +2,8 @@ #include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h" #include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" +/* TODO: Map error bits in 0x158 */ + /* Do not change code below unless you are sure what you are doing */ static unsigned long previousMillis100ms = 0; // will store last time a 100ms CAN Message was send static const int interval100ms = 100; // interval (ms) at which send CAN Messages @@ -94,10 +96,12 @@ CAN_frame_t SMA_158 = {.FIR = {.B = .MsgID = 0x158, .data = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x6A, 0xAA, 0xAA}}; -static int discharge_current = 0; -static int charge_current = 0; -static int temperature_average = 0; -static int ampere_hours_remaining = 0; +static int16_t discharge_current = 0; +static int16_t charge_current = 0; +static int16_t temperature_average = 0; +static int16_t temp_min = 0; +static int16_t temp_max = 0; +static uint16_t ampere_hours_remaining = 0; void update_values_can_sma() { //This function maps all the values fetched from battery CAN to the correct CAN messages //Calculate values @@ -111,7 +115,9 @@ void update_values_can_sma() { //This function maps all the values fetched from //The above calculation results in (30 000*10)/3700=81A discharge_current = (discharge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A) - temperature_average = ((temperature_max + temperature_min) / 2); + temp_min = temperature_min; //Convert from unsigned to signed + temp_max = temperature_max; + temperature_average = ((temp_max + temp_min) / 2); ampere_hours_remaining = ((remaining_capacity_Wh / battery_voltage) * 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah) @@ -149,10 +155,63 @@ void update_values_can_sma() { //This function maps all the values fetched from //Temperature average SMA_4D8.data.u8[4] = (temperature_average >> 8); SMA_4D8.data.u8[5] = (temperature_average & 0x00FF); + //Battery ready + if (bms_status == ACTIVE) { + SMA_4D8.data.u8[6] = READY_STATE; + } else { + SMA_4D8.data.u8[6] = STOP_STATE; + } //Error bits + /* //SMA_158.data.u8[0] = //bit12 Fault high temperature, bit34Battery cellundervoltage, bit56 Battery cell overvoltage, bit78 batterysystemdefect //TODO: add all error bits. Sending message with all 0xAA until that. + + 0x158 can be used to send error messages or warnings. + + Each message is defined of two bits: + 01=message triggered + 10=no message triggered + 0xA9=10101001, triggers first message + 0xA6=10100110, triggers second message + 0x9A=10011010, triggers third message + 0x6A=01101010, triggers forth message + bX defines the byte + + b0 A9 Battery system defect + b0 A6 Battery cell overvoltage fault + b0 9A Battery cell undervoltage fault + b0 6A Battery high temperature fault + b1 A9 Battery low temperature fault + b1 A6 Battery high temperature fault + b1 9A Battery low temperature fault + b1 6A Overload (reboot required) + b2 A9 Overload (reboot required) + b2 A6 Incorrect switch position for the battery disconnection point + b2 9A Battery system short circuit + b2 6A Internal battery hardware fault + b3 A9 Battery imbalancing fault + b3 A6 Battery service life expiry + b3 9A Battery system thermal management defective + b3 6A Internal battery hardware fault + b4 A9 Battery system defect (warning) + b4 A6 Battery cell overvoltage fault (warning) + b4 9A Battery cell undervoltage fault (warning) + b4 6A Battery high temperature fault (warning) + b5 A9 Battery low temperature fault (warning) + b5 A6 Battery high temperature fault (warning) + b5 9A Battery low temperature fault (warning) + b5 6A Self-diagnosis (warning) + b6 A9 Self-diagnosis (warning) + b6 A6 Incorrect switch position for the battery disconnection point (warning) + b6 9A Battery system short circuit (warning) + b6 6A Internal battery hardware fault (warning) + b7 A9 Battery imbalancing fault (warning) + b7 A6 Battery service life expiry (warning) + b7 9A Battery system thermal management defective (warning) + b7 6A Internal battery hardware fault (warning) + +*/ } void receive_can_sma(CAN_frame_t rx_frame) { @@ -164,11 +223,11 @@ void receive_can_sma(CAN_frame_t rx_frame) { case 0x420: //Message originating from SMA inverter - Timestamp //Frame0-3 Timestamp break; - case 0x660: //Message originating from SMA inverter + case 0x3E0: //Message originating from SMA inverter - ? break; - case 0x5E0: //Message originating from SMA inverter + case 0x5E0: //Message originating from SMA inverter - String break; - case 0x560: //Message originating from SMA inverter + case 0x560: //Message originating from SMA inverter - Init break; default: break; @@ -185,9 +244,9 @@ void send_can_sma() { ESP32Can.CANWriteFrame(&SMA_558); ESP32Can.CANWriteFrame(&SMA_598); ESP32Can.CANWriteFrame(&SMA_5D8); - ESP32Can.CANWriteFrame(&SMA_618_1); - ESP32Can.CANWriteFrame(&SMA_618_2); - ESP32Can.CANWriteFrame(&SMA_618_3); + ESP32Can.CANWriteFrame(&SMA_618_1); // TODO, should these 3x + ESP32Can.CANWriteFrame(&SMA_618_2); // be sent as batch? + ESP32Can.CANWriteFrame(&SMA_618_3); // or alternate on each send? ESP32Can.CANWriteFrame(&SMA_358); ESP32Can.CANWriteFrame(&SMA_3D8); ESP32Can.CANWriteFrame(&SMA_458); diff --git a/Software/src/inverter/SMA-CAN.h b/Software/src/inverter/SMA-CAN.h index 29e87b7f..30227b1e 100644 --- a/Software/src/inverter/SMA-CAN.h +++ b/Software/src/inverter/SMA-CAN.h @@ -18,11 +18,15 @@ extern uint16_t temperature_min; //C+1, Goes thru convert2unsignedint16 funct 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 uint8_t bms_status; extern uint16_t min_voltage; extern uint16_t max_voltage; extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false +#define READY_STATE 0x03 +#define STOP_STATE 0x02 + void update_values_can_sma(); void send_can_sma(); void receive_can_sma(CAN_frame_t rx_frame); diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.cpp b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp new file mode 100644 index 00000000..963c4407 --- /dev/null +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.cpp @@ -0,0 +1,364 @@ +#include "SMA-TRIPOWER-CAN.h" +#include "../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h" +#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" + +/* TODO: +- Figure out the manufacturer info needed in send_tripower_init() CAN messages + - CAN logs from real system might be needed +- Figure out how cellvoltages need to be displayed +- Figure out if sending send_tripower_init() like we do now is OK +- Figure out how to send the non-cyclic messages when needed +*/ + +/* Do not change code below unless you are sure what you are doing */ +static unsigned long previousMillis500ms = 0; // will store last time a 100ms CAN Message was send +static const int interval500ms = 100; // interval (ms) at which send CAN Messages + +//Actual content messages +static CAN_frame_t SMA_00D = { // Battery Limits + .FIR = {.B = + { + .DLC = 8, + .FF = CAN_frame_std, + }}, + .MsgID = 0x00D, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +static CAN_frame_t SMA_00F = { // Battery State + .FIR = {.B = + { + .DLC = 8, + .FF = CAN_frame_std, + }}, + .MsgID = 0x00F, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +static CAN_frame_t SMA_011 = { // Battery Energy + .FIR = {.B = + { + .DLC = 8, + .FF = CAN_frame_std, + }}, + .MsgID = 0x011, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +static CAN_frame_t SMA_013 = { // Battery Measurements + .FIR = {.B = + { + .DLC = 8, + .FF = CAN_frame_std, + }}, + .MsgID = 0x013, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +static CAN_frame_t SMA_014 = { // Battery Tempeartures and Cellvoltages + .FIR = {.B = + { + .DLC = 8, + .FF = CAN_frame_std, + }}, + .MsgID = 0x014, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +static CAN_frame_t SMA_005 = { // Battery Alarms 1 + .FIR = {.B = + { + .DLC = 8, + .FF = CAN_frame_std, + }}, + .MsgID = 0x005, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +static CAN_frame_t SMA_007 = { // Battery Alarms 2 + .FIR = {.B = + { + .DLC = 8, + .FF = CAN_frame_std, + }}, + .MsgID = 0x007, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +static CAN_frame_t SMA_006 = { // Battery Error Codes + .FIR = {.B = + { + .DLC = 8, + .FF = CAN_frame_std, + }}, + .MsgID = 0x006, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +static CAN_frame_t SMA_008 = { // Battery Events + .FIR = {.B = + { + .DLC = 8, + .FF = CAN_frame_std, + }}, + .MsgID = 0x008, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +static CAN_frame_t SMA_015 = { // Battery Data 1 + .FIR = {.B = + { + .DLC = 8, + .FF = CAN_frame_std, + }}, + .MsgID = 0x015, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +static CAN_frame_t SMA_016 = { // Battery Data 2 + .FIR = {.B = + { + .DLC = 8, + .FF = CAN_frame_std, + }}, + .MsgID = 0x016, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +static CAN_frame_t SMA_017 = { // Battery Manufacturer + .FIR = {.B = + { + .DLC = 8, + .FF = CAN_frame_std, + }}, + .MsgID = 0x017, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; +static CAN_frame_t SMA_018 = { // Battery Name + .FIR = {.B = + { + .DLC = 8, + .FF = CAN_frame_std, + }}, + .MsgID = 0x018, + .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; + +static int discharge_current = 0; +static int charge_current = 0; +static int temperature_average = 0; +static int ampere_hours_remaining = 0; +static int ampere_hours_max = 0; +static bool batteryAlarm = false; +static bool BMSevent = false; + +enum BatteryState { NA, INIT, BAT_STANDBY, OPERATE, WARNING, FAULTED, UPDATE, BAT_UPDATE }; +BatteryState batteryState = OPERATE; +enum InverterControlFlags { + EMG_CHARGE_REQUEST, + EMG_DISCHARGE_REQUEST, + NOT_ENOUGH_ENERGY_FOR_START, + INVERTER_STAY_ON, + FORCED_BATTERY_SHUTDOWN, + RESERVED, + BATTERY_UPDATE_AVAILABLE, + NO_BATTERY_UPDATED_BY_INV +}; +InverterControlFlags inverterControlFlags = BATTERY_UPDATE_AVAILABLE; +enum Events0 { + START_SOC_CALIBRATE, + STOP_SOC_CALIBRATE, + START_POWERLIMIT, + STOP_POWERLIMIT, + PREVENTATIVE_BAT_SHUTDOWN, + THERMAL_MANAGEMENT, + START_BALANCING, + STOP_BALANCING +}; +Events0 events0 = START_BALANCING; +enum Events1 { START_BATTERY_SELFTEST, STOP_BATTERY_SELFTEST }; +Events1 events1 = START_BATTERY_SELFTEST; +enum Command2Battery { IDLE, RUN, NOT_USED1, NOT_USED2, SHUTDOWN, FIRMWARE_UPDATE, BATSELFUPDATE, NOT_USED3 }; +Command2Battery command2Battery = RUN; +enum InvInitState { SYSTEM_FREQUENCY, XPHASE_SYSTEM, BLACKSTART_OPERATION }; +InvInitState invInitState = SYSTEM_FREQUENCY; + +void update_values_can_sma_tripower() { //This function maps all the values fetched from battery CAN to the inverter CAN + //Calculate values + charge_current = + ((max_target_charge_power * 10) / max_voltage); //Charge power in W , max volt in V+1decimal (P=UI, solve for I) + //The above calculation results in (30 000*10)/3700=81A + charge_current = (charge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A) + + discharge_current = ((max_target_discharge_power * 10) / + max_voltage); //Charge power in W , max volt in V+1decimal (P=UI, solve for I) + //The above calculation results in (30 000*10)/3700=81A + discharge_current = (discharge_current * 10); //Value needs a decimal before getting sent to inverter (81.0A) + + temperature_average = ((temperature_max + temperature_min) / 2); + + ampere_hours_remaining = + ((remaining_capacity_Wh / battery_voltage) * 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah) + ampere_hours_max = ((capacity_Wh / battery_voltage) * 100); //(WH[10000] * V+1[3600])*100 = 270 (27.0Ah) + + batteryState = OPERATE; + inverterControlFlags = INVERTER_STAY_ON; + + //Map values to CAN messages + // Battery Limits + //Battery Max Charge Voltage (eg 400.0V = 4000 , 16bits long) + SMA_00D.data.u8[0] = (max_voltage >> 8); + SMA_00D.data.u8[1] = (max_voltage & 0x00FF); + //Battery Min Discharge Voltage (eg 300.0V = 3000 , 16bits long) + SMA_00D.data.u8[2] = (min_voltage >> 8); + SMA_00D.data.u8[3] = (min_voltage & 0x00FF); + //Discharge limited current, 500 = 50A, (0.1, A) + SMA_00D.data.u8[4] = (discharge_current >> 8); + SMA_00D.data.u8[5] = (discharge_current & 0x00FF); + //Charge limited current, 125 =12.5A (0.1, A) + SMA_00D.data.u8[6] = (charge_current >> 8); + SMA_00D.data.u8[7] = (charge_current & 0x00FF); + + // Battery State + //SOC (100.00%) + SMA_00F.data.u8[0] = (SOC >> 8); + SMA_00F.data.u8[1] = (SOC & 0x00FF); + //StateOfHealth (100.00%) + SMA_00F.data.u8[2] = (StateOfHealth >> 8); + SMA_00F.data.u8[3] = (StateOfHealth & 0x00FF); + //State of charge (AH, 0.1) + SMA_00F.data.u8[4] = (ampere_hours_remaining >> 8); + SMA_00F.data.u8[5] = (ampere_hours_remaining & 0x00FF); + //Fully charged (AH, 0.1) + SMA_00F.data.u8[6] = (ampere_hours_max >> 8); + SMA_00F.data.u8[7] = (ampere_hours_max & 0x00FF); + + // Battery Energy + //Charged Energy Counter TODO: are these needed? + //SMA_011.data.u8[0] = (X >> 8); + //SMA_011.data.u8[1] = (X & 0x00FF); + //SMA_011.data.u8[2] = (X >> 8); + //SMA_011.data.u8[3] = (X & 0x00FF); + //Discharged Energy Counter TODO: are these needed? + //SMA_011.data.u8[4] = (X >> 8); + //SMA_011.data.u8[5] = (X & 0x00FF); + //SMA_011.data.u8[6] = (X >> 8); + //SMA_011.data.u8[7] = (X & 0x00FF); + + // Battery Measurements + //Voltage (370.0) + SMA_013.data.u8[0] = (battery_voltage >> 8); + SMA_013.data.u8[1] = (battery_voltage & 0x00FF); + //Current (TODO: signed OK?) + SMA_013.data.u8[2] = (battery_current >> 8); + SMA_013.data.u8[3] = (battery_current & 0x00FF); + //Temperature average + SMA_013.data.u8[4] = (temperature_average >> 8); + SMA_013.data.u8[5] = (temperature_average & 0x00FF); + //Battery state + SMA_013.data.u8[6] = batteryState; + SMA_013.data.u8[6] = inverterControlFlags; + + // Battery Temperature and Cellvoltages + // Battery max temperature + SMA_014.data.u8[0] = (temperature_max >> 8); + SMA_014.data.u8[1] = (temperature_max & 0x00FF); + // Battery min temperature + SMA_014.data.u8[2] = (temperature_min >> 8); + SMA_014.data.u8[3] = (temperature_min & 0x00FF); + // Battery Cell Voltage (sum) + //SMA_014.data.u8[4] = (??? >> 8); //TODO scaling? + //SMA_014.data.u8[5] = (??? & 0x00FF); //TODO scaling? + // Cell voltage min + //SMA_014.data.u8[6] = (??? >> 8); //TODO scaling? 0-255 + // Cell voltage max + //SMA_014.data.u8[7] = (??? >> 8); //TODO scaling? 0-255 + + //SMA_006.data.u8[0] = (ErrorCode >> 8); + //SMA_006.data.u8[1] = (ErrorCode & 0x00FF); + //SMA_006.data.u8[2] = ModuleNumber; + //SMA_006.data.u8[3] = ErrorLevel; + //SMA_008.data.u8[0] = Events0; + //SMA_008.data.u8[1] = Events1; + + //SMA_005.data.u8[0] = BMSalarms0; + //SMA_005.data.u8[1] = BMSalarms1; + //SMA_005.data.u8[2] = BMSalarms2; + //SMA_005.data.u8[3] = BMSalarms3; + //SMA_005.data.u8[4] = BMSalarms4; + //SMA_005.data.u8[5] = BMSalarms5; + //SMA_005.data.u8[6] = BMSalarms6; + //SMA_005.data.u8[7] = BMSalarms7; + + //SMA_007.data.u8[0] = DCDCalarms0; + //SMA_007.data.u8[1] = DCDCalarms1; + //SMA_007.data.u8[2] = DCDCalarms2; + //SMA_007.data.u8[3] = DCDCalarms3; + //SMA_007.data.u8[4] = DCDCwarnings0; + //SMA_007.data.u8[5] = DCDCwarnings1; + //SMA_007.data.u8[6] = DCDCwarnings2; + //SMA_007.data.u8[7] = DCDCwarnings3; + + //SMA_015.data.u8[0] = BatterySystemVersion; + //SMA_015.data.u8[1] = BatterySystemVersion; + //SMA_015.data.u8[2] = BatterySystemVersion; + //SMA_015.data.u8[3] = BatterySystemVersion; + //SMA_015.data.u8[4] = BatteryCapacity; + //SMA_015.data.u8[5] = BatteryCapacity; + //SMA_015.data.u8[6] = NumberOfModules; + //SMA_015.data.u8[7] = BatteryManufacturerID; + + //SMA_016.data.u8[0] = SerialNumber; + //SMA_016.data.u8[1] = SerialNumber; + //SMA_016.data.u8[2] = SerialNumber; + //SMA_016.data.u8[3] = SerialNumber; + //SMA_016.data.u8[4] = ManufacturingDate; + //SMA_016.data.u8[5] = ManufacturingDate; + //SMA_016.data.u8[6] = ManufacturingDate; + //SMA_016.data.u8[7] = ManufacturingDate; + + //SMA_017.data.u8[0] = Multiplex; + //SMA_017.data.u8[1] = ManufacturerName; + //SMA_017.data.u8[2] = ManufacturerName; + //SMA_017.data.u8[3] = ManufacturerName; + //SMA_017.data.u8[4] = ManufacturerName; + //SMA_017.data.u8[5] = ManufacturerName; + //SMA_017.data.u8[6] = ManufacturerName; + //SMA_017.data.u8[7] = ManufacturerName; + + //SMA_018.data.u8[0] = Multiplex; + //SMA_018.data.u8[1] = BatteryName; + //SMA_018.data.u8[2] = BatteryName; + //SMA_018.data.u8[3] = BatteryName; + //SMA_018.data.u8[4] = BatteryName; + //SMA_018.data.u8[5] = BatteryName; + //SMA_018.data.u8[6] = BatteryName; + //SMA_018.data.u8[7] = BatteryName; +} + +void receive_can_sma_tripower(CAN_frame_t rx_frame) { + switch (rx_frame.MsgID) { + case 0x00D: //Inverter Measurements + break; + case 0x00F: //Inverter Feedback + break; + case 0x010: //Time from inverter + break; + case 0x015: //Initialization message from inverter + send_tripower_init(); + break; + case 0x017: //Initialization message from inverter 2 + //send_tripower_init(); + break; + default: + break; + } +} + +void send_can_sma_tripower() { + unsigned long currentMillis = millis(); + + // Send CAN Message every 500ms + if (currentMillis - previousMillis500ms >= interval500ms) { + previousMillis500ms = currentMillis; + + ESP32Can.CANWriteFrame(&SMA_00D); //Battery limits + ESP32Can.CANWriteFrame(&SMA_00F); // Battery state + ESP32Can.CANWriteFrame(&SMA_011); // Battery Energy + ESP32Can.CANWriteFrame(&SMA_013); // Battery Measurements + ESP32Can.CANWriteFrame(&SMA_014); // Battery Temperatures and cellvoltages + } + + if (batteryAlarm) { //Non-cyclic + ESP32Can.CANWriteFrame(&SMA_005); // Battery Alarms 1 + ESP32Can.CANWriteFrame(&SMA_007); // Battery Alarms 2 + } + + if (BMSevent) { //Non-cyclic + ESP32Can.CANWriteFrame(&SMA_006); // Battery Errorcode + ESP32Can.CANWriteFrame(&SMA_008); // Battery Events + } +} + +void send_tripower_init() { + ESP32Can.CANWriteFrame(&SMA_015); // Battery Data 1 + ESP32Can.CANWriteFrame(&SMA_016); // Battery Data 2 + ESP32Can.CANWriteFrame(&SMA_017); // Battery Manufacturer + ESP32Can.CANWriteFrame(&SMA_018); // Battery Name +} diff --git a/Software/src/inverter/SMA-TRIPOWER-CAN.h b/Software/src/inverter/SMA-TRIPOWER-CAN.h new file mode 100644 index 00000000..7b31d9b8 --- /dev/null +++ b/Software/src/inverter/SMA-TRIPOWER-CAN.h @@ -0,0 +1,32 @@ +#ifndef SMA_CAN_TRIPOWER_H +#define SMA_CAN_TRIPOWER_H +#include +#include "../../USER_SETTINGS.h" +#include "../devboard/config.h" // Needed for all defines +#include "../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h" + +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_char_dis_status; //Enum, 0-2 +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 min_voltage; +extern uint16_t max_voltage; +extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false +extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false + +void update_values_can_sma_tripower(); +void send_can_sma_tripower(); +void receive_can_sma_tripower(CAN_frame_t rx_frame); +void send_tripower_init(); + +#endif