mirror of
https://github.com/dalathegreat/Battery-Emulator.git
synced 2025-10-03 09:49:32 +02:00
Make SD card configurable via webserver
This commit is contained in:
parent
94eeccb017
commit
6c8326fce1
8 changed files with 132 additions and 128 deletions
|
@ -80,10 +80,10 @@ void setup() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(LOG_CAN_TO_SD) || defined(LOG_TO_SD)
|
if (datalayer.system.info.CAN_SD_logging_active || datalayer.system.info.SD_logging_active) {
|
||||||
xTaskCreatePinnedToCore((TaskFunction_t)&logging_loop, "logging_loop", 4096, NULL, TASK_CONNECTIVITY_PRIO,
|
xTaskCreatePinnedToCore((TaskFunction_t)&logging_loop, "logging_loop", 4096, NULL, TASK_CONNECTIVITY_PRIO,
|
||||||
&logging_loop_task, esp32hal->WIFICORE());
|
&logging_loop_task, esp32hal->WIFICORE());
|
||||||
#endif
|
}
|
||||||
|
|
||||||
if (!init_contactors()) {
|
if (!init_contactors()) {
|
||||||
return;
|
return;
|
||||||
|
@ -167,22 +167,21 @@ void setup() {
|
||||||
// Loop empty, all functionality runs in tasks
|
// Loop empty, all functionality runs in tasks
|
||||||
void loop() {}
|
void loop() {}
|
||||||
|
|
||||||
#if defined(LOG_CAN_TO_SD) || defined(LOG_TO_SD)
|
|
||||||
void logging_loop(void*) {
|
void logging_loop(void*) {
|
||||||
|
|
||||||
init_logging_buffers();
|
init_logging_buffers();
|
||||||
init_sdcard();
|
init_sdcard();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
#ifdef LOG_TO_SD
|
if (datalayer.system.info.SD_logging_active) {
|
||||||
write_log_to_sdcard();
|
write_log_to_sdcard();
|
||||||
#endif
|
}
|
||||||
#ifdef LOG_CAN_TO_SD
|
|
||||||
write_can_frame_to_sdcard();
|
if (datalayer.system.info.CAN_SD_logging_active) {
|
||||||
#endif
|
write_can_frame_to_sdcard();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void connectivity_loop(void*) {
|
void connectivity_loop(void*) {
|
||||||
esp_task_wdt_add(NULL); // Register this task with WDT
|
esp_task_wdt_add(NULL); // Register this task with WDT
|
||||||
|
|
|
@ -107,8 +107,6 @@
|
||||||
//#define EQUIPMENT_STOP_BUTTON // Enable this to allow an equipment stop button connected to the Battery-Emulator to disengage the battery
|
//#define EQUIPMENT_STOP_BUTTON // Enable this to allow an equipment stop button connected to the Battery-Emulator to disengage the battery
|
||||||
//#define LFP_CHEMISTRY //Tesla specific setting, enable this line to startup in LFP mode
|
//#define LFP_CHEMISTRY //Tesla specific setting, enable this line to startup in LFP mode
|
||||||
//#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting
|
//#define INTERLOCK_REQUIRED //Nissan LEAF specific setting, if enabled requires both high voltage conenctors to be seated before starting
|
||||||
//#define LOG_TO_SD //Enable this line to log diagnostic data to SD card (WARNING, raises CPU load, do not use for production)
|
|
||||||
//#define LOG_CAN_TO_SD //Enable this line to log incoming/outgoing CAN & CAN-FD messages to SD card (WARNING, raises CPU load, do not use for production)
|
|
||||||
/* CAN options */
|
/* CAN options */
|
||||||
//#define CAN_ADDON //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 chip (Needed for some inverters / double battery)
|
//#define CAN_ADDON //Enable this line to activate an isolated secondary CAN Bus using add-on MCP2515 chip (Needed for some inverters / double battery)
|
||||||
#define CRYSTAL_FREQUENCY_MHZ 8 //CAN_ADDON option, what is your MCP2515 add-on boards crystal frequency?
|
#define CRYSTAL_FREQUENCY_MHZ 8 //CAN_ADDON option, what is your MCP2515 add-on boards crystal frequency?
|
||||||
|
@ -221,10 +219,6 @@ extern IPAddress gateway;
|
||||||
extern IPAddress subnet;
|
extern IPAddress subnet;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(DEBUG_VIA_USB) || defined(LOG_TO_SD)
|
|
||||||
#define DEBUG_LOG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(MEB_BATTERY)
|
#if defined(MEB_BATTERY)
|
||||||
#define PRECHARGE_CONTROL
|
#define PRECHARGE_CONTROL
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -138,6 +138,8 @@ void init_stored_settings() {
|
||||||
datalayer.system.info.CAN_usb_logging_active = settings.getBool("CANLOGUSB", false);
|
datalayer.system.info.CAN_usb_logging_active = settings.getBool("CANLOGUSB", false);
|
||||||
datalayer.system.info.usb_logging_active = settings.getBool("USBENABLED", false);
|
datalayer.system.info.usb_logging_active = settings.getBool("USBENABLED", false);
|
||||||
datalayer.system.info.web_logging_active = settings.getBool("WEBENABLED", false);
|
datalayer.system.info.web_logging_active = settings.getBool("WEBENABLED", false);
|
||||||
|
datalayer.system.info.CAN_SD_logging_active = settings.getBool("CANLOGSD", false);
|
||||||
|
datalayer.system.info.SD_logging_active = settings.getBool("SDLOGENABLED", false);
|
||||||
|
|
||||||
// WIFI AP is enabled by default unless disabled in the settings
|
// WIFI AP is enabled by default unless disabled in the settings
|
||||||
wifiap_enabled = settings.getBool("WIFIAPENABLED", true);
|
wifiap_enabled = settings.getBool("WIFIAPENABLED", true);
|
||||||
|
|
|
@ -244,9 +244,13 @@ struct DATALAYER_SYSTEM_INFO_TYPE {
|
||||||
/** bool, determines if USB serial logging should occur */
|
/** bool, determines if USB serial logging should occur */
|
||||||
bool CAN_usb_logging_active = false;
|
bool CAN_usb_logging_active = false;
|
||||||
/** bool, determines if USB serial logging should occur */
|
/** bool, determines if USB serial logging should occur */
|
||||||
|
bool CAN_SD_logging_active = false;
|
||||||
|
/** bool, determines if USB serial logging should occur */
|
||||||
bool usb_logging_active = false;
|
bool usb_logging_active = false;
|
||||||
/** bool, determines if general logging should be active for webserver */
|
/** bool, determines if general logging should be active for webserver */
|
||||||
bool web_logging_active = false;
|
bool web_logging_active = false;
|
||||||
|
/** bool, determines if general logging to SD card should be active */
|
||||||
|
bool SD_logging_active = false;
|
||||||
/** uint8_t, enumeration which CAN interface should be used for log playback */
|
/** uint8_t, enumeration which CAN interface should be used for log playback */
|
||||||
uint8_t can_replay_interface = CAN_NATIVE;
|
uint8_t can_replay_interface = CAN_NATIVE;
|
||||||
/** bool, determines if CAN replay should loop or not */
|
/** bool, determines if CAN replay should loop or not */
|
||||||
|
|
|
@ -63,9 +63,7 @@ void add_can_frame_to_buffer(CAN_frame frame, frameDirection msgDir) {
|
||||||
currentTime / 1000, currentTime % 1000, (msgDir == MSG_RX ? "RX0" : "TX1"), frame.ID, frame.DLC);
|
currentTime / 1000, currentTime % 1000, (msgDir == MSG_RX ? "RX0" : "TX1"), frame.ID, frame.DLC);
|
||||||
|
|
||||||
if (xRingbufferSend(can_bufferHandle, &messagestr_buffer, size, pdMS_TO_TICKS(2)) != pdTRUE) {
|
if (xRingbufferSend(can_bufferHandle, &messagestr_buffer, size, pdMS_TO_TICKS(2)) != pdTRUE) {
|
||||||
#ifdef DEBUG_VIA_USB
|
logging.println("Failed to send message to can ring buffer!");
|
||||||
Serial.println("Failed to send message to can ring buffer!");
|
|
||||||
#endif // DEBUG_VIA_USB
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,9 +75,7 @@ void add_can_frame_to_buffer(CAN_frame frame, frameDirection msgDir) {
|
||||||
size = snprintf(messagestr_buffer, sizeof(messagestr_buffer), "%02X\n", frame.data.u8[i]);
|
size = snprintf(messagestr_buffer, sizeof(messagestr_buffer), "%02X\n", frame.data.u8[i]);
|
||||||
|
|
||||||
if (xRingbufferSend(can_bufferHandle, &messagestr_buffer, size, pdMS_TO_TICKS(2)) != pdTRUE) {
|
if (xRingbufferSend(can_bufferHandle, &messagestr_buffer, size, pdMS_TO_TICKS(2)) != pdTRUE) {
|
||||||
#ifdef DEBUG_VIA_USB
|
logging.println("Failed to send message to can ring buffer!");
|
||||||
Serial.println("Failed to send message to can ring buffer!");
|
|
||||||
#endif // DEBUG_VIA_USB
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -127,9 +123,7 @@ void add_log_to_buffer(const uint8_t* buffer, size_t size) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (xRingbufferSend(log_bufferHandle, buffer, size, pdMS_TO_TICKS(1)) != pdTRUE) {
|
if (xRingbufferSend(log_bufferHandle, buffer, size, pdMS_TO_TICKS(1)) != pdTRUE) {
|
||||||
#ifdef DEBUG_VIA_USB
|
logging.println("Failed to send message to log ring buffer!");
|
||||||
Serial.println("Failed to send message to log ring buffer!");
|
|
||||||
#endif // DEBUG_VIA_USB
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -161,21 +155,22 @@ void write_log_to_sdcard() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_logging_buffers() {
|
void init_logging_buffers() {
|
||||||
#if defined(LOG_CAN_TO_SD)
|
|
||||||
can_bufferHandle = xRingbufferCreate(32 * 1024, RINGBUF_TYPE_BYTEBUF);
|
|
||||||
if (can_bufferHandle == NULL) {
|
|
||||||
logging.println("Failed to create CAN ring buffer!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif // defined(LOG_CAN_TO_SD)
|
|
||||||
|
|
||||||
#if defined(LOG_TO_SD)
|
if (datalayer.system.info.CAN_SD_logging_active) {
|
||||||
log_bufferHandle = xRingbufferCreate(1024, RINGBUF_TYPE_BYTEBUF);
|
can_bufferHandle = xRingbufferCreate(32 * 1024, RINGBUF_TYPE_BYTEBUF);
|
||||||
if (log_bufferHandle == NULL) {
|
if (can_bufferHandle == NULL) {
|
||||||
logging.println("Failed to create log ring buffer!");
|
logging.println("Failed to create CAN ring buffer!");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (datalayer.system.info.SD_logging_active) {
|
||||||
|
log_bufferHandle = xRingbufferCreate(1024, RINGBUF_TYPE_BYTEBUF);
|
||||||
|
if (log_bufferHandle == NULL) {
|
||||||
|
logging.println("Failed to create log ring buffer!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif // defined(LOG_TO_SD)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool init_sdcard() {
|
bool init_sdcard() {
|
||||||
|
|
|
@ -57,9 +57,9 @@ String debug_logger_processor(void) {
|
||||||
content += "<button onclick='refreshPage()'>Refresh data</button> ";
|
content += "<button onclick='refreshPage()'>Refresh data</button> ";
|
||||||
}
|
}
|
||||||
content += "<button onclick='exportLog()'>Export to .txt</button> ";
|
content += "<button onclick='exportLog()'>Export to .txt</button> ";
|
||||||
#ifdef LOG_TO_SD
|
if (datalayer.system.info.SD_logging_active) {
|
||||||
content += "<button onclick='deleteLog()'>Delete log file</button> ";
|
content += "<button onclick='deleteLog()'>Delete log file</button> ";
|
||||||
#endif
|
}
|
||||||
content += "<button onclick='goToMainPage()'>Back to main page</button>";
|
content += "<button onclick='goToMainPage()'>Back to main page</button>";
|
||||||
|
|
||||||
// Start a new block for the debug log messages
|
// Start a new block for the debug log messages
|
||||||
|
@ -98,9 +98,9 @@ String debug_logger_processor(void) {
|
||||||
content += "<script>";
|
content += "<script>";
|
||||||
content += "function refreshPage(){ location.reload(true); }";
|
content += "function refreshPage(){ location.reload(true); }";
|
||||||
content += "function exportLog() { window.location.href = '/export_log'; }";
|
content += "function exportLog() { window.location.href = '/export_log'; }";
|
||||||
#ifdef LOG_TO_SD
|
if (datalayer.system.info.SD_logging_active) {
|
||||||
content += "function deleteLog() { window.location.href = '/delete_log'; }";
|
content += "function deleteLog() { window.location.href = '/delete_log'; }";
|
||||||
#endif
|
}
|
||||||
content += "function goToMainPage() { window.location.href = '/'; }";
|
content += "function goToMainPage() { window.location.href = '/'; }";
|
||||||
content += "</script>";
|
content += "</script>";
|
||||||
content += index_html_footer;
|
content += index_html_footer;
|
||||||
|
|
|
@ -266,6 +266,14 @@ String settings_processor(const String& var, BatteryEmulatorSettingsStore& setti
|
||||||
return settings.getBool("WEBENABLED") ? "checked" : "";
|
return settings.getBool("WEBENABLED") ? "checked" : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (var == "CANLOGSD") {
|
||||||
|
return settings.getBool("CANLOGSD") ? "checked" : "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (var == "SDLOGENABLED") {
|
||||||
|
return settings.getBool("SDLOGENABLED") ? "checked" : "";
|
||||||
|
}
|
||||||
|
|
||||||
if (var == "MQTTENABLED") {
|
if (var == "MQTTENABLED") {
|
||||||
return settings.getBool("MQTTENABLED") ? "checked" : "";
|
return settings.getBool("MQTTENABLED") ? "checked" : "";
|
||||||
}
|
}
|
||||||
|
@ -883,6 +891,12 @@ const char* getCANInterfaceName(CAN_Interface interface) {
|
||||||
<label>Enable logging via Webserver: </label>
|
<label>Enable logging via Webserver: </label>
|
||||||
<input type='checkbox' name='WEBENABLED' value='on' style='margin-left: 0;' %WEBENABLED% />
|
<input type='checkbox' name='WEBENABLED' value='on' style='margin-left: 0;' %WEBENABLED% />
|
||||||
|
|
||||||
|
<label>Enable CAN logging via SD card: </label>
|
||||||
|
<input type='checkbox' name='CANLOGSD' value='on' style='margin-left: 0;' %CANLOGSD% />
|
||||||
|
|
||||||
|
<label>Enable logging via SD card: </label>
|
||||||
|
<input type='checkbox' name='SDLOGENABLED' value='on' style='margin-left: 0;' %SDLOGENABLED% />
|
||||||
|
|
||||||
<label>Enable MQTT: </label>
|
<label>Enable MQTT: </label>
|
||||||
<input type='checkbox' name='MQTTENABLED' value='on' style='margin-left: 0;' %MQTTENABLED% />
|
<input type='checkbox' name='MQTTENABLED' value='on' style='margin-left: 0;' %MQTTENABLED% />
|
||||||
|
|
||||||
|
|
|
@ -267,7 +267,7 @@ void init_webserver() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (datalayer.system.info.web_logging_active) { //|| defined(LOG_TO_SD)
|
if (datalayer.system.info.web_logging_active || datalayer.system.info.SD_logging_active) {
|
||||||
// Route for going to debug logging web page
|
// Route for going to debug logging web page
|
||||||
server.on("/log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
AsyncWebServerResponse* response = request->beginResponse(200, "text/html", debug_logger_processor());
|
AsyncWebServerResponse* response = request->beginResponse(200, "text/html", debug_logger_processor());
|
||||||
|
@ -289,93 +289,89 @@ void init_webserver() {
|
||||||
},
|
},
|
||||||
handleFileUpload);
|
handleFileUpload);
|
||||||
|
|
||||||
#ifndef LOG_CAN_TO_SD
|
if (datalayer.system.info.CAN_SD_logging_active) {
|
||||||
// Define the handler to export can log
|
// Define the handler to export can log
|
||||||
server.on("/export_can_log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/export_can_log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
String logs = String(datalayer.system.info.logged_can_messages);
|
pause_can_writing();
|
||||||
if (logs.length() == 0) {
|
request->send(SD_MMC, CAN_LOG_FILE, String(), true);
|
||||||
logs = "No logs available.";
|
resume_can_writing();
|
||||||
}
|
});
|
||||||
|
|
||||||
// Get the current time
|
// Define the handler to delete can log
|
||||||
time_t now = time(nullptr);
|
server.on("/delete_can_log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
struct tm timeinfo;
|
delete_can_log();
|
||||||
localtime_r(&now, &timeinfo);
|
request->send(200, "text/plain", "Log file deleted");
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Define the handler to export can log
|
||||||
|
server.on("/export_can_log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
String logs = String(datalayer.system.info.logged_can_messages);
|
||||||
|
if (logs.length() == 0) {
|
||||||
|
logs = "No logs available.";
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure time retrieval was successful
|
// Get the current time
|
||||||
char filename[32];
|
time_t now = time(nullptr);
|
||||||
if (strftime(filename, sizeof(filename), "canlog_%H-%M-%S.txt", &timeinfo)) {
|
struct tm timeinfo;
|
||||||
// Valid filename created
|
localtime_r(&now, &timeinfo);
|
||||||
} else {
|
|
||||||
// Fallback filename if automatic timestamping failed
|
|
||||||
strcpy(filename, "battery_emulator_can_log.txt");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use request->send with dynamic headers
|
// Ensure time retrieval was successful
|
||||||
AsyncWebServerResponse* response = request->beginResponse(200, "text/plain", logs);
|
char filename[32];
|
||||||
response->addHeader("Content-Disposition", String("attachment; filename=\"") + String(filename) + "\"");
|
if (strftime(filename, sizeof(filename), "canlog_%H-%M-%S.txt", &timeinfo)) {
|
||||||
request->send(response);
|
// Valid filename created
|
||||||
});
|
} else {
|
||||||
#endif
|
// Fallback filename if automatic timestamping failed
|
||||||
|
strcpy(filename, "battery_emulator_can_log.txt");
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef LOG_CAN_TO_SD
|
// Use request->send with dynamic headers
|
||||||
// Define the handler to export can log
|
AsyncWebServerResponse* response = request->beginResponse(200, "text/plain", logs);
|
||||||
server.on("/export_can_log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
response->addHeader("Content-Disposition", String("attachment; filename=\"") + String(filename) + "\"");
|
||||||
pause_can_writing();
|
request->send(response);
|
||||||
request->send(SD_MMC, CAN_LOG_FILE, String(), true);
|
});
|
||||||
resume_can_writing();
|
}
|
||||||
});
|
|
||||||
|
|
||||||
// Define the handler to delete can log
|
if (datalayer.system.info.SD_logging_active) {
|
||||||
server.on("/delete_can_log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
// Define the handler to delete log file
|
||||||
delete_can_log();
|
server.on("/delete_log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
request->send(200, "text/plain", "Log file deleted");
|
delete_log();
|
||||||
});
|
request->send(200, "text/plain", "Log file deleted");
|
||||||
#endif
|
});
|
||||||
|
|
||||||
#ifdef LOG_TO_SD
|
// Define the handler to export debug log
|
||||||
// Define the handler to delete log file
|
server.on("/export_log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
server.on("/delete_log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
pause_log_writing();
|
||||||
delete_log();
|
request->send(SD_MMC, LOG_FILE, String(), true);
|
||||||
request->send(200, "text/plain", "Log file deleted");
|
resume_log_writing();
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// Define the handler to export debug log
|
||||||
|
server.on("/export_log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
String logs = String(datalayer.system.info.logged_can_messages);
|
||||||
|
if (logs.length() == 0) {
|
||||||
|
logs = "No logs available.";
|
||||||
|
}
|
||||||
|
|
||||||
// Define the handler to export debug log
|
// Get the current time
|
||||||
server.on("/export_log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
time_t now = time(nullptr);
|
||||||
pause_log_writing();
|
struct tm timeinfo;
|
||||||
request->send(SD_MMC, LOG_FILE, String(), true);
|
localtime_r(&now, &timeinfo);
|
||||||
resume_log_writing();
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef LOG_TO_SD
|
// Ensure time retrieval was successful
|
||||||
// Define the handler to export debug log
|
char filename[32];
|
||||||
server.on("/export_log", HTTP_GET, [](AsyncWebServerRequest* request) {
|
if (strftime(filename, sizeof(filename), "log_%H-%M-%S.txt", &timeinfo)) {
|
||||||
String logs = String(datalayer.system.info.logged_can_messages);
|
// Valid filename created
|
||||||
if (logs.length() == 0) {
|
} else {
|
||||||
logs = "No logs available.";
|
// Fallback filename if automatic timestamping failed
|
||||||
}
|
strcpy(filename, "battery_emulator_log.txt");
|
||||||
|
}
|
||||||
|
|
||||||
// Get the current time
|
// Use request->send with dynamic headers
|
||||||
time_t now = time(nullptr);
|
AsyncWebServerResponse* response = request->beginResponse(200, "text/plain", logs);
|
||||||
struct tm timeinfo;
|
response->addHeader("Content-Disposition", String("attachment; filename=\"") + String(filename) + "\"");
|
||||||
localtime_r(&now, &timeinfo);
|
request->send(response);
|
||||||
|
});
|
||||||
// Ensure time retrieval was successful
|
}
|
||||||
char filename[32];
|
|
||||||
if (strftime(filename, sizeof(filename), "log_%H-%M-%S.txt", &timeinfo)) {
|
|
||||||
// Valid filename created
|
|
||||||
} else {
|
|
||||||
// Fallback filename if automatic timestamping failed
|
|
||||||
strcpy(filename, "battery_emulator_log.txt");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use request->send with dynamic headers
|
|
||||||
AsyncWebServerResponse* response = request->beginResponse(200, "text/plain", logs);
|
|
||||||
response->addHeader("Content-Disposition", String("attachment; filename=\"") + String(filename) + "\"");
|
|
||||||
request->send(response);
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Route for going to cellmonitor web page
|
// Route for going to cellmonitor web page
|
||||||
def_route_with_auth("/cellmonitor", server, HTTP_GET, [](AsyncWebServerRequest* request) {
|
def_route_with_auth("/cellmonitor", server, HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
@ -413,8 +409,8 @@ void init_webserver() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const char* boolSettingNames[] = {
|
const char* boolSettingNames[] = {
|
||||||
"DBLBTR", "CNTCTRL", "CNTCTRLDBL", "PWMCNTCTRL", "PERBMSRESET",
|
"DBLBTR", "CNTCTRL", "CNTCTRLDBL", "PWMCNTCTRL", "PERBMSRESET", "SDLOGENABLED",
|
||||||
"REMBMSRESET", "USBENABLED", "CANLOGUSB", "WEBENABLED", "CANFDASCAN",
|
"REMBMSRESET", "USBENABLED", "CANLOGUSB", "WEBENABLED", "CANFDASCAN", "CANLOGSD",
|
||||||
"WIFIAPENABLED", "MQTTENABLED", "HADISC", "MQTTTOPICS", "INVICNT",
|
"WIFIAPENABLED", "MQTTENABLED", "HADISC", "MQTTTOPICS", "INVICNT",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1389,7 +1385,7 @@ String processor(const String& var) {
|
||||||
content += "<button onclick='Advanced()'>More Battery Info</button> ";
|
content += "<button onclick='Advanced()'>More Battery Info</button> ";
|
||||||
content += "<button onclick='CANlog()'>CAN logger</button> ";
|
content += "<button onclick='CANlog()'>CAN logger</button> ";
|
||||||
content += "<button onclick='CANreplay()'>CAN replay</button> ";
|
content += "<button onclick='CANreplay()'>CAN replay</button> ";
|
||||||
if (datalayer.system.info.web_logging_active) { //|| defined(LOG_TO_SD)
|
if (datalayer.system.info.web_logging_active || datalayer.system.info.SD_logging_active) {
|
||||||
content += "<button onclick='Log()'>Log</button> ";
|
content += "<button onclick='Log()'>Log</button> ";
|
||||||
}
|
}
|
||||||
content += "<button onclick='Cellmon()'>Cellmonitor</button> ";
|
content += "<button onclick='Cellmon()'>Cellmonitor</button> ";
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue