Lots of modifications... Hopefully the end

This commit is contained in:
Cabooman 2024-02-11 22:22:36 +01:00
parent e2faaecfd4
commit 6cb7e55dad
36 changed files with 345 additions and 210 deletions

View file

@ -187,7 +187,7 @@ void loop() {
previousMillisUpdateVal = millis();
update_values(); // Update values heading towards inverter. Prepare for sending on CAN, or write directly to Modbus.
if (DUMMY_EVENT_ENABLED) {
set_event(EVENT_DUMMY, (uint8_t)millis());
set_event(EVENT_DUMMY_ERROR, (uint8_t)millis());
}
}
@ -557,26 +557,31 @@ void handle_LED_state() {
} else if (!rampUp && brightness == 0) {
rampUp = true;
}
switch (LEDcolor) {
case GREEN:
pixels.setPixelColor(0, pixels.Color(0, brightness, 0)); // Green pulsing LED
switch (get_event_level()) {
case EVENT_LEVEL_INFO:
LEDcolor = GREEN;
pixels.setPixelColor(0, pixels.Color(0, brightness, 0)); // Red LED full brightness
break;
case YELLOW:
case EVENT_LEVEL_WARNING:
LEDcolor = YELLOW;
pixels.setPixelColor(0, pixels.Color(brightness, brightness, 0)); // Yellow pulsing LED
break;
case BLUE:
case EVENT_LEVEL_DEBUG:
LEDcolor = BLUE;
pixels.setPixelColor(0, pixels.Color(0, 0, brightness)); // Blue pulsing LED
break;
case RED:
case EVENT_LEVEL_ERROR:
LEDcolor = RED;
pixels.setPixelColor(0, pixels.Color(150, 0, 0)); // Red LED full brightness
break;
case TEST_ALL_COLORS:
pixels.setPixelColor(0, pixels.Color(brightness, abs((100 - brightness)), abs((50 - brightness)))); // RGB
break;
default:
break;
}
if (LEDcolor == TEST_ALL_COLORS) {
pixels.setPixelColor(0, pixels.Color(0, brightness, 0)); // Green pulsing LED
}
pixels.show(); // This sends the updated pixel color to the hardware.
}

View file

@ -27,9 +27,9 @@ volatile float CHARGER_END_A = 1.0; // Current at which charging is consid
#ifdef WEBSERVER
volatile uint8_t AccessPointEnabled =
true; //Set to either true or false incase you want the board to enable a direct wifi access point
const char* ssid = "REPLACE_WITH_YOUR_SSID"; // Maximum of 63 characters;
const char* password = "REPLACE_WITH_YOUR_PASSWORD"; // Minimum of 8 characters;
const char* ssidAP = "Battery Emulator"; // Maximum of 63 characters;
const char* ssid = "comhem_F0A1A5"; // Maximum of 63 characters;
const char* password = "3027CCA803"; // Minimum of 8 characters;
const char* ssidAP = "Battery Emulator"; // Maximum of 63 characters;
const char* passwordAP = "123456789"; // Minimum of 8 characters; set to NULL if you want the access point to be open
const uint8_t wifi_channel = 0; // set to 0 for automatic channel selection

View file

@ -12,16 +12,16 @@
//#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
//#define TESLA_MODEL_3_BATTERY
//#define TEST_FAKE_BATTERY
#define TEST_FAKE_BATTERY
/* 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
@ -37,10 +37,10 @@
//#define SERIAL_LINK_RECEIVER //Enable this line to receive battery data over RS485 pins from another Lilygo (This LilyGo interfaces with inverter)
//#define SERIAL_LINK_TRANSMITTER //Enable this line to send battery data over RS485 pins to another Lilygo (This LilyGo interfaces with battery)
#define WEBSERVER //Enable this line to enable WiFi, and to run the webserver. See USER_SETTINGS.cpp for the Wifi settings.
#define LOAD_SAVED_SETTINGS_ON_BOOT //Enable this line to read settings stored via the webserver on boot
// #define LOAD_SAVED_SETTINGS_ON_BOOT //Enable this line to read settings stored via the webserver on boot
/* MQTT options */
#define MQTT // Enable this line to enable MQTT
// #define MQTT // Enable this line to enable MQTT
#define MQTT_SUBSCRIPTIONS \
{ "my/topic/abc", "my/other/topic" }
#define MQTT_SERVER "192.168.xxx.yyy"

View file

@ -55,8 +55,6 @@ 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
bms_status = ACTIVE; //Startout in active mode
//Calculate the SOC% value to send to inverter
Calculated_SOC = (Display_SOC * 10); //Increase decimal amount
Calculated_SOC =

View file

@ -18,7 +18,6 @@ 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 uint8_t bms_char_dis_status;
extern uint16_t stat_batt_power;
extern uint16_t temperature_min;

View file

@ -90,7 +90,6 @@ 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
bms_status = ACTIVE; //Startout in active mode
SOC = ChargingRate;

View file

@ -41,8 +41,6 @@ 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
bms_status = ACTIVE; //Startout in active mode
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

View file

@ -18,7 +18,6 @@ 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 uint8_t bms_char_dis_status;
extern uint16_t stat_batt_power;
extern uint16_t temperature_min;

View file

@ -195,8 +195,6 @@ void update_values_kiaHyundai_64_battery() { //This function maps all the value
cell_min_voltage = CellVoltMin_mV;
bms_status = ACTIVE; //Startout in active mode. Then check safeties
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) {
set_event(EVENT_CAN_FAILURE, 0);

View file

@ -246,8 +246,6 @@ void update_values_leaf_battery() { /* This function maps all the values fetched
cellvoltages[i] = cell_voltages[i];
}
bms_status = ACTIVE; //Startout in active mode
/*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.

View file

@ -58,8 +58,6 @@ static const int interval100 = 100; // interval (ms) at which send CAN Messag
static const int interval1000 = 1000; // interval (ms) at which send CAN Messages
void update_values_kangoo_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
bms_status = ACTIVE; //Startout in active mode
StateOfHealth = (LB_SOH * 100); //Increase range from 99% -> 99.00%
//Calculate the SOC% value to send to Fronius

View file

@ -43,8 +43,6 @@ static const int interval100 = 100; // interval (ms) at which send CAN Messag
static const int interval1000 = 1000; // interval (ms) at which send CAN Messages
void update_values_zoe_battery() { //This function maps all the values fetched via CAN to the correct parameters used for modbus
bms_status = ACTIVE; //Startout in active mode
StateOfHealth = (LB_SOH * 100); //Increase range from 99% -> 99.00%
//Calculate the SOC% value to send to Fronius

View file

@ -79,8 +79,6 @@ void update_values_santafe_phev_battery() { //This function maps all the values
temperature_max;
bms_status = ACTIVE; //Startout in active mode, then check safeties
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!CANstillAlive) {
set_event(EVENT_CAN_FAILURE, 0);

View file

@ -18,7 +18,6 @@ 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 uint8_t bms_char_dis_status;
extern uint16_t stat_batt_power;
extern uint16_t temperature_min;

View file

@ -1,6 +1,8 @@
// SERIAL-LINK-RECEIVER-FROM-BATTERY.cpp
#include "SERIAL-LINK-RECEIVER-FROM-BATTERY.h"
#include <Arduino.h>
#include "../devboard/utils/events.h"
#define INVERTER_SEND_NUM_VARIABLES 1
#define INVERTER_RECV_NUM_VARIABLES 16
@ -35,7 +37,6 @@ void __getData() {
max_target_discharge_power = (uint16_t)dataLinkReceive.getReceivedData(6);
max_target_charge_power = (uint16_t)dataLinkReceive.getReceivedData(7);
uint16_t _bms_status = (uint16_t)dataLinkReceive.getReceivedData(8);
bms_status = _bms_status;
bms_char_dis_status = (uint16_t)dataLinkReceive.getReceivedData(9);
stat_batt_power = (uint16_t)dataLinkReceive.getReceivedData(10);
temperature_min = (uint16_t)dataLinkReceive.getReceivedData(11);
@ -46,8 +47,10 @@ void __getData() {
batteryAllowsContactorClosing = (uint16_t)dataLinkReceive.getReceivedData(16);
batteryFault = false;
if (_bms_status == FAULT)
if (_bms_status == FAULT) {
batteryFault = true;
set_event(EVENT_SERIAL_TRANSMITTER_FAILURE, 0);
}
}
void updateData() {
@ -116,12 +119,12 @@ void manageSerialLinkReceiver() {
if (minutesLost < 4) {
max_target_charge_power = (lastGoodMaxCharge * (4 - minutesLost)) / 4;
max_target_discharge_power = (lastGoodMaxDischarge * (4 - minutesLost)) / 4;
set_event(EVENT_SERIAL_RX_WARNING, minutesLost);
} else {
// Times Up -
max_target_charge_power = 0;
max_target_discharge_power = 0;
bms_status = 4; //Fault state
LEDcolor = RED;
set_event(EVENT_SERIAL_RX_FAILURE, uint8_t(min(minutesLost, 255uL)));
//----- Throw Error
}
// report Lost data & Max charge / Discharge reductions

View file

@ -30,7 +30,6 @@ 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 LEDcolor; //Enum, 0-10
extern bool LFP_Chemistry;
extern uint16_t CANerror;

View file

@ -226,8 +226,6 @@ void update_values_tesla_model_3_battery() { //This function maps all the value
/* Value mapping is completed. Start to check all safeties */
bms_status = ACTIVE; //Startout in active mode before checking if we have any faults
/* Check if the BMS is still sending CAN messages. If we go 60s without messages we raise an error*/
if (!stillAliveCAN) {
set_event(EVENT_CAN_FAILURE, 0);
@ -264,7 +262,6 @@ void update_values_tesla_model_3_battery() { //This function maps all the value
Serial.println("Warning: kWh remaining " + String(nominal_full_pack_energy) +
" reported by battery not plausible. Battery needs cycling.");
set_event(EVENT_KWH_PLAUSIBILITY_ERROR, nominal_full_pack_energy);
LEDcolor = YELLOW;
} else if (nominal_full_pack_energy <= 1) {
Serial.println("Info: kWh remaining battery is not reporting kWh remaining.");
set_event(EVENT_KWH_PLAUSIBILITY_ERROR, nominal_full_pack_energy);

View file

@ -17,11 +17,7 @@ void print_units(char* header, int value, char* units) {
}
void update_values_test_battery() { /* This function puts fake values onto the parameters sent towards the inverter */
bms_status = ACTIVE; //Always be in Active mode
LEDcolor = TEST_ALL_COLORS; // Cycle the LED thru all available colors
SOC = 5000; // 50.00%
SOC = 5000; // 50.00%
StateOfHealth = 9900; // 99.00%

View file

@ -28,7 +28,6 @@ extern uint16_t cell_min_voltage; //mV, 0-4350
extern uint16_t cellvoltages[120]; //mV 0-5000 per cell
extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false
extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false
extern uint8_t LEDcolor; //Enum, 0-10
void update_values_test_battery();
void receive_can_test_battery(CAN_frame_t rx_frame);

View file

@ -8,9 +8,7 @@ typedef struct {
EVENTS_STRUCT_TYPE entries[EVENT_NOF_EVENTS];
uint32_t time_seconds;
MyTimer second_timer;
uint8_t nof_warning_events;
uint8_t nof_debug_events;
uint8_t nof_error_events;
EVENTS_LEVEL_TYPE level;
} EVENT_TYPE;
/* Local variables */
@ -20,10 +18,8 @@ static const char* EVENTS_LEVEL_TYPE_STRING[] = {EVENTS_LEVEL_TYPE(GENERATE_STRI
/* Local function prototypes */
static void update_event_time(void);
static void set_message(EVENTS_ENUM_TYPE event);
static void update_led_color(void);
static void set_event(EVENTS_ENUM_TYPE event, uint8_t data, bool latched);
static void update_event_numbers(void);
static void update_event_level(void);
static void update_bms_status(void);
/* Exported functions */
@ -31,6 +27,7 @@ static void update_bms_status(void);
/* Main execution function, should handle various continuous functionality */
void run_event_handling(void) {
update_event_time();
run_sequence_on_target();
}
/* Initialization function */
@ -40,34 +37,31 @@ void init_events(void) {
events.entries[EVENT_CAN_FAILURE].data = 0;
events.entries[EVENT_CAN_FAILURE].timestamp = 0;
events.entries[EVENT_CAN_FAILURE].occurences = 0;
events.entries[EVENT_CAN_FAILURE].state = EVENT_STATE_INACTIVE;
}
events.entries[EVENT_CAN_FAILURE].led_color = RED;
events.entries[EVENT_CAN_WARNING].led_color = YELLOW;
events.entries[EVENT_WATER_INGRESS].led_color = RED;
events.entries[EVENT_12V_LOW].led_color = YELLOW;
events.entries[EVENT_SOC_PLAUSIBILITY_ERROR].led_color = RED;
events.entries[EVENT_KWH_PLAUSIBILITY_ERROR].led_color = YELLOW;
events.entries[EVENT_BATTERY_CHG_STOP_REQ].led_color = RED;
events.entries[EVENT_BATTERY_DISCHG_STOP_REQ].led_color = RED;
events.entries[EVENT_BATTERY_CHG_DISCHG_STOP_REQ].led_color = RED;
events.entries[EVENT_LOW_SOH].led_color = RED;
events.entries[EVENT_HVIL_FAILURE].led_color = RED;
events.entries[EVENT_INTERNAL_OPEN_FAULT].led_color = RED;
events.entries[EVENT_CELL_UNDER_VOLTAGE].led_color = RED;
events.entries[EVENT_CELL_OVER_VOLTAGE].led_color = RED;
events.entries[EVENT_CELL_DEVIATION_HIGH].led_color = YELLOW;
events.entries[EVENT_UNKNOWN_EVENT_SET].led_color = RED;
events.entries[EVENT_OTA_UPDATE].led_color = BLUE;
events.entries[EVENT_DUMMY].led_color = RED;
events.entries[EVENT_NOF_EVENTS].led_color = RED;
events.entries[EVENT_CAN_FAILURE].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_CAN_WARNING].level = EVENT_LEVEL_WARNING;
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_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;
events.entries[EVENT_LOW_SOH].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_HVIL_FAILURE].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_INTERNAL_OPEN_FAULT].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_CELL_UNDER_VOLTAGE].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_CELL_OVER_VOLTAGE].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_CELL_DEVIATION_HIGH].level = EVENT_LEVEL_WARNING;
events.entries[EVENT_UNKNOWN_EVENT_SET].level = EVENT_LEVEL_ERROR;
events.entries[EVENT_OTA_UPDATE].level = EVENT_LEVEL_DEBUG;
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;
events.entries[EVENT_DUMMY_ERROR].level = EVENT_LEVEL_ERROR;
events.second_timer.interval = 1000;
events.nof_debug_events = 0;
events.nof_error_events = 0;
events.nof_warning_events = 0;
events.second_timer.set_interval(1000);
}
void set_event(EVENTS_ENUM_TYPE event, uint8_t data) {
@ -81,96 +75,11 @@ void set_event_latched(EVENTS_ENUM_TYPE event, uint8_t data) {
void clear_event(EVENTS_ENUM_TYPE event) {
if (events.entries[event].state == EVENT_STATE_ACTIVE) {
events.entries[event].state = EVENT_STATE_INACTIVE;
update_event_numbers();
update_led_color();
update_event_level();
update_bms_status();
}
}
/* Local functions */
static void set_event(EVENTS_ENUM_TYPE event, uint8_t data, bool latched) {
// Just some defensive stuff if someone sets an unknown event
if (event >= EVENT_NOF_EVENTS) {
event = EVENT_UNKNOWN_EVENT_SET;
}
// If the event is already set, no reason to continue
if ((events.entries[event].state != EVENT_STATE_ACTIVE) &&
(events.entries[event].state != EVENT_STATE_ACTIVE_LATCHED)) {
events.entries[event].occurences++;
}
// We should set the event, update event info
events.entries[event].timestamp = events.time_seconds;
events.entries[event].data = data;
// Check if the event is latching
events.entries[event].state = latched ? EVENT_STATE_ACTIVE_LATCHED : EVENT_STATE_ACTIVE;
update_event_numbers();
update_led_color();
update_bms_status();
#ifdef DEBUG_VIA_USB
Serial.println(get_event_message_string(event));
#endif
}
static void update_bms_status(void) {
if (events.nof_error_events > 0) {
bms_status = FAULT;
} else if (events.nof_debug_events > 0) {
bms_status = UPDATING;
} else if (events.nof_warning_events > 0) {
// No bms_status update
}
}
static void update_event_numbers(void) {
events.nof_error_events = 0;
events.nof_debug_events = 0;
events.nof_warning_events = 0;
for (uint8_t i = 0u; i < EVENT_NOF_EVENTS; i++) {
if ((events.entries[i].state == EVENT_STATE_ACTIVE) || (events.entries[i].state == EVENT_STATE_ACTIVE_LATCHED)) {
switch (events.entries[i].led_color) {
case GREEN:
// Just informative
break;
case YELLOW:
events.nof_warning_events++;
break;
case BLUE:
events.nof_debug_events++;
break;
case RED:
events.nof_error_events++;
break;
default:
break;
}
}
}
}
static void update_event_time(void) {
unsigned long new_millis = millis();
if (events.second_timer.elapsed() == true) {
events.time_seconds++;
}
}
static void update_led_color(void) {
if (events.nof_error_events > 0) {
LEDcolor = RED;
} else if (events.nof_debug_events > 0) {
LEDcolor = BLUE;
} else if (events.nof_warning_events > 0) {
LEDcolor = YELLOW;
} else {
LEDcolor = GREEN;
}
}
const char* get_event_message_string(EVENTS_ENUM_TYPE event) {
switch (event) {
case EVENT_CAN_FAILURE:
@ -207,8 +116,22 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event) {
return "ERROR: HIGH CELL DEVIATION!!! Inspect battery!";
case EVENT_UNKNOWN_EVENT_SET:
return "An unknown event was set! Review your code!";
case EVENT_DUMMY:
return "The dummy event was set!"; // Don't change this event message!
case EVENT_DUMMY_INFO:
return "The dummy info event was set!"; // Don't change this event message!
case EVENT_DUMMY_DEBUG:
return "The dummy debug event was set!"; // Don't change this event message!
case EVENT_DUMMY_WARNING:
return "The dummy warning event was set!"; // Don't change this event message!
case EVENT_DUMMY_ERROR:
return "The dummy error event was set!"; // Don't change this event message!
case EVENT_SERIAL_RX_WARNING:
return "Error in serial function: No data received for some time, see data for minutes";
case EVENT_SERIAL_RX_FAILURE:
return "Error in serial function: No data for a long time!";
case EVENT_SERIAL_TX_FAILURE:
return "Error in serial function: No ACK from receiver!";
case EVENT_SERIAL_TRANSMITTER_FAILURE:
return "Error in serial function: Some ERROR level fault in transmitter, received by receiver";
default:
return "";
}
@ -221,9 +144,73 @@ const char* get_event_enum_string(EVENTS_ENUM_TYPE event) {
const char* get_event_level_string(EVENTS_ENUM_TYPE event) {
// Return the event level but skip "EVENT_LEVEL_" that should always be first
return EVENTS_LEVEL_TYPE_STRING[event] + 12;
return EVENTS_LEVEL_TYPE_STRING[events.entries[event].level] + 12;
}
const EVENTS_STRUCT_TYPE* get_event_pointer(EVENTS_ENUM_TYPE event) {
return &events.entries[event];
}
EVENTS_LEVEL_TYPE get_event_level(void) {
return events.level;
}
/* Local functions */
static void set_event(EVENTS_ENUM_TYPE event, uint8_t data, bool latched) {
// Just some defensive stuff if someone sets an unknown event
if (event >= EVENT_NOF_EVENTS) {
event = EVENT_UNKNOWN_EVENT_SET;
}
// If the event is already set, no reason to continue
if ((events.entries[event].state != EVENT_STATE_ACTIVE) &&
(events.entries[event].state != EVENT_STATE_ACTIVE_LATCHED)) {
events.entries[event].occurences++;
}
// We should set the event, update event info
events.entries[event].timestamp = events.time_seconds;
events.entries[event].data = data;
// Check if the event is latching
events.entries[event].state = latched ? EVENT_STATE_ACTIVE_LATCHED : EVENT_STATE_ACTIVE;
update_event_level();
update_bms_status();
#ifdef DEBUG_VIA_USB
Serial.println(get_event_message_string(event));
#endif
}
static void update_bms_status(void) {
switch (events.level) {
case EVENT_LEVEL_INFO:
case EVENT_LEVEL_WARNING:
bms_status = ACTIVE;
break;
case EVENT_LEVEL_DEBUG:
bms_status = UPDATING;
break;
case EVENT_LEVEL_ERROR:
bms_status = FAULT;
break;
default:
break;
}
}
static void update_event_level(void) {
events.level = EVENT_LEVEL_INFO;
for (uint8_t i = 0u; i < EVENT_NOF_EVENTS; i++) {
if ((events.entries[i].state == EVENT_STATE_ACTIVE) || (events.entries[i].state == EVENT_STATE_ACTIVE_LATCHED)) {
events.level = max(events.entries[i].level, events.level);
}
}
}
static void update_event_time(void) {
if (events.second_timer.elapsed() == true) {
events.time_seconds++;
}
}

View file

@ -6,10 +6,17 @@
#include <Arduino.h>
#endif
// #define INCLUDE_EVENTS_TEST // Enable to run an event test loop, see events_test_on_target.cpp
#define GENERATE_ENUM(ENUM) ENUM,
#define GENERATE_STRING(STRING) #STRING,
/* Event enumeration */
/** EVENT ENUMERATION
*
* Do not change the order!
* When adding events, add them RIGHT BEFORE the EVENT_NOF_EVENTS enum.
* In addition, the event name must start with "EVENT_"
*/
#define EVENTS_ENUM_TYPE(XX) \
XX(EVENT_CAN_FAILURE) \
XX(EVENT_CAN_WARNING) \
@ -28,22 +35,29 @@
XX(EVENT_CELL_DEVIATION_HIGH) \
XX(EVENT_UNKNOWN_EVENT_SET) \
XX(EVENT_OTA_UPDATE) \
XX(EVENT_DUMMY) \
XX(EVENT_DUMMY_INFO) \
XX(EVENT_DUMMY_DEBUG) \
XX(EVENT_DUMMY_WARNING) \
XX(EVENT_DUMMY_ERROR) \
XX(EVENT_SERIAL_RX_WARNING) \
XX(EVENT_SERIAL_RX_FAILURE) \
XX(EVENT_SERIAL_TX_FAILURE) \
XX(EVENT_SERIAL_TRANSMITTER_FAILURE) \
XX(EVENT_NOF_EVENTS)
typedef enum { EVENTS_ENUM_TYPE(GENERATE_ENUM) } EVENTS_ENUM_TYPE;
/* Event type enumeration */
/* Event type enumeration, keep in order of priority! */
#define EVENTS_LEVEL_TYPE(XX) \
XX(EVENT_LEVEL_ERROR) \
XX(EVENT_LEVEL_WARNING) \
XX(EVENT_LEVEL_INFO) \
XX(EVENT_LEVEL_DEBUG)
XX(EVENT_LEVEL_DEBUG) \
XX(EVENT_LEVEL_WARNING) \
XX(EVENT_LEVEL_ERROR)
typedef enum { EVENTS_LEVEL_TYPE(GENERATE_ENUM) } EVENTS_LEVEL_TYPE;
typedef enum {
EVENT_STATE_INIT = 0,
EVENT_STATE_PENDING = 0,
EVENT_STATE_INACTIVE,
EVENT_STATE_ACTIVE,
EVENT_STATE_ACTIVE_LATCHED
@ -63,6 +77,8 @@ const char* get_event_message_string(EVENTS_ENUM_TYPE event);
const char* get_event_level_string(EVENTS_ENUM_TYPE event);
const char* get_event_type(EVENTS_ENUM_TYPE event);
EVENTS_LEVEL_TYPE get_event_level(void);
void init_events(void);
void set_event_latched(EVENTS_ENUM_TYPE event, uint8_t data);
void set_event(EVENTS_ENUM_TYPE event, uint8_t data);
@ -72,7 +88,8 @@ const EVENTS_STRUCT_TYPE* get_event_pointer(EVENTS_ENUM_TYPE event);
void run_event_handling(void);
void run_sequence_on_target(void);
extern uint8_t bms_status; //Enum, 0-5
extern uint8_t LEDcolor;
#endif // __MYTIMER_H__

View file

@ -0,0 +1,142 @@
#include "events.h"
#include "timer.h"
typedef enum {
ETOT_INIT,
ETOT_FIRST_WAIT,
ETOT_INFO,
ETOT_INFO_CLEAR,
ETOT_DEBUG,
ETOT_DEBUG_CLEAR,
ETOT_WARNING,
ETOT_WARNING_CLEAR,
ETOT_ERROR,
ETOT_ERROR_CLEAR,
ETOT_ERROR_LATCHED,
ETOT_DONE
} ETOT_TYPE;
MyTimer timer(5000);
ETOT_TYPE events_test_state = ETOT_INIT;
void run_sequence_on_target(void) {
#ifdef INCLUDE_EVENTS_TEST
switch (events_test_state) {
case ETOT_INIT:
timer.set_interval(10000);
events_test_state = ETOT_FIRST_WAIT;
Serial.println("Events test: initialized");
Serial.print("bms_status: ");
Serial.println(bms_status);
break;
case ETOT_FIRST_WAIT:
if (timer.elapsed()) {
timer.set_interval(8000);
events_test_state = ETOT_INFO;
set_event(EVENT_DUMMY_INFO, 123);
set_event(EVENT_DUMMY_INFO, 234); // 234 should show, occurrence 1
Serial.println("Events test: info event set, data: 234");
Serial.print("bms_status: ");
Serial.println(bms_status);
}
break;
case ETOT_INFO:
if (timer.elapsed()) {
timer.set_interval(8000);
clear_event(EVENT_DUMMY_INFO);
events_test_state = ETOT_INFO_CLEAR;
Serial.println("Events test : info event cleared");
Serial.print("bms_status: ");
Serial.println(bms_status);
}
break;
case ETOT_INFO_CLEAR:
if (timer.elapsed()) {
timer.set_interval(8000);
events_test_state = ETOT_DEBUG;
set_event(EVENT_DUMMY_DEBUG, 111);
set_event(EVENT_DUMMY_DEBUG, 222); // 222 should show, occurrence 1
Serial.println("Events test : debug event set, data: 222");
Serial.print("bms_status: ");
Serial.println(bms_status);
}
break;
case ETOT_DEBUG:
if (timer.elapsed()) {
timer.set_interval(8000);
clear_event(EVENT_DUMMY_DEBUG);
events_test_state = ETOT_DEBUG_CLEAR;
Serial.println("Events test : info event cleared");
Serial.print("bms_status: ");
Serial.println(bms_status);
}
break;
case ETOT_DEBUG_CLEAR:
if (timer.elapsed()) {
timer.set_interval(8000);
events_test_state = ETOT_WARNING;
set_event(EVENT_DUMMY_WARNING, 234);
set_event(EVENT_DUMMY_WARNING, 121); // 121 should show, occurrence 1
Serial.println("Events test : warning event set, data: 121");
Serial.print("bms_status: ");
Serial.println(bms_status);
}
break;
case ETOT_WARNING:
if (timer.elapsed()) {
timer.set_interval(8000);
clear_event(EVENT_DUMMY_WARNING);
events_test_state = ETOT_WARNING_CLEAR;
Serial.println("Events test : warning event cleared");
Serial.print("bms_status: ");
Serial.println(bms_status);
}
break;
case ETOT_WARNING_CLEAR:
if (timer.elapsed()) {
timer.set_interval(8000);
events_test_state = ETOT_ERROR;
set_event(EVENT_DUMMY_ERROR, 221);
set_event(EVENT_DUMMY_ERROR, 133); // 133 should show, occurrence 1
Serial.println("Events test : error event set, data: 133");
Serial.print("bms_status: ");
Serial.println(bms_status);
}
break;
case ETOT_ERROR:
if (timer.elapsed()) {
timer.set_interval(8000);
clear_event(EVENT_DUMMY_ERROR);
events_test_state = ETOT_ERROR_CLEAR;
Serial.println("Events test : error event cleared");
Serial.print("bms_status: ");
Serial.println(bms_status);
}
break;
case ETOT_ERROR_CLEAR:
if (timer.elapsed()) {
timer.set_interval(8000);
events_test_state = ETOT_ERROR_LATCHED;
set_event_latched(EVENT_DUMMY_ERROR, 221);
set_event_latched(EVENT_DUMMY_ERROR, 133); // 133 should show, occurrence 1
Serial.println("Events test : latched error event set, data: 133");
Serial.print("bms_status: ");
Serial.println(bms_status);
}
break;
case ETOT_ERROR_LATCHED:
if (timer.elapsed()) {
timer.set_interval(8000);
clear_event(EVENT_DUMMY_ERROR);
events_test_state = ETOT_DONE;
Serial.println("Events test : latched error event cleared?");
Serial.print("bms_status: ");
Serial.println(bms_status);
}
break;
case ETOT_DONE:
default:
break;
}
#endif
}

View file

@ -4,7 +4,7 @@ MyTimer::MyTimer(unsigned long interval) : interval(interval) {
previous_millis = millis();
}
bool MyTimer::elapsed() {
bool MyTimer::elapsed(void) {
unsigned long current_millis = millis();
if (current_millis - previous_millis >= interval) {
previous_millis = current_millis;
@ -12,3 +12,12 @@ bool MyTimer::elapsed() {
}
return false;
}
void MyTimer::reset(void) {
previous_millis = millis();
}
void MyTimer::set_interval(unsigned long interval) {
this->interval = interval;
reset();
}

View file

@ -13,11 +13,14 @@ class MyTimer {
/** interval in ms */
MyTimer(unsigned long interval);
/** Returns true and resets the timer if it has elapsed */
bool elapsed();
bool elapsed(void);
void reset(void);
void set_interval(unsigned long interval);
unsigned long interval;
unsigned long previous_millis;
private:
unsigned long previous_millis;
};
#endif // __MYTIMER_H__

View file

@ -74,7 +74,8 @@ String events_processor(const String& var) {
EVENTS_ENUM_TYPE event_handle = static_cast<EVENTS_ENUM_TYPE>(i);
Serial.println("Event: " + String(get_event_enum_string(event_handle)) +
" count: " + String(event_pointer->occurences) + " seconds: " + String(event_pointer->timestamp) +
" data: " + String(event_pointer->data));
" data: " + String(event_pointer->data) +
" level: " + String(get_event_level_string(event_handle)));
if (event_pointer->occurences > 0) {
content.concat("<div class='event'>");
content.concat("<div>" + String(get_event_enum_string(event_handle)) + "</div>");

View file

@ -508,8 +508,10 @@ String processor(const String& var) {
content += "<h4>Cell min: " + String(cell_min_voltage) + " mV</h4>";
content += "<h4>Temperature max: " + String(tempMaxFloat, 1) + " C</h4>";
content += "<h4>Temperature min: " + String(tempMinFloat, 1) + " C</h4>";
if (bms_status == 3) {
if (bms_status == ACTIVE) {
content += "<h4>BMS Status: OK </h4>";
} else if (bms_status == UPDATING) {
content += "<h4>BMS Status: UPDATING </h4>";
} else {
content += "<h4>BMS Status: FAULT </h4>";
}

View file

@ -13,7 +13,6 @@ 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 uint8_t bms_char_dis_status;
extern uint16_t stat_batt_power;
extern uint16_t temperature_min;

View file

@ -14,7 +14,6 @@ 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 uint8_t bms_char_dis_status;
extern uint16_t stat_batt_power;
extern uint16_t temperature_min;

View file

@ -1,6 +1,7 @@
//SERIAL-LINK-TRANSMITTER-INVERTER.cpp
#include "SERIAL-LINK-TRANSMITTER-INVERTER.h"
#include "../devboard/utils/events.h"
/*
* SerialDataLink
@ -107,10 +108,9 @@ void manageSerialLinkTransmitter() {
Serial.println("SerialDataLink : max_target_discharge_power = 0");
Serial.println("SerialDataLink : max_target_charge_power = 0");
bms_status = 4; //FAULT
max_target_discharge_power = 0;
max_target_charge_power = 0;
LEDcolor = RED;
set_event(EVENT_SERIAL_TX_FAILURE, 0);
// throw error
}
/*

View file

@ -24,7 +24,6 @@ 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 LEDcolor; //Enum, 0-10
extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false
extern bool LFP_Chemistry;

View file

@ -13,7 +13,6 @@ extern uint16_t capacity_Wh; //Wh, 0-60000
extern uint16_t remaining_capacity_Wh; //Wh, 0-60000
extern uint16_t max_target_discharge_power; //W, 0-60000
extern uint16_t max_target_charge_power; //W, 0-60000
extern uint8_t bms_status; //Enum, 0-5
extern 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)
@ -22,7 +21,6 @@ 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 uint8_t LEDcolor; //Enum, 0-10
extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false
extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false

View file

@ -14,14 +14,12 @@ extern uint16_t capacity_Wh; //Wh, 0-60000
extern uint16_t remaining_capacity_Wh; //Wh, 0-60000
extern uint16_t max_target_discharge_power; //W, 0-60000
extern uint16_t max_target_charge_power; //W, 0-60000
extern uint8_t bms_status; //Enum, 0-5
extern 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 uint8_t LEDcolor; //Enum, 0-10
extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false
extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false

View file

@ -16,7 +16,6 @@ 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 uint8_t bms_char_dis_status;
extern uint16_t stat_batt_power;
extern uint16_t temperature_min;

View file

@ -1,5 +1,6 @@
#include "ESP32CAN.h"
#include <Arduino.h>
#include "../../devboard/utils/events.h"
int ESP32CAN::CANInit() {
return CAN_init();
@ -12,13 +13,14 @@ int ESP32CAN::CANWriteFrame(const CAN_frame_t* p_frame) {
tx_ok = (result == 0) ? true : false;
if (tx_ok == false) {
Serial.println("CAN failure! Check wires");
LEDcolor = 3;
set_event(EVENT_CAN_FAILURE, 0);
start_time = millis();
} else {
clear_event(EVENT_CAN_FAILURE);
}
} else {
if ((millis() - start_time) >= 2000) {
tx_ok = true;
LEDcolor = 0;
}
}
return result;

View file

@ -3,7 +3,6 @@
#include "../../lib/miwagner-ESP32-Arduino-CAN/CAN.h"
#include "../../lib/miwagner-ESP32-Arduino-CAN/CAN_config.h"
extern uint8_t LEDcolor;
class ESP32CAN {
public:

View file

@ -8,12 +8,12 @@
/* Local rest variables */
bool elapsed = false;
/* Helper functions */
// bool MyTimer::elapsed(void) { return true; }
/* Stubs */
void run_sequence_on_target(void) {}
static void reset_event_msg(void) {
snprintf(events.message, sizeof(events.message), ".");
}
/* Helper functions */
/* Test functions */
TEST(init_events_test) {
init_events();
@ -27,11 +27,11 @@ TEST(init_events_test) {
TEST(update_event_time_test) {
// Reset
init_events();
testlib_millis = 0;
events.time_seconds = 0;
init_events();
// No delta, so time shouldn't increase
testlib_millis = 0;
update_event_time();
ASSERT_EQ(events.time_seconds, 0);
@ -74,16 +74,16 @@ TEST(set_event_test) {
}
TEST(events_message_test) {
reset_event_msg();
set_event(EVENT_DUMMY_ERROR, 0); // Set dummy event with no data
set_event(EVENT_DUMMY, 0); // Set dummy event with no data
ASSERT_STREQ("The dummy event was set!", events.message);
ASSERT_STREQ("The dummy error event was set!", get_event_message_string(EVENT_DUMMY_ERROR));
}
TEST(event_priority_test) {
ASSERT_TRUE(RED > BLUE);
ASSERT_TRUE(BLUE > YELLOW);
TEST(events_level_test) {
init_events();
set_event(EVENT_DUMMY_ERROR, 0); // Set dummy event with no data
ASSERT_STREQ("ERROR", get_event_level_string(EVENT_DUMMY_ERROR));
}
TEST_MAIN();