mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-04 18:29:48 +02:00
Merge remote-tracking branch 'upstream/main' into mqtt-cleanup
This commit is contained in:
commit
01f4ecb56b
11 changed files with 104 additions and 25 deletions
|
@ -103,6 +103,7 @@ void update_values_i3_battery() { //This function maps all the values fetched v
|
|||
set_event(EVENT_CAN_RX_FAILURE, 0);
|
||||
} else {
|
||||
CANstillAlive--;
|
||||
clear_event(EVENT_CAN_RX_FAILURE);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VIA_USB
|
||||
|
|
|
@ -108,6 +108,7 @@ void update_values_chademo_battery() { //This function maps all the values fetc
|
|||
set_event(EVENT_CAN_RX_FAILURE, 0);
|
||||
} else {
|
||||
CANstillAlive--;
|
||||
clear_event(EVENT_CAN_RX_FAILURE);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VIA_USB
|
||||
|
|
|
@ -109,6 +109,7 @@ void update_values_imiev_battery() { //This function maps all the values fetche
|
|||
set_event(EVENT_CAN_RX_FAILURE, 0);
|
||||
} else {
|
||||
CANstillAlive--;
|
||||
clear_event(EVENT_CAN_RX_FAILURE);
|
||||
}
|
||||
|
||||
if (!BMU_Detected) {
|
||||
|
|
|
@ -200,6 +200,7 @@ void update_values_kiaHyundai_64_battery() { //This function maps all the value
|
|||
set_event(EVENT_CAN_RX_FAILURE, 0);
|
||||
} else {
|
||||
CANstillAlive--;
|
||||
clear_event(EVENT_CAN_RX_FAILURE);
|
||||
}
|
||||
|
||||
if (waterleakageSensor == 0) {
|
||||
|
@ -221,6 +222,8 @@ void update_values_kiaHyundai_64_battery() { //This function maps all the value
|
|||
}
|
||||
if (cell_deviation_mV > MAX_CELL_DEVIATION) {
|
||||
set_event(EVENT_CELL_DEVIATION_HIGH, 0);
|
||||
} else {
|
||||
clear_event(EVENT_CELL_DEVIATION_HIGH);
|
||||
}
|
||||
|
||||
if (bms_status == FAULT) { //Incase we enter a critical fault state, zero out the allowed limits
|
||||
|
|
|
@ -104,7 +104,7 @@ static int16_t LB_SOC = 500; //0 - 100.0 % (0-1000) The real S
|
|||
static int16_t CalculatedSOC = 0; // Temporary value used for calculating SOC
|
||||
static uint16_t LB_TEMP = 0; //Temporary value used in status checks
|
||||
static uint16_t LB_Wh_Remaining = 0; //Amount of energy in battery, in Wh
|
||||
static uint16_t LB_GIDS = 0;
|
||||
static uint16_t LB_GIDS = 273; //Startup in 24kWh mode
|
||||
static uint16_t LB_MAX = 0;
|
||||
static uint16_t LB_Max_GIDS = 273; //Startup in 24kWh mode
|
||||
static uint16_t LB_StateOfHealth = 99; //State of health %
|
||||
|
@ -247,8 +247,9 @@ void update_values_leaf_battery() { /* This function maps all the values fetched
|
|||
}
|
||||
|
||||
/*Extra safety functions below*/
|
||||
if (LB_GIDS < 10) //800Wh left in battery
|
||||
{ //Battery is running abnormally low, some discharge logic might have failed. Zero it all out.
|
||||
if (LB_GIDS < 6) //500Wh left in battery
|
||||
{ //Battery is running abnormally low, some discharge logic might have failed. Zero it all out.
|
||||
set_event(EVENT_BATTERY_EMPTY, 0);
|
||||
SOC = 0;
|
||||
max_target_discharge_power = 0;
|
||||
}
|
||||
|
@ -264,11 +265,17 @@ void update_values_leaf_battery() { /* This function maps all the values fetched
|
|||
}
|
||||
|
||||
if (LB_Full_CHARGE_flag) { //Battery reports that it is fully charged stop all further charging incase it hasn't already
|
||||
set_event(EVENT_BATTERY_FULL, 0);
|
||||
max_target_charge_power = 0;
|
||||
} else {
|
||||
clear_event(EVENT_BATTERY_FULL);
|
||||
}
|
||||
|
||||
if (LB_Capacity_Empty) { //Battery reports that it is fully discharged. Stop all further discharging incase it hasn't already
|
||||
set_event(EVENT_BATTERY_EMPTY, 0);
|
||||
max_target_discharge_power = 0;
|
||||
} else {
|
||||
clear_event(EVENT_BATTERY_EMPTY);
|
||||
}
|
||||
|
||||
if (LB_Relay_Cut_Request) { //LB_FAIL, BMS requesting shutdown and contactors to be opened
|
||||
|
@ -320,14 +327,18 @@ void update_values_leaf_battery() { /* This function maps all the values fetched
|
|||
default:
|
||||
break;
|
||||
}
|
||||
} else { //LB_Failsafe_Status == 0
|
||||
clear_event(EVENT_BATTERY_DISCHG_STOP_REQ);
|
||||
clear_event(EVENT_BATTERY_CHG_STOP_REQ);
|
||||
clear_event(EVENT_BATTERY_CHG_DISCHG_STOP_REQ);
|
||||
}
|
||||
|
||||
if (LB_StateOfHealth < 25) { //Battery is extremely degraded, not fit for secondlifestorage. Zero it all out.
|
||||
if (LB_StateOfHealth != 0) { //Extra check to see that we actually have a SOH Value available
|
||||
errorCode = 5;
|
||||
set_event(EVENT_LOW_SOH, LB_StateOfHealth);
|
||||
max_target_discharge_power = 0;
|
||||
max_target_charge_power = 0;
|
||||
} else {
|
||||
clear_event(EVENT_LOW_SOH);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,9 +346,8 @@ void update_values_leaf_battery() { /* This function maps all the values fetched
|
|||
if (!LB_Interlock) {
|
||||
set_event(EVENT_HVIL_FAILURE, 0);
|
||||
errorCode = 6;
|
||||
SOC = 0;
|
||||
max_target_discharge_power = 0;
|
||||
max_target_charge_power = 0;
|
||||
} else {
|
||||
clear_event(EVENT_HVIL_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -347,6 +357,7 @@ void update_values_leaf_battery() { /* This function maps all the values fetched
|
|||
set_event(EVENT_CAN_RX_FAILURE, 0);
|
||||
} else {
|
||||
CANstillAlive--;
|
||||
clear_event(EVENT_CAN_RX_FAILURE);
|
||||
}
|
||||
if (CANerror >
|
||||
MAX_CAN_FAILURES) //Also check if we have recieved too many malformed CAN messages. If so, signal via LED
|
||||
|
@ -355,6 +366,11 @@ void update_values_leaf_battery() { /* This function maps all the values fetched
|
|||
set_event(EVENT_CAN_RX_WARNING, 0);
|
||||
}
|
||||
|
||||
if (bms_status == FAULT) { //Incase we enter a critical fault state, zero out the allowed limits
|
||||
max_target_charge_power = 0;
|
||||
max_target_discharge_power = 0;
|
||||
}
|
||||
|
||||
/*Finally print out values to serial if configured to do so*/
|
||||
#ifdef DEBUG_VIA_USB
|
||||
if (errorCode > 0) {
|
||||
|
|
|
@ -126,6 +126,7 @@ void update_values_kangoo_battery() { //This function maps all the values fetch
|
|||
set_event(EVENT_CAN_RX_FAILURE, 0);
|
||||
} else {
|
||||
CANstillAlive--;
|
||||
clear_event(EVENT_CAN_RX_FAILURE);
|
||||
}
|
||||
|
||||
if (LB_Cell_Max_Voltage >= ABSOLUTE_CELL_MAX_VOLTAGE) {
|
||||
|
@ -136,6 +137,8 @@ void update_values_kangoo_battery() { //This function maps all the values fetch
|
|||
}
|
||||
if (cell_deviation_mV > MAX_CELL_DEVIATION_MV) {
|
||||
set_event(EVENT_CELL_DEVIATION_HIGH, 0);
|
||||
} else {
|
||||
clear_event(EVENT_CELL_DEVIATION_HIGH);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VIA_USB
|
||||
|
|
|
@ -87,6 +87,7 @@ void update_values_zoe_battery() { //This function maps all the values fetched
|
|||
set_event(EVENT_CAN_RX_FAILURE, 0);
|
||||
} else {
|
||||
CANstillAlive--;
|
||||
clear_event(EVENT_CAN_RX_FAILURE);
|
||||
}
|
||||
|
||||
if (LB_Cell_Max_Voltage >= ABSOLUTE_CELL_MAX_VOLTAGE) {
|
||||
|
@ -97,6 +98,8 @@ void update_values_zoe_battery() { //This function maps all the values fetched
|
|||
}
|
||||
if (cell_deviation_mV > MAX_CELL_DEVIATION_MV) {
|
||||
set_event(EVENT_CELL_DEVIATION_HIGH, 0);
|
||||
} else {
|
||||
clear_event(EVENT_CELL_DEVIATION_HIGH);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VIA_USB
|
||||
|
|
|
@ -84,6 +84,7 @@ void update_values_santafe_phev_battery() { //This function maps all the values
|
|||
set_event(EVENT_CAN_RX_FAILURE, 0);
|
||||
} else {
|
||||
CANstillAlive--;
|
||||
clear_event(EVENT_CAN_RX_FAILURE);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_VIA_USB
|
||||
|
|
|
@ -231,10 +231,13 @@ void update_values_tesla_model_3_battery() { //This function maps all the value
|
|||
set_event(EVENT_CAN_RX_FAILURE, 0);
|
||||
} else {
|
||||
stillAliveCAN--;
|
||||
clear_event(EVENT_CAN_RX_FAILURE);
|
||||
}
|
||||
|
||||
if (hvil_status == 3) { //INTERNAL_OPEN_FAULT - Someone disconnected a high voltage cable while battery was in use
|
||||
set_event(EVENT_INTERNAL_OPEN_FAULT, 0);
|
||||
} else {
|
||||
clear_event(EVENT_INTERNAL_OPEN_FAULT);
|
||||
}
|
||||
|
||||
cell_deviation_mV = (cell_max_v - cell_min_v);
|
||||
|
@ -269,23 +272,27 @@ void update_values_tesla_model_3_battery() { //This function maps all the value
|
|||
|
||||
if (LFP_Chemistry) { //LFP limits used for voltage safeties
|
||||
if (cell_max_v >= MAX_CELL_VOLTAGE_LFP) {
|
||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
||||
set_event(EVENT_CELL_OVER_VOLTAGE, (cell_max_v - MAX_CELL_VOLTAGE_LFP));
|
||||
}
|
||||
if (cell_min_v <= MIN_CELL_VOLTAGE_LFP) {
|
||||
set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
|
||||
set_event(EVENT_CELL_UNDER_VOLTAGE, (MIN_CELL_VOLTAGE_LFP - cell_min_v));
|
||||
}
|
||||
if (cell_deviation_mV > MAX_CELL_DEVIATION_LFP) {
|
||||
set_event(EVENT_CELL_DEVIATION_HIGH, 0);
|
||||
set_event(EVENT_CELL_DEVIATION_HIGH, cell_deviation_mV);
|
||||
} else {
|
||||
clear_event(EVENT_CELL_DEVIATION_HIGH);
|
||||
}
|
||||
} else { //NCA/NCM limits used
|
||||
if (cell_max_v >= MAX_CELL_VOLTAGE_NCA_NCM) {
|
||||
set_event(EVENT_CELL_OVER_VOLTAGE, 0);
|
||||
set_event(EVENT_CELL_OVER_VOLTAGE, (cell_max_v - MAX_CELL_VOLTAGE_NCA_NCM));
|
||||
}
|
||||
if (cell_min_v <= MIN_CELL_VOLTAGE_NCA_NCM) {
|
||||
set_event(EVENT_CELL_UNDER_VOLTAGE, 0);
|
||||
set_event(EVENT_CELL_UNDER_VOLTAGE, (MIN_CELL_VOLTAGE_NCA_NCM - cell_min_v));
|
||||
}
|
||||
if (cell_deviation_mV > MAX_CELL_DEVIATION_NCA_NCM) {
|
||||
set_event(EVENT_CELL_DEVIATION_HIGH, 0);
|
||||
set_event(EVENT_CELL_DEVIATION_HIGH, cell_deviation_mV);
|
||||
} else {
|
||||
clear_event(EVENT_CELL_DEVIATION_HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
#include "../config.h"
|
||||
#include "timer.h"
|
||||
|
||||
#define EE_MAGIC_HEADER_VALUE 0xAA55
|
||||
#define EE_MAGIC_HEADER_VALUE 0xA5A5
|
||||
#define EE_NOF_EVENT_ENTRIES 30
|
||||
#define EE_EVENT_ENTRY_SIZE sizeof(EVENT_LOG_ENTRY_TYPE)
|
||||
#define EE_WRITE_PERIOD_MINUTES 10
|
||||
|
@ -52,6 +52,8 @@ typedef struct {
|
|||
EVENTS_LEVEL_TYPE level;
|
||||
uint16_t event_log_head_index;
|
||||
uint16_t event_log_tail_index;
|
||||
uint8_t nof_logged_events;
|
||||
uint16_t nof_eeprom_writes;
|
||||
} EVENT_TYPE;
|
||||
|
||||
/* Local variables */
|
||||
|
@ -82,12 +84,27 @@ void run_event_handling(void) {
|
|||
void init_events(void) {
|
||||
|
||||
EEPROM.begin(1024);
|
||||
events.nof_logged_events = 0;
|
||||
|
||||
uint16_t header = EEPROM.readUShort(EE_EVENT_LOG_START_ADDRESS);
|
||||
if (header != EE_MAGIC_HEADER_VALUE) {
|
||||
// The header doesn't appear to be a compatible event log, clear it and initialize
|
||||
EEPROM.writeUShort(EE_EVENT_LOG_START_ADDRESS, EE_MAGIC_HEADER_VALUE);
|
||||
EEPROM.writeUShort(EE_EVENT_LOG_HEAD_INDEX_ADDRESS, 0);
|
||||
EEPROM.writeUShort(EE_EVENT_LOG_TAIL_INDEX_ADDRESS, 0);
|
||||
|
||||
// Prepare an empty event block to write
|
||||
EVENT_LOG_ENTRY_TYPE entry = {.event = EVENT_NOF_EVENTS, .timestamp = 0, .data = 0};
|
||||
|
||||
// Put the event in (what I guess is) the RAM EEPROM mirror, or write buffer
|
||||
|
||||
for (int i = 0; i < EE_NOF_EVENT_ENTRIES; i++) {
|
||||
// Start at the oldest event, work through the log all the way the the head
|
||||
int address = EE_EVENT_ENTRY_START_ADDRESS + EE_EVENT_ENTRY_SIZE * i;
|
||||
EEPROM.put(address, entry);
|
||||
}
|
||||
|
||||
// Push changes to eeprom
|
||||
EEPROM.commit();
|
||||
Serial.println("EEPROM wasn't ready");
|
||||
} else {
|
||||
|
@ -102,7 +119,7 @@ void init_events(void) {
|
|||
events.entries[i].data = 0;
|
||||
events.entries[i].timestamp = 0;
|
||||
events.entries[i].occurences = 0;
|
||||
events.entries[i].log = false;
|
||||
events.entries[i].log = true;
|
||||
}
|
||||
|
||||
events.entries[EVENT_CAN_RX_FAILURE].level = EVENT_LEVEL_ERROR;
|
||||
|
@ -111,7 +128,9 @@ void init_events(void) {
|
|||
events.entries[EVENT_WATER_INGRESS].level = EVENT_LEVEL_ERROR;
|
||||
events.entries[EVENT_12V_LOW].level = EVENT_LEVEL_WARNING;
|
||||
events.entries[EVENT_SOC_PLAUSIBILITY_ERROR].level = EVENT_LEVEL_ERROR;
|
||||
events.entries[EVENT_KWH_PLAUSIBILITY_ERROR].level = EVENT_LEVEL_WARNING;
|
||||
events.entries[EVENT_KWH_PLAUSIBILITY_ERROR].level = EVENT_LEVEL_INFO;
|
||||
events.entries[EVENT_BATTERY_EMPTY].level = EVENT_LEVEL_INFO;
|
||||
events.entries[EVENT_BATTERY_FULL].level = EVENT_LEVEL_INFO;
|
||||
events.entries[EVENT_BATTERY_CHG_STOP_REQ].level = EVENT_LEVEL_ERROR;
|
||||
events.entries[EVENT_BATTERY_DISCHG_STOP_REQ].level = EVENT_LEVEL_ERROR;
|
||||
events.entries[EVENT_BATTERY_CHG_DISCHG_STOP_REQ].level = EVENT_LEVEL_ERROR;
|
||||
|
@ -131,14 +150,13 @@ void init_events(void) {
|
|||
events.entries[EVENT_SERIAL_RX_FAILURE].level = EVENT_LEVEL_ERROR;
|
||||
events.entries[EVENT_SERIAL_TX_FAILURE].level = EVENT_LEVEL_ERROR;
|
||||
events.entries[EVENT_SERIAL_TRANSMITTER_FAILURE].level = EVENT_LEVEL_ERROR;
|
||||
events.entries[EVENT_EEPROM_WRITE].level = EVENT_LEVEL_INFO;
|
||||
|
||||
events.entries[EVENT_DUMMY_INFO].log = true;
|
||||
events.entries[EVENT_DUMMY_DEBUG].log = true;
|
||||
events.entries[EVENT_DUMMY_WARNING].log = true;
|
||||
events.entries[EVENT_DUMMY_ERROR].log = true;
|
||||
events.entries[EVENT_EEPROM_WRITE].log = false; // Don't log the logger...
|
||||
|
||||
events.second_timer.set_interval(1000);
|
||||
events.ee_timer.set_interval(EE_WRITE_PERIOD_MINUTES * 60 * 1000); // Write to EEPROM every X minutes
|
||||
// Write to EEPROM every X minutes (if an event has been set)
|
||||
events.ee_timer.set_interval(EE_WRITE_PERIOD_MINUTES * 60 * 1000);
|
||||
}
|
||||
|
||||
void set_event(EVENTS_ENUM_TYPE event, uint8_t data) {
|
||||
|
@ -172,7 +190,11 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) {
|
|||
case EVENT_SOC_PLAUSIBILITY_ERROR:
|
||||
return "ERROR: SOC% reported by battery not plausible. Restart battery!";
|
||||
case EVENT_KWH_PLAUSIBILITY_ERROR:
|
||||
return "Warning: kWh remaining reported by battery not plausible. Battery needs cycling.";
|
||||
return "Info: kWh remaining reported by battery not plausible. Battery needs cycling.";
|
||||
case EVENT_BATTERY_EMPTY:
|
||||
return "Info: Battery is completely discharged";
|
||||
case EVENT_BATTERY_FULL:
|
||||
return "Info: Battery is fully charged";
|
||||
case EVENT_BATTERY_CHG_STOP_REQ:
|
||||
return "ERROR: Battery raised caution indicator AND requested charge stop. Inspect battery status!";
|
||||
case EVENT_BATTERY_DISCHG_STOP_REQ:
|
||||
|
@ -213,6 +235,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_EEPROM_WRITE:
|
||||
return "Info: The EEPROM was written";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
@ -328,6 +352,9 @@ static void log_event(EVENTS_ENUM_TYPE event, uint8_t data) {
|
|||
EEPROM.writeUShort(EE_EVENT_LOG_TAIL_INDEX_ADDRESS, events.event_log_tail_index);
|
||||
//Serial.println("Wrote event " + String(event) + " to " + String(entry_address));
|
||||
//Serial.println("head: " + String(events.event_log_head_index) + ", tail: " + String(events.event_log_tail_index));
|
||||
|
||||
// We don't need the exact number, it's just for deciding to store or not
|
||||
events.nof_logged_events += (events.nof_logged_events < 255) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void print_event_log(void) {
|
||||
|
@ -344,6 +371,10 @@ static void print_event_log(void) {
|
|||
int address = EE_EVENT_ENTRY_START_ADDRESS + EE_EVENT_ENTRY_SIZE * index;
|
||||
|
||||
EEPROM.get(address, entry);
|
||||
if (entry.event == EVENT_NOF_EVENTS) {
|
||||
// The entry is a blank that has been left behind somehow
|
||||
continue;
|
||||
}
|
||||
Serial.println("Event: " + String(get_event_enum_string(entry.event)) + ", data: " + String(entry.data) +
|
||||
", time: " + String(entry.timestamp));
|
||||
|
||||
|
@ -354,8 +385,17 @@ static void print_event_log(void) {
|
|||
}
|
||||
|
||||
static void check_ee_write(void) {
|
||||
// Only actually write to flash emulated EEPROM every EE_WRITE_PERIOD_MINUTES minutes
|
||||
if (events.ee_timer.elapsed()) {
|
||||
// Only actually write to flash emulated EEPROM every EE_WRITE_PERIOD_MINUTES minutes,
|
||||
// and only if we've logged any events
|
||||
if (events.ee_timer.elapsed() && (events.nof_logged_events > 0)) {
|
||||
EEPROM.commit();
|
||||
events.nof_eeprom_writes += (events.nof_eeprom_writes < 65535) ? 1 : 0;
|
||||
events.nof_logged_events = 0;
|
||||
|
||||
// We want to know how many writes we have, and to increment the occurrence counter
|
||||
// we need to clear it first. It's just the way life is. Using events is a smooth
|
||||
// way to visualize it in the web UI
|
||||
clear_event(EVENT_EEPROM_WRITE);
|
||||
set_event(EVENT_EEPROM_WRITE, events.nof_eeprom_writes);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@
|
|||
XX(EVENT_12V_LOW) \
|
||||
XX(EVENT_SOC_PLAUSIBILITY_ERROR) \
|
||||
XX(EVENT_KWH_PLAUSIBILITY_ERROR) \
|
||||
XX(EVENT_BATTERY_EMPTY) \
|
||||
XX(EVENT_BATTERY_FULL) \
|
||||
XX(EVENT_BATTERY_CHG_STOP_REQ) \
|
||||
XX(EVENT_BATTERY_DISCHG_STOP_REQ) \
|
||||
XX(EVENT_BATTERY_CHG_DISCHG_STOP_REQ) \
|
||||
|
@ -47,6 +49,7 @@
|
|||
XX(EVENT_SERIAL_RX_FAILURE) \
|
||||
XX(EVENT_SERIAL_TX_FAILURE) \
|
||||
XX(EVENT_SERIAL_TRANSMITTER_FAILURE) \
|
||||
XX(EVENT_EEPROM_WRITE) \
|
||||
XX(EVENT_NOF_EVENTS)
|
||||
|
||||
typedef enum { EVENTS_ENUM_TYPE(GENERATE_ENUM) } EVENTS_ENUM_TYPE;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue