mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-04 10:19:29 +02:00
add event log to webserver
This commit is contained in:
parent
f0f1fddb15
commit
3503b8586a
4 changed files with 126 additions and 77 deletions
|
@ -3,14 +3,6 @@
|
|||
#include "../../../USER_SETTINGS.h"
|
||||
#include "../config.h"
|
||||
|
||||
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; // Weirdly indented comment
|
||||
} EVENTS_STRUCT_TYPE;
|
||||
|
||||
static EVENTS_STRUCT_TYPE entries[EVENT_NOF_EVENTS];
|
||||
static unsigned long previous_millis = 0;
|
||||
static uint32_t time_seconds = 0;
|
||||
static uint8_t total_led_color = GREEN;
|
||||
|
@ -62,75 +54,52 @@ static void update_led_color(EVENTS_ENUM_TYPE event) {
|
|||
total_led_color = (total_led_color == RED) ? RED : entries[event].led_color;
|
||||
}
|
||||
|
||||
static void set_event_message(EVENTS_ENUM_TYPE event) {
|
||||
const char* get_event_message(EVENTS_ENUM_TYPE event) {
|
||||
switch (event) {
|
||||
case EVENT_CAN_FAILURE:
|
||||
snprintf(event_message, sizeof(event_message),
|
||||
"No CAN communication detected for 60s. Shutting down battery control.");
|
||||
break;
|
||||
return "No CAN communication detected for 60s. Shutting down battery control.";
|
||||
case EVENT_CAN_WARNING:
|
||||
snprintf(event_message, sizeof(event_message),
|
||||
"ERROR: High amount of corrupted CAN messages detected. Check CAN wire shielding!");
|
||||
break;
|
||||
return "ERROR: High amount of corrupted CAN messages detected. Check CAN wire shielding!";
|
||||
case EVENT_WATER_INGRESS:
|
||||
snprintf(event_message, sizeof(event_message),
|
||||
"Water leakage inside battery detected. Operation halted. Inspect battery!");
|
||||
break;
|
||||
return "Water leakage inside battery detected. Operation halted. Inspect battery!";
|
||||
case EVENT_12V_LOW:
|
||||
snprintf(event_message, sizeof(event_message),
|
||||
"12V battery source below required voltage to safely close contactors. Inspect the supply/battery!");
|
||||
break;
|
||||
return "12V battery source below required voltage to safely close contactors. Inspect the supply/battery!";
|
||||
case EVENT_SOC_PLAUSIBILITY_ERROR:
|
||||
snprintf(event_message, sizeof(event_message), "ERROR: SOC% reported by battery not plausible. Restart battery!");
|
||||
break;
|
||||
return "ERROR: SOC% reported by battery not plausible. Restart battery!";
|
||||
case EVENT_KWH_PLAUSIBILITY_ERROR:
|
||||
snprintf(event_message, sizeof(event_message),
|
||||
"Warning: kWh remaining reported by battery not plausible. Battery needs cycling.");
|
||||
break;
|
||||
return "Warning: kWh remaining reported by battery not plausible. Battery needs cycling.";
|
||||
case EVENT_BATTERY_CHG_STOP_REQ:
|
||||
snprintf(event_message, sizeof(event_message),
|
||||
"ERROR: Battery raised caution indicator AND requested charge stop. Inspect battery status!");
|
||||
break;
|
||||
return "ERROR: Battery raised caution indicator AND requested charge stop. Inspect battery status!";
|
||||
case EVENT_BATTERY_DISCHG_STOP_REQ:
|
||||
snprintf(event_message, sizeof(event_message),
|
||||
"ERROR: Battery raised caution indicator AND requested discharge stop. Inspect battery status!");
|
||||
break;
|
||||
return "ERROR: Battery raised caution indicator AND requested discharge stop. Inspect battery status!";
|
||||
case EVENT_BATTERY_CHG_DISCHG_STOP_REQ:
|
||||
snprintf(event_message, sizeof(event_message),
|
||||
"ERROR: Battery raised caution indicator AND requested charge/discharge stop. Inspect battery status!");
|
||||
break;
|
||||
return "ERROR: Battery raised caution indicator AND requested charge/discharge stop. Inspect battery status!";
|
||||
case EVENT_LOW_SOH:
|
||||
snprintf(
|
||||
event_message, sizeof(event_message),
|
||||
"ERROR: State of health critically low. Battery internal resistance too high to continue. Recycle battery.");
|
||||
break;
|
||||
return "ERROR: State of health critically low. Battery internal resistance too high to continue. Recycle battery.";
|
||||
case EVENT_HVIL_FAILURE:
|
||||
snprintf(event_message, sizeof(event_message),
|
||||
"ERROR: Battery interlock loop broken. Check that high voltage connectors are seated. Battery will be "
|
||||
"disabled!");
|
||||
break;
|
||||
return "ERROR: Battery interlock loop broken. Check that high voltage connectors are seated. Battery will be disabled!";
|
||||
case EVENT_INTERNAL_OPEN_FAULT:
|
||||
snprintf(event_message, sizeof(event_message),
|
||||
"ERROR: High voltage cable removed while battery running. Opening contactors!");
|
||||
break;
|
||||
return "ERROR: High voltage cable removed while battery running. Opening contactors!";
|
||||
case EVENT_CELL_UNDER_VOLTAGE:
|
||||
snprintf(event_message, sizeof(event_message),
|
||||
"ERROR: CELL UNDERVOLTAGE!!! Stopping battery charging and discharging. Inspect battery!");
|
||||
break;
|
||||
return "ERROR: CELL UNDERVOLTAGE!!! Stopping battery charging and discharging. Inspect battery!";
|
||||
case EVENT_CELL_OVER_VOLTAGE:
|
||||
snprintf(event_message, sizeof(event_message),
|
||||
"ERROR: CELL OVERVOLTAGE!!! Stopping battery charging and discharging. Inspect battery!");
|
||||
break;
|
||||
return "ERROR: CELL OVERVOLTAGE!!! Stopping battery charging and discharging. Inspect battery!";
|
||||
case EVENT_CELL_DEVIATION_HIGH:
|
||||
snprintf(event_message, sizeof(event_message), "ERROR: HIGH CELL DEVIATION!!! Inspect battery!");
|
||||
break;
|
||||
return "ERROR: HIGH CELL DEVIATION!!! Inspect battery!";
|
||||
case EVENT_UNKNOWN_EVENT_SET:
|
||||
snprintf(event_message, sizeof(event_message), "An unknown event was set! Review your code!");
|
||||
break;
|
||||
return "An unknown event was set! Review your code!";
|
||||
case EVENT_DUMMY:
|
||||
snprintf(event_message, sizeof(event_message), "The dummy event was set!"); // Don't change this event message!
|
||||
break;
|
||||
return "The dummy event was set!"; // Don't change this event message!
|
||||
default:
|
||||
break;
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
const char* get_event_enum_string(EVENTS_ENUM_TYPE event) {
|
||||
return EVENTS_ENUM_TYPE_STRING[event];
|
||||
}
|
||||
|
||||
static void set_event_message(EVENTS_ENUM_TYPE event) {
|
||||
const char* message = get_event_message(event);
|
||||
snprintf(event_message, sizeof(event_message), "%s", message);
|
||||
}
|
||||
|
|
|
@ -7,29 +7,50 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#define EVENTS_ENUM_TYPE(XX) \
|
||||
XX(EVENT_CAN_FAILURE) \
|
||||
XX(EVENT_CAN_WARNING) \
|
||||
XX(EVENT_WATER_INGRESS) \
|
||||
XX(EVENT_12V_LOW) \
|
||||
XX(EVENT_SOC_PLAUSIBILITY_ERROR) \
|
||||
XX(EVENT_KWH_PLAUSIBILITY_ERROR) \
|
||||
XX(EVENT_BATTERY_CHG_STOP_REQ) \
|
||||
XX(EVENT_BATTERY_DISCHG_STOP_REQ) \
|
||||
XX(EVENT_BATTERY_CHG_DISCHG_STOP_REQ) \
|
||||
XX(EVENT_LOW_SOH) \
|
||||
XX(EVENT_HVIL_FAILURE) \
|
||||
XX(EVENT_INTERNAL_OPEN_FAULT) \
|
||||
XX(EVENT_CELL_UNDER_VOLTAGE) \
|
||||
XX(EVENT_CELL_OVER_VOLTAGE) \
|
||||
XX(EVENT_CELL_DEVIATION_HIGH) \
|
||||
XX(EVENT_UNKNOWN_EVENT_SET) \
|
||||
XX(EVENT_DUMMY) \
|
||||
XX(EVENT_NOF_EVENTS)
|
||||
|
||||
#define GENERATE_ENUM(ENUM) ENUM,
|
||||
#define GENERATE_STRING(STRING) #STRING,
|
||||
|
||||
typedef enum {
|
||||
EVENT_CAN_FAILURE = 0u,
|
||||
EVENT_CAN_WARNING,
|
||||
EVENT_WATER_INGRESS,
|
||||
EVENT_12V_LOW,
|
||||
EVENT_SOC_PLAUSIBILITY_ERROR,
|
||||
EVENT_KWH_PLAUSIBILITY_ERROR,
|
||||
EVENT_BATTERY_CHG_STOP_REQ,
|
||||
EVENT_BATTERY_DISCHG_STOP_REQ,
|
||||
EVENT_BATTERY_CHG_DISCHG_STOP_REQ,
|
||||
EVENT_LOW_SOH,
|
||||
EVENT_HVIL_FAILURE,
|
||||
EVENT_INTERNAL_OPEN_FAULT,
|
||||
EVENT_CELL_UNDER_VOLTAGE,
|
||||
EVENT_CELL_OVER_VOLTAGE,
|
||||
EVENT_CELL_DEVIATION_HIGH,
|
||||
EVENT_UNKNOWN_EVENT_SET,
|
||||
EVENT_DUMMY,
|
||||
EVENT_NOF_EVENTS
|
||||
EVENTS_ENUM_TYPE(GENERATE_ENUM)
|
||||
} EVENTS_ENUM_TYPE;
|
||||
|
||||
static const char *EVENTS_ENUM_TYPE_STRING[] = {
|
||||
EVENTS_ENUM_TYPE(GENERATE_STRING)
|
||||
};
|
||||
|
||||
const char* get_event_enum_string(EVENTS_ENUM_TYPE event);
|
||||
|
||||
const char* get_event_message(EVENTS_ENUM_TYPE event);
|
||||
|
||||
void init_events(void);
|
||||
void set_event(EVENTS_ENUM_TYPE event, uint8_t data);
|
||||
void update_event_timestamps(void);
|
||||
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; // Weirdly indented comment
|
||||
} EVENTS_STRUCT_TYPE;
|
||||
static EVENTS_STRUCT_TYPE entries[EVENT_NOF_EVENTS];
|
||||
|
||||
#endif // __MYTIMER_H__
|
||||
|
|
|
@ -68,6 +68,10 @@ void init_webserver() {
|
|||
request->send_P(200, "text/html", index_html, cellmonitor_processor);
|
||||
});
|
||||
|
||||
server.on("events", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
request->send_P(200, "text/html", index_html, events_processor);
|
||||
});
|
||||
|
||||
// Route for editing Wh
|
||||
server.on("/updateBatterySize", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||
if (request->hasParam("value")) {
|
||||
|
@ -581,11 +585,14 @@ String processor(const String& var) {
|
|||
content += " ";
|
||||
content += "<button onclick='goToCellmonitorPage()'>Cellmonitor</button>";
|
||||
content += " ";
|
||||
content += "<button onclick='goToEventsPage()'>Events</button>";
|
||||
content += " ";
|
||||
content += "<button onclick='promptToReboot()'>Reboot Emulator</button>";
|
||||
content += "<script>";
|
||||
content += "function goToUpdatePage() { window.location.href = '/update'; }";
|
||||
content += "function goToCellmonitorPage() { window.location.href = '/cellmonitor'; }";
|
||||
content += "function goToSettingsPage() { window.location.href = '/settings'; }";
|
||||
content += "function goToEventsPage() { window.location.href = '/events'; }";
|
||||
content +=
|
||||
"function promptToReboot() { if (window.confirm('Are you sure you want to reboot the emulator? NOTE: If "
|
||||
"emulator is handling contactors, they will open during reboot!')) { "
|
||||
|
@ -897,6 +904,47 @@ String cellmonitor_processor(const String& var) {
|
|||
return String();
|
||||
}
|
||||
|
||||
String events_processor(const String& var) {
|
||||
if (var == "PLACEHOLDER") {
|
||||
String content = "";
|
||||
// Page format
|
||||
content += "<style>";
|
||||
content += "body { background-color: black; color: white; }";
|
||||
content += "table { width: 100%; border-collapse: collapse; }";
|
||||
content += "th, td { border: 1px solid white; padding: 10px; text-align: left; }";
|
||||
content += "</style>";
|
||||
|
||||
// Start a new block with a specific background color
|
||||
content += "<div style='background-color: #303E47; padding: 10px; margin-bottom: 10px;border-radius: 50px'>";
|
||||
|
||||
//iterate through entries and display count, time and event
|
||||
content += "<h4 style='color: white;'>Event log:</h4>";
|
||||
content += "<table>";
|
||||
content += "<tr><th>Event Type</th><th>LED Color</th><th>Last Event (seconds ago)</th><th>Count</th><th>Data</th><th>Message</th></tr>";
|
||||
for(int i = 0; i < EVENT_NOF_EVENTS; i++) {
|
||||
content += "<tr>";
|
||||
content += "<td>" + String(get_event_enum_string(static_cast<EVENTS_ENUM_TYPE>(i))) + "</td>";
|
||||
content += "<td>" + String(entries[i].led_color) + "</td>";
|
||||
content += "<td>" + String((millis() / 1000) - entries[i].timestamp) + "</td>";
|
||||
content += "<td>" + String(entries[i].occurences) + "</td>";
|
||||
content += "<td>" + String(entries[i].data) + "</td>";
|
||||
content += "<td>" + String(get_event_message(static_cast<EVENTS_ENUM_TYPE>(i))) + "</td>";
|
||||
content += "</tr>";
|
||||
}
|
||||
content += "</table>";
|
||||
|
||||
// Close the block
|
||||
content += "</div>";
|
||||
|
||||
content += "<button onclick='goToMainPage()'>Back to main page</button>";
|
||||
content += "<script>";
|
||||
content += "function goToMainPage() { window.location.href = '/'; }";
|
||||
content += "</script>";
|
||||
return content;
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
void onOTAStart() {
|
||||
// Log when OTA has started
|
||||
Serial.println("OTA update started!");
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "../../lib/me-no-dev-ESPAsyncWebServer/src/ESPAsyncWebServer.h"
|
||||
#include "../../lib/miwagner-ESP32-Arduino-CAN/ESP32CAN.h"
|
||||
#include "../config.h" // Needed for LED defines
|
||||
#include "../utils/events.h"
|
||||
#ifdef MQTT
|
||||
#include "../mqtt/mqtt.h"
|
||||
#endif
|
||||
|
@ -35,6 +36,7 @@ extern uint16_t cellvoltages[120]; //mV 0-4350 per cell
|
|||
extern uint8_t LEDcolor; //Enum, 0-10
|
||||
extern bool batteryAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||
extern bool inverterAllowsContactorClosing; //Bool, 1=true, 0=false
|
||||
extern EVENTS_STRUCT_TYPE entries[EVENT_NOF_EVENTS];
|
||||
|
||||
extern const char* ssid;
|
||||
extern const char* password;
|
||||
|
@ -117,6 +119,15 @@ String settings_processor(const String& var);
|
|||
*/
|
||||
String cellmonitor_processor(const String& var);
|
||||
|
||||
/**
|
||||
* @brief Replaces placeholder with content section in web page
|
||||
*
|
||||
* @param[in] var
|
||||
*
|
||||
* @return String
|
||||
*/
|
||||
String events_processor(const String& var);
|
||||
|
||||
/**
|
||||
* @brief Executes on OTA start
|
||||
*
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue