mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-05 10:49:42 +02:00
Halfway to the finish line
This commit is contained in:
parent
d9f3dbc3d0
commit
5e0893d3ca
3 changed files with 40 additions and 141 deletions
|
@ -12,7 +12,7 @@
|
||||||
//#define CHADEMO_BATTERY
|
//#define CHADEMO_BATTERY
|
||||||
//#define IMIEV_CZERO_ION_BATTERY
|
//#define IMIEV_CZERO_ION_BATTERY
|
||||||
//#define KIA_HYUNDAI_64_BATTERY
|
//#define KIA_HYUNDAI_64_BATTERY
|
||||||
//#define NISSAN_LEAF_BATTERY
|
#define NISSAN_LEAF_BATTERY
|
||||||
//#define RENAULT_KANGOO_BATTERY
|
//#define RENAULT_KANGOO_BATTERY
|
||||||
//#define RENAULT_ZOE_BATTERY
|
//#define RENAULT_ZOE_BATTERY
|
||||||
//#define SANTA_FE_PHEV_BATTERY
|
//#define SANTA_FE_PHEV_BATTERY
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
/* Select inverter communication protocol. See Wiki for which to use with your inverter: https://github.com/dalathegreat/BYD-Battery-Emulator-For-Gen24/wiki */
|
/* 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_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 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 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_CAN //Enable this line to emulate a "BYD Battery-Box H 8.9kWh, 7 mod" over CAN bus
|
||||||
|
@ -40,7 +40,7 @@
|
||||||
//#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 */
|
/* MQTT options */
|
||||||
//#define MQTT // Enable this line to enable MQTT
|
#define MQTT // Enable this line to enable MQTT
|
||||||
#define MQTT_SUBSCRIPTIONS \
|
#define MQTT_SUBSCRIPTIONS \
|
||||||
{ "my/topic/abc", "my/other/topic" }
|
{ "my/topic/abc", "my/other/topic" }
|
||||||
#define MQTT_SERVER "192.168.xxx.yyy"
|
#define MQTT_SERVER "192.168.xxx.yyy"
|
||||||
|
|
|
@ -4,25 +4,9 @@
|
||||||
#include "../config.h"
|
#include "../config.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
EVENT_STATE_INIT = 0,
|
|
||||||
EVENT_STATE_INACTIVE,
|
|
||||||
EVENT_STATE_ACTIVE,
|
|
||||||
EVENT_STATE_ACTIVE_LATCHED
|
|
||||||
} EVENT_STATE_TYPE;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t timestamp; // Time in seconds since startup when the event occurred
|
|
||||||
uint8_t data; // Custom data passed when setting the event, for example cell number for under voltage
|
|
||||||
uint8_t occurences; // Number of occurrences since startup
|
|
||||||
uint8_t led_color; // LED indication
|
|
||||||
EVENT_STATE_TYPE state; // Event state
|
|
||||||
} EVENTS_STRUCT_TYPE;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
EVENTS_STRUCT_TYPE entries[EVENT_NOF_EVENTS];
|
EVENTS_STRUCT_TYPE entries[EVENT_NOF_EVENTS];
|
||||||
uint32_t time_seconds;
|
uint32_t time_seconds;
|
||||||
char message[256];
|
|
||||||
MyTimer second_timer;
|
MyTimer second_timer;
|
||||||
uint8_t nof_yellow_events;
|
uint8_t nof_yellow_events;
|
||||||
uint8_t nof_blue_events;
|
uint8_t nof_blue_events;
|
||||||
|
@ -31,6 +15,8 @@ typedef struct {
|
||||||
|
|
||||||
/* Local variables */
|
/* Local variables */
|
||||||
static EVENT_TYPE events;
|
static EVENT_TYPE events;
|
||||||
|
static const char* EVENTS_ENUM_TYPE_STRING[] = {EVENTS_ENUM_TYPE(GENERATE_STRING)};
|
||||||
|
static const char* EVENTS_LEVEL_TYPE_STRING[] = {EVENTS_LEVEL_TYPE(GENERATE_STRING)};
|
||||||
|
|
||||||
/* Local function prototypes */
|
/* Local function prototypes */
|
||||||
static void update_event_time(void);
|
static void update_event_time(void);
|
||||||
|
@ -125,15 +111,14 @@ static void set_event(EVENTS_ENUM_TYPE event, uint8_t data, bool latched) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the event is already set, no reason to continue
|
// If the event is already set, no reason to continue
|
||||||
if ((events.entries[event].state == EVENT_STATE_ACTIVE) ||
|
if ((events.entries[event].state != EVENT_STATE_ACTIVE) &&
|
||||||
(events.entries[event].state == EVENT_STATE_ACTIVE_LATCHED)) {
|
(events.entries[event].state != EVENT_STATE_ACTIVE_LATCHED)) {
|
||||||
return;
|
events.entries[event].occurences++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We should set the event, update event info
|
// We should set the event, update event info
|
||||||
events.entries[event].timestamp = events.time_seconds;
|
events.entries[event].timestamp = events.time_seconds;
|
||||||
events.entries[event].data = data;
|
events.entries[event].data = data;
|
||||||
events.entries[event].occurences++;
|
|
||||||
// Check if the event is latching
|
// Check if the event is latching
|
||||||
events.entries[event].state = latched ? EVENT_STATE_ACTIVE_LATCHED : EVENT_STATE_ACTIVE;
|
events.entries[event].state = latched ? EVENT_STATE_ACTIVE_LATCHED : EVENT_STATE_ACTIVE;
|
||||||
|
|
||||||
|
@ -141,10 +126,8 @@ static void set_event(EVENTS_ENUM_TYPE event, uint8_t data, bool latched) {
|
||||||
update_led_color();
|
update_led_color();
|
||||||
update_bms_status();
|
update_bms_status();
|
||||||
|
|
||||||
// Set the associated event message, even if debug is disabled
|
|
||||||
set_message(event);
|
|
||||||
#ifdef DEBUG_VIA_USB
|
#ifdef DEBUG_VIA_USB
|
||||||
Serial.println(events.message);
|
Serial.println(get_event_message(event));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,83 +188,6 @@ static void update_led_color(void) {
|
||||||
// events.total_led_color = max(events.total_led_color, events.entries[event].led_color);
|
// events.total_led_color = max(events.total_led_color, events.entries[event].led_color);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_message(EVENTS_ENUM_TYPE event) {
|
|
||||||
switch (event) {
|
|
||||||
case EVENT_CAN_FAILURE:
|
|
||||||
snprintf(events.message, sizeof(events.message),
|
|
||||||
"No CAN communication detected for 60s. Shutting down battery control.");
|
|
||||||
break;
|
|
||||||
case EVENT_CAN_WARNING:
|
|
||||||
snprintf(events.message, sizeof(events.message),
|
|
||||||
"ERROR: High amount of corrupted CAN messages detected. Check CAN wire shielding!");
|
|
||||||
break;
|
|
||||||
case EVENT_WATER_INGRESS:
|
|
||||||
snprintf(events.message, sizeof(events.message),
|
|
||||||
"Water leakage inside battery detected. Operation halted. Inspect battery!");
|
|
||||||
break;
|
|
||||||
case EVENT_12V_LOW:
|
|
||||||
snprintf(events.message, sizeof(events.message),
|
|
||||||
"12V battery source below required voltage to safely close contactors. Inspect the supply/battery!");
|
|
||||||
break;
|
|
||||||
case EVENT_SOC_PLAUSIBILITY_ERROR:
|
|
||||||
snprintf(events.message, sizeof(events.message),
|
|
||||||
"ERROR: SOC reported by battery not plausible. Restart battery!");
|
|
||||||
break;
|
|
||||||
case EVENT_KWH_PLAUSIBILITY_ERROR:
|
|
||||||
snprintf(events.message, sizeof(events.message),
|
|
||||||
"Warning: kWh remaining reported by battery not plausible. Battery needs cycling.");
|
|
||||||
break;
|
|
||||||
case EVENT_BATTERY_CHG_STOP_REQ:
|
|
||||||
snprintf(events.message, sizeof(events.message),
|
|
||||||
"ERROR: Battery raised caution indicator AND requested charge stop. Inspect battery status!");
|
|
||||||
break;
|
|
||||||
case EVENT_BATTERY_DISCHG_STOP_REQ:
|
|
||||||
snprintf(events.message, sizeof(events.message),
|
|
||||||
"ERROR: Battery raised caution indicator AND requested discharge stop. Inspect battery status!");
|
|
||||||
break;
|
|
||||||
case EVENT_BATTERY_CHG_DISCHG_STOP_REQ:
|
|
||||||
snprintf(events.message, sizeof(events.message),
|
|
||||||
"ERROR: Battery raised caution indicator AND requested charge/discharge stop. Inspect battery status!");
|
|
||||||
break;
|
|
||||||
case EVENT_LOW_SOH:
|
|
||||||
snprintf(
|
|
||||||
events.message, sizeof(events.message),
|
|
||||||
"ERROR: State of health critically low. Battery internal resistance too high to continue. Recycle battery.");
|
|
||||||
break;
|
|
||||||
case EVENT_HVIL_FAILURE:
|
|
||||||
snprintf(events.message, sizeof(events.message),
|
|
||||||
"ERROR: Battery interlock loop broken. Check that high voltage connectors are seated. Battery will be "
|
|
||||||
"disabled!");
|
|
||||||
break;
|
|
||||||
case EVENT_INTERNAL_OPEN_FAULT:
|
|
||||||
snprintf(events.message, sizeof(events.message),
|
|
||||||
"ERROR: High voltage cable removed while battery running. Opening contactors!");
|
|
||||||
break;
|
|
||||||
case EVENT_CELL_UNDER_VOLTAGE:
|
|
||||||
snprintf(events.message, sizeof(events.message),
|
|
||||||
"ERROR: CELL UNDERVOLTAGE!!! Stopping battery charging and discharging. Inspect battery!");
|
|
||||||
break;
|
|
||||||
case EVENT_CELL_OVER_VOLTAGE:
|
|
||||||
snprintf(events.message, sizeof(events.message),
|
|
||||||
"ERROR: CELL OVERVOLTAGE!!! Stopping battery charging and discharging. Inspect battery!");
|
|
||||||
break;
|
|
||||||
case EVENT_CELL_DEVIATION_HIGH:
|
|
||||||
snprintf(events.message, sizeof(events.message), "ERROR: HIGH CELL DEVIATION!!! Inspect battery!");
|
|
||||||
break;
|
|
||||||
case EVENT_UNKNOWN_EVENT_SET:
|
|
||||||
snprintf(events.message, sizeof(events.message), "An unknown event was set! Review your code!");
|
|
||||||
break;
|
|
||||||
case EVENT_OTA_UPDATE:
|
|
||||||
snprintf(events.message, sizeof(events.message), "OTA update started!");
|
|
||||||
break;
|
|
||||||
case EVENT_DUMMY:
|
|
||||||
snprintf(events.message, sizeof(events.message), "The dummy event was set!"); // Don't change this event message!
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* get_event_message(EVENTS_ENUM_TYPE event) {
|
const char* get_event_message(EVENTS_ENUM_TYPE event) {
|
||||||
switch (event) {
|
switch (event) {
|
||||||
case EVENT_CAN_FAILURE:
|
case EVENT_CAN_FAILURE:
|
||||||
|
@ -326,14 +232,7 @@ const char* get_event_message(EVENTS_ENUM_TYPE event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* get_event_enum_string(EVENTS_ENUM_TYPE event) {
|
const char* get_event_enum_string(EVENTS_ENUM_TYPE event) {
|
||||||
const char* fullString = EVENTS_ENUM_TYPE_STRING[event];
|
return EVENTS_ENUM_TYPE_STRING[event] + 6; // Return the event name but skip "EVENT_" that should always be first
|
||||||
if (strncmp(fullString, "EVENT_", 6) == 0) {
|
|
||||||
return fullString + 6; // Skip the first 6 characters
|
|
||||||
}
|
|
||||||
return fullString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_event_message(EVENTS_ENUM_TYPE event) {
|
const char* get_event_type(EVENTS_ENUM_TYPE event) {}
|
||||||
const char* message = get_event_message(event);
|
|
||||||
snprintf(event_message, sizeof(event_message), "%s", message);
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,10 +4,27 @@
|
||||||
|
|
||||||
#ifndef UNIT_TEST
|
#ifndef UNIT_TEST
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
extern unsigned long previous_millis;
|
|
||||||
extern uint32_t time_seconds;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
EVENT_STATE_INIT = 0,
|
||||||
|
EVENT_STATE_INACTIVE,
|
||||||
|
EVENT_STATE_ACTIVE,
|
||||||
|
EVENT_STATE_ACTIVE_LATCHED
|
||||||
|
} EVENTS_STATE_TYPE;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
uint32_t timestamp; // Time in seconds since startup when the event occurred
|
||||||
|
uint8_t data; // Custom data passed when setting the event, for example cell number for under voltage
|
||||||
|
uint8_t occurences; // Number of occurrences since startup
|
||||||
|
uint8_t led_color; // LED indication
|
||||||
|
EVENTS_STATE_TYPE state; // Event state
|
||||||
|
} EVENTS_STRUCT_TYPE;
|
||||||
|
|
||||||
|
#define GENERATE_ENUM(ENUM) ENUM,
|
||||||
|
#define GENERATE_STRING(STRING) #STRING,
|
||||||
|
|
||||||
|
/* Event enumeration */
|
||||||
#define EVENTS_ENUM_TYPE(XX) \
|
#define EVENTS_ENUM_TYPE(XX) \
|
||||||
XX(EVENT_CAN_FAILURE) \
|
XX(EVENT_CAN_FAILURE) \
|
||||||
XX(EVENT_CAN_WARNING) \
|
XX(EVENT_CAN_WARNING) \
|
||||||
|
@ -25,42 +42,25 @@ extern uint32_t time_seconds;
|
||||||
XX(EVENT_CELL_OVER_VOLTAGE) \
|
XX(EVENT_CELL_OVER_VOLTAGE) \
|
||||||
XX(EVENT_CELL_DEVIATION_HIGH) \
|
XX(EVENT_CELL_DEVIATION_HIGH) \
|
||||||
XX(EVENT_UNKNOWN_EVENT_SET) \
|
XX(EVENT_UNKNOWN_EVENT_SET) \
|
||||||
|
XX(EVENT_OTA_UPDATE) \
|
||||||
XX(EVENT_DUMMY) \
|
XX(EVENT_DUMMY) \
|
||||||
XX(EVENT_NOF_EVENTS)
|
XX(EVENT_NOF_EVENTS)
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
EVENT_CAN_FAILURE = 0u, // RED event
|
|
||||||
EVENT_CAN_WARNING, // YELLOW event
|
|
||||||
EVENT_WATER_INGRESS, // RED event
|
|
||||||
EVENT_12V_LOW, // YELLOW event
|
|
||||||
EVENT_SOC_PLAUSIBILITY_ERROR, // RED event
|
|
||||||
EVENT_KWH_PLAUSIBILITY_ERROR, // YELLOW event
|
|
||||||
EVENT_BATTERY_CHG_STOP_REQ, // RED event
|
|
||||||
EVENT_BATTERY_DISCHG_STOP_REQ, // RED event
|
|
||||||
EVENT_BATTERY_CHG_DISCHG_STOP_REQ, // RED event
|
|
||||||
EVENT_LOW_SOH, // RED event
|
|
||||||
EVENT_HVIL_FAILURE, // RED event
|
|
||||||
EVENT_INTERNAL_OPEN_FAULT, // RED event
|
|
||||||
EVENT_CELL_UNDER_VOLTAGE, // RED event
|
|
||||||
EVENT_CELL_OVER_VOLTAGE, // RED event
|
|
||||||
EVENT_CELL_DEVIATION_HIGH, // YELLOW event
|
|
||||||
EVENT_UNKNOWN_EVENT_SET, // RED event
|
|
||||||
EVENT_OTA_UPDATE, // BLUE event
|
|
||||||
EVENT_DUMMY, // RED event
|
|
||||||
EVENT_NOF_EVENTS // RED event
|
|
||||||
} EVENTS_ENUM_TYPE;
|
|
||||||
#define GENERATE_ENUM(ENUM) ENUM,
|
|
||||||
#define GENERATE_STRING(STRING) #STRING,
|
|
||||||
|
|
||||||
typedef enum { EVENTS_ENUM_TYPE(GENERATE_ENUM) } EVENTS_ENUM_TYPE;
|
typedef enum { EVENTS_ENUM_TYPE(GENERATE_ENUM) } EVENTS_ENUM_TYPE;
|
||||||
|
|
||||||
static const char* EVENTS_ENUM_TYPE_STRING[] = {EVENTS_ENUM_TYPE(GENERATE_STRING)};
|
/* Event type enumeration */
|
||||||
|
#define EVENTS_LEVEL_TYPE(XX) \
|
||||||
|
XX(EVENT_LEVEL_ERROR) \
|
||||||
|
XX(EVENT_LEVEL_WARNING) \
|
||||||
|
XX(EVENT_LEVEL_INFO) \
|
||||||
|
XX(EVENT_LEVEL_DEBUG)
|
||||||
|
|
||||||
|
typedef enum { EVENTS_LEVEL_TYPE(GENERATE_ENUM) } EVENTS_LEVEL_TYPE;
|
||||||
|
|
||||||
const char* get_event_enum_string(EVENTS_ENUM_TYPE event);
|
const char* get_event_enum_string(EVENTS_ENUM_TYPE event);
|
||||||
|
|
||||||
const char* get_event_message(EVENTS_ENUM_TYPE event);
|
const char* get_event_message(EVENTS_ENUM_TYPE event);
|
||||||
|
|
||||||
const char* get_led_color_display_text(u_int8_t led_color);
|
const char* get_led_color_display_text(u_int8_t led_color);
|
||||||
|
const char* get_event_type(EVENTS_ENUM_TYPE event);
|
||||||
|
|
||||||
void init_events(void);
|
void init_events(void);
|
||||||
void set_event_latched(EVENTS_ENUM_TYPE event, uint8_t data);
|
void set_event_latched(EVENTS_ENUM_TYPE event, uint8_t data);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue