Merge branch 'main' into bugfix/char-dis-status

This commit is contained in:
Daniel Öster 2024-02-17 23:19:13 +02:00 committed by GitHub
commit ecce5a61ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
32 changed files with 821 additions and 326 deletions

View file

@ -54,8 +54,8 @@ 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 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)
@ -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

View file

@ -25,6 +25,7 @@
//#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

View file

@ -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

View file

@ -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

View file

@ -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 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_i3_battery();
void receive_can_i3_battery(CAN_frame_t rx_frame);
void send_can_i3_battery();
void setup_battery(void);
#endif

View file

@ -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

View file

@ -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;
// 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_chademo_battery();
void receive_can_chademo_battery(CAN_frame_t rx_frame);
void send_can_chademo_battery();
void setup_battery(void);
#endif

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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<uint16_t>(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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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 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_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

View file

@ -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)

View file

@ -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,10 +253,22 @@ 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 (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

View file

@ -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

View file

@ -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,7 +18,7 @@ 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 */
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

View file

@ -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

View file

@ -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:

View file

@ -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) \

View file

@ -1,6 +1,7 @@
#include "webserver.h"
#include <Preferences.h>
#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);
}

View file

@ -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

View file

@ -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);

View file

@ -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);

View file

@ -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
}

View file

@ -0,0 +1,32 @@
#ifndef SMA_CAN_TRIPOWER_H
#define SMA_CAN_TRIPOWER_H
#include <Arduino.h>
#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