From 4dc45954e9c0d2adc83f152a0fbea9b7b8dfcc3d Mon Sep 17 00:00:00 2001 From: Emanuele Trabattoni Date: Wed, 8 Apr 2026 15:23:21 +0200 Subject: [PATCH] Webpage is OK, html in memory since SPIFFS is to slow. Moving average to be fixed --- RotaxMonitor/data/index.html | 198 ++++++++++++++++++++++++++++++++++ RotaxMonitor/platformio.ini | 60 ++++++----- RotaxMonitor/src/datasave.cpp | 106 +++++++++++++++++- RotaxMonitor/src/datasave.h | 42 +++++--- RotaxMonitor/src/devices.h | 2 - RotaxMonitor/src/main.cpp | 109 ++++++++++++++----- RotaxMonitor/src/ui.h | 190 +++++++++++++++++++++++++++++++- 7 files changed, 629 insertions(+), 78 deletions(-) create mode 100644 RotaxMonitor/data/index.html diff --git a/RotaxMonitor/data/index.html b/RotaxMonitor/data/index.html new file mode 100644 index 0000000..783cd00 --- /dev/null +++ b/RotaxMonitor/data/index.html @@ -0,0 +1,198 @@ + + + + + ESP32 Dashboard + + + + +

RotaxMonitor realtime data

+ + + + +
+

Timestamp: -

+

Generator voltage: -

+

Engine RPM: -

+

ADC read time: -

+

Queue errors: -

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyCoils 12Coils 34
Trigger time--
Spark time--
Spark delay--
Spark status--
Soft start status--
Peak P in--
Peak N in--
Peak P out--
Peak N out--
Level spark--
Events--
Missed firings--
+
+ + + + + \ No newline at end of file diff --git a/RotaxMonitor/platformio.ini b/RotaxMonitor/platformio.ini index 9001479..9e5b1bf 100644 --- a/RotaxMonitor/platformio.ini +++ b/RotaxMonitor/platformio.ini @@ -11,60 +11,62 @@ [env:esp32-s3-devkitc1-n16r8] board = esp32-s3-devkitc1-n16r8 board_build.partitions = partitions/no_ota_10mb_spiffs.csv +board_build.filesystem = spiffs platform = https://github.com/pioarduino/platform-espressif32/releases/download/stable/platform-espressif32.zip framework = arduino lib_deps = hideakitai/DebugLog@^0.8.4 bblanchon/ArduinoJson@^7.4.2 hideakitai/PCA95x5@^0.1.3 - adafruit/Adafruit SSD1306@^2.5.16 - garfius/Menu-UI@^1.2.0 - -;Upload protocol configuration + me-no-dev/AsyncTCP@^3.3.2 + me-no-dev/ESPAsyncWebServer@^3.6.0 upload_protocol = esptool upload_port = COM8 upload_speed = 921600 - -;Monitor configuration monitor_port = COM4 monitor_speed = 921600 - -; Build configuration build_type = release build_flags = - -DARDUINO_USB_CDC_ON_BOOT=0 - -DARDUINO_USB_MODE=0 - -fstack-protector-all - -DCONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=1 - -DCONFIG_FREERTOS_USE_TRACE_FACILITY=1 + -DCORE_DEBUG_LEVEL=5 + -DARDUINO_USB_CDC_ON_BOOT=0 + -DARDUINO_USB_MODE=0 + -DCONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=1 + -DCONFIG_FREERTOS_USE_TRACE_FACILITY=1 + -DCONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 + -DCONFIG_ASYNC_TCP_PRIORITY=20 + -DCONFIG_ASYNC_TCP_QUEUE_SIZE=128 + -DCONFIG_ASYNC_TCP_RUNNING_CORE=1 + -DCONFIG_ASYNC_TCP_STACK_SIZE=8192 + -fstack-protector-all [env:esp32-s3-devkitc1-n16r8-debug] board = ${env:esp32-s3-devkitc1-n16r8.board} board_build.partitions = ${env:esp32-s3-devkitc1-n16r8.board_build.partitions} +board_build.filesystem = ${env:esp32-s3-devkitc1-n16r8.board_build.filesystem} platform = ${env:esp32-s3-devkitc1-n16r8.platform} framework = ${env:esp32-s3-devkitc1-n16r8.framework} -lib_deps = ${env:esp32-s3-devkitc1-n16r8.lib_deps} - -;Upload protocol configuration +lib_deps = + ${env:esp32-s3-devkitc1-n16r8.lib_deps} upload_protocol = esptool upload_port = COM8 upload_speed = 921600 - -;Monitor configuration monitor_port = COM4 monitor_speed = 921600 - -; Debug configuration debug_tool = esp-builtin debug_speed = 15000 - -; Build configuration build_type = debug build_flags = - -O0 - -g3 - -ggdb3 - -DCORE_DEBUG_LEVEL=5 - -DARDUINO_USB_CDC_ON_BOOT=0 - -DARDUINO_USB_MODE=0 - -fstack-protector-all + -O0 + -g3 + -ggdb3 + -DCORE_DEBUG_LEVEL=5 + -DARDUINO_USB_CDC_ON_BOOT=0 + -DARDUINO_USB_MODE=0 + -DCONFIG_FREERTOS_GENERATE_RUN_TIME_STATS=1 + -DCONFIG_FREERTOS_USE_TRACE_FACILITY=1 + -DCONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 + -DCONFIG_ASYNC_TCP_PRIORITY=20 + -DCONFIG_ASYNC_TCP_QUEUE_SIZE=128 + -DCONFIG_ASYNC_TCP_RUNNING_CORE=1 + -DCONFIG_ASYNC_TCP_STACK_SIZE=8192 + -fstack-protector-all diff --git a/RotaxMonitor/src/datasave.cpp b/RotaxMonitor/src/datasave.cpp index 7387dc4..37fc778 100644 --- a/RotaxMonitor/src/datasave.cpp +++ b/RotaxMonitor/src/datasave.cpp @@ -2,12 +2,106 @@ static const size_t min_free = 1024 * 1024; // minimum free space in SPIFFS to allow saving history (1MB) +void ignitionBoxStatusAverage::reset() +{ + m_last = ignitionBoxStatus(); + m_count = 0; + m_data_valid = false; +} + +void ignitionBoxStatusAverage::update(const ignitionBoxStatus &new_status) +{ + if (m_count == 0) + { + m_last = new_status; + } + else + { + // simple moving average calculation + m_last.timestamp = new_status.timestamp; // keep timestamp of latest status + + m_last.coils12.n_events = new_status.coils12.n_events; // sum events instead of averaging + m_last.coils12.n_missed_firing = new_status.coils12.n_missed_firing; // sum missed firings instead of averaging + m_last.coils12.spark_status = new_status.coils12.spark_status; // take latest spark status + m_last.coils12.sstart_status = new_status.coils12.sstart_status; // take latest soft start status + m_last.coils12.spark_delay += (uint32_t)(0.1f * (float)(new_status.coils12.spark_delay - m_last.coils12.spark_delay)); // incremental average calculation + m_last.coils12.peak_p_in += 1.0f / m_max_count * (new_status.coils12.peak_p_in - m_last.coils12.peak_p_in); // incremental average calculation + m_last.coils12.peak_n_in += 1.0f / m_max_count * (new_status.coils12.peak_n_in - m_last.coils12.peak_n_in); // incremental average calculation + m_last.coils12.peak_p_out += 1.0f / m_max_count * (new_status.coils12.peak_p_out - m_last.coils12.peak_p_out); // incremental average calculation + m_last.coils12.peak_n_out += 1.0f / m_max_count * (new_status.coils12.peak_n_out - m_last.coils12.peak_n_out); // incremental average calculation + + m_last.coils34.n_events = new_status.coils34.n_events; // sum events instead of averaging + m_last.coils34.n_missed_firing = new_status.coils34.n_missed_firing; // sum missed firings instead of averaging + m_last.coils34.spark_status = new_status.coils34.spark_status; // take latest spark status + m_last.coils34.sstart_status = new_status.coils34.sstart_status; // take latest soft start status + m_last.coils34.spark_delay += (uint32_t)(0.1f * (float)(new_status.coils34.spark_delay - m_last.coils34.spark_delay)); // incremental average calculation + m_last.coils34.peak_p_in += 1.0f / m_max_count * (new_status.coils34.peak_p_in - m_last.coils34.peak_p_in); // incremental average calculation + m_last.coils34.peak_n_in += 1.0f / m_max_count * (new_status.coils34.peak_n_in - m_last.coils34.peak_n_in); // incremental average calculation + m_last.coils34.peak_p_out += 1.0f / m_max_count * (new_status.coils34.peak_p_out - m_last.coils34.peak_p_out); // incremental average calculation + m_last.coils34.peak_n_out += 1.0f / m_max_count * (new_status.coils34.peak_n_out - m_last.coils34.peak_n_out); // incremental average calculation + + m_last.eng_rpm += (uint32_t)(0.1f * (float)(new_status.eng_rpm - m_last.eng_rpm)); // incremental average calculation + m_last.adc_read_time += (uint32_t)(0.1f * (float)(new_status.adc_read_time - m_last.adc_read_time)); // incremental average calculation + m_last.n_queue_errors = new_status.n_queue_errors; // take last of queue errors since it's a cumulative count of errors in the queue, not an average value + } + m_count++; + if (m_count >= m_max_count) + { + m_count = 0; // reset count after reaching max samples to average + m_data_valid = true; // set data valid flag after first average is calculated + } +} + +const bool ignitionBoxStatusAverage::get(ignitionBoxStatus &status) const +{ + if (m_data_valid) + { + status = m_last; + } + return m_data_valid; +} + +const ArduinoJson::JsonDocument ignitionBoxStatusAverage::toJson() const +{ + ArduinoJson::JsonDocument doc; + if (m_data_valid) + { + doc["timestamp"] = m_last.timestamp; + + doc["coils12"]["n_events"] = m_last.coils12.n_events; + doc["coils12"]["n_missed_firing"] = m_last.coils12.n_missed_firing; + doc["coils12"]["spark_delay"] = m_last.coils12.spark_delay; + doc["coils12"]["spark_status"] = sparkStatusNames.at(m_last.coils12.spark_status); + doc["coils12"]["peak_p_in"] = m_last.coils12.peak_p_in; + doc["coils12"]["peak_n_in"] = m_last.coils12.peak_n_in; + doc["coils12"]["peak_p_out"] = m_last.coils12.peak_p_out; + doc["coils12"]["peak_n_out"] = m_last.coils12.peak_n_out; + doc["coils12"]["sstart_status"] = softStartStatusNames.at(m_last.coils12.sstart_status); + + doc["coils34"]["n_events"] = m_last.coils34.n_events; + doc["coils34"]["n_missed_firing"] = m_last.coils34.n_missed_firing; + doc["coils34"]["spark_delay"] = m_last.coils34.spark_delay; + doc["coils34"]["spark_status"] = sparkStatusNames.at(m_last.coils34.spark_status); + doc["coils34"]["peak_p_in"] = m_last.coils34.peak_p_in; + doc["coils34"]["peak_n_in"] = m_last.coils34.peak_n_in; + doc["coils34"]["peak_p_out"] = m_last.coils34.peak_p_out; + doc["coils34"]["peak_n_out"] = m_last.coils34.peak_n_out; + doc["coils34"]["sstart_status"] = softStartStatusNames.at(m_last.coils34.sstart_status); + + doc["eng_rpm"] = m_last.eng_rpm; + doc["adc_read_time"] = m_last.adc_read_time; + doc["n_queue_errors"] = m_last.n_queue_errors; + } + return doc; +} + void saveHistoryTask(void *pvParameters) { const auto *params = static_cast(pvParameters); const auto &history = *params->history; const auto &file_path = params->file_path; - if (!params) { + if (!params) + { LOG_ERROR("Invalid parameters for saveHistoryTask"); return; } @@ -19,9 +113,10 @@ void saveHistoryTask(void *pvParameters) void save_history(const PSRAMVector &history, const std::filesystem::path &file_name) { // Initialize SPIFFS - auto spiffs_guard = SPIFFSGuard(); // use RAII guard to ensure SPIFFS is properly mounted and unmounted + if (!SAVE_HISTORY_TO_SPIFFS) return; + //auto spiffs_guard = SPIFFSGuard(); // use RAII guard to ensure SPIFFS is properly mounted and unmounted - if (SPIFFS.totalBytes() - SPIFFS.usedBytes() < min_free ) // check if at least 1MB is free for saving history + if (SPIFFS.totalBytes() - SPIFFS.usedBytes() < min_free) // check if at least 1MB is free for saving history { LOG_ERROR("Not enough space in SPIFFS to save history"); return; @@ -35,7 +130,7 @@ void save_history(const PSRAMVector &history, const std::file if (first_save && SPIFFS.exists(file_path.c_str())) { first_save = false; - save_flags |= std::ios::trunc; // overwrite existing file + save_flags |= std::ios::trunc; // overwrite existing file SPIFFS.remove(file_path.c_str()); // ensure file is removed before saving to avoid issues with appending to existing file in SPIFFS LOG_INFO("Saving history to SPIFFS, new file:", file_path.c_str()); } @@ -58,7 +153,8 @@ void save_history(const PSRAMVector &history, const std::file ofs << "TS,\ EVENTS_12,DLY_12,STAT_12,V_12_1,V_12_2,V_12_3,V_12_4,IGNITION_MODE_12,\ EVENTS_34,DLY_34,STAT_34,V_34_1,V_34_2,V_34_3,V_34_4,IGNITION_MODE_34,\ - ENGINE_RPM,ADC_READTIME,N_QUEUE_ERRORS" << std::endl; + ENGINE_RPM,ADC_READTIME,N_QUEUE_ERRORS" + << std::endl; ofs.flush(); } diff --git a/RotaxMonitor/src/datasave.h b/RotaxMonitor/src/datasave.h index 60e7599..21851b6 100644 --- a/RotaxMonitor/src/datasave.h +++ b/RotaxMonitor/src/datasave.h @@ -8,14 +8,15 @@ #include #include #include +#include // Project Includes #include "isr.h" #include "psvector.h" const uint32_t max_history = 256; -const bool SAVE_HISTORY_TO_SPIFFS = true; // Set to true to enable saving history to SPIFFS, false to disable -static bool first_save = true; // flag to indicate if this is the first save (to write header) +const bool SAVE_HISTORY_TO_SPIFFS = false; // Set to true to enable saving history to SPIFFS, false to disable +static bool first_save = true; // flag to indicate if this is the first save (to write header) struct dataSaveParams { @@ -26,23 +27,40 @@ struct dataSaveParams class SPIFFSGuard { public: - SPIFFSGuard() { - if (!SPIFFS.begin(true)) { + SPIFFSGuard() + { + if (!SPIFFS.begin(true)) + { LOG_ERROR("Failed to mount SPIFFS"); - LOG_ERROR("5 seconds to restart..."); - vTaskDelay(pdMS_TO_TICKS(5000)); - esp_restart(); } - LOG_DEBUG("SPIFFS mounted successfully"); + LOG_INFO("SPIFFS mounted successfully"); } - ~SPIFFSGuard() { + ~SPIFFSGuard() + { SPIFFS.end(); - LOG_DEBUG("SPIFFS unmounted successfully"); + LOG_INFO("SPIFFS unmounted successfully"); } }; +class ignitionBoxStatusAverage +{ +private: + ignitionBoxStatus m_last; + uint32_t m_count = 0; + uint32_t m_max_count = 100; // number of samples to average before resetting + bool m_data_valid = false; // flag to indicate if the average data is valid (i.e. at least one sample has been added) + +public: + ignitionBoxStatusAverage() = default; + ignitionBoxStatusAverage(const uint32_t max_count) : m_max_count(max_count) {} + + void reset(); + void update(const ignitionBoxStatus &new_status); + const bool get(ignitionBoxStatus &status) const; + const ArduinoJson::JsonDocument toJson() const; +}; + // Task and function declarations void saveHistoryTask(void *pvParameters); -void save_history(const PSRAMVector &history, const std::filesystem::path& file_path); - +void save_history(const PSRAMVector &history, const std::filesystem::path &file_path); diff --git a/RotaxMonitor/src/devices.h b/RotaxMonitor/src/devices.h index e6027e5..d43d2c1 100644 --- a/RotaxMonitor/src/devices.h +++ b/RotaxMonitor/src/devices.h @@ -6,7 +6,6 @@ // Device Libraries #include #include -#include #include // ADC Channel mapping @@ -23,7 +22,6 @@ struct Devices { AD5292 *pot_a = NULL, *pot_b = NULL; ADS1256 *adc_a = NULL, *adc_b = NULL; - Adafruit_SSD1306* lcd = NULL; PCA9555* io = NULL; }; diff --git a/RotaxMonitor/src/main.cpp b/RotaxMonitor/src/main.cpp index 65a2ec8..c793436 100644 --- a/RotaxMonitor/src/main.cpp +++ b/RotaxMonitor/src/main.cpp @@ -5,6 +5,10 @@ #include #include #include +#include +#include +#include +#include // Definitions #include @@ -19,6 +23,23 @@ // #define CH_B_ENABLE #define TEST +#define WIFI_SSID "AstroRotaxMonitor" +#define WIFI_PASSWORD "maledettirotax" + +void onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *client, + AwsEventType type, void *arg, uint8_t *data, size_t len) +{ + switch (type) + { + case WS_EVT_CONNECT: + Serial.printf("WS client IP[%s]-ID[%u] CONNECTED\r\n", client->remoteIP().toString().c_str(), client->id()); + break; + case WS_EVT_DISCONNECT: + Serial.printf("WS client ID[%u] DISCONNECTED\r\n", client->remoteIP().toString().c_str(), client->id()); + break; + } +} + void setup() { Serial.begin(921600); @@ -29,21 +50,43 @@ void setup() LOG_SET_LEVEL(DebugLogLevel::LVL_INFO); // Print Processor Info - LOG_INFO("ESP32 Chip:", ESP.getChipModel()); + LOG_DEBUG("ESP32 Chip:", ESP.getChipModel()); if (psramFound()) { - LOG_INFO("ESP32 PSram Found"); - LOG_INFO("ESP32 PSram:", ESP.getPsramSize()); + LOG_DEBUG("ESP32 PSram Found"); + LOG_DEBUG("ESP32 PSram:", ESP.getPsramSize()); psramInit(); } - LOG_INFO("ESP32 Flash:", ESP.getFlashChipSize()); - LOG_INFO("ESP32 Heap:", ESP.getHeapSize()); - LOG_INFO("ESP32 Sketch:", ESP.getFreeSketchSpace()); + LOG_DEBUG("ESP32 Flash:", ESP.getFlashChipSize()); + LOG_DEBUG("ESP32 Heap:", ESP.getHeapSize()); + LOG_DEBUG("ESP32 Sketch:", ESP.getFreeSketchSpace()); // Initialize Interrupt pins on PICKUP detectors initTriggerPinsInputs(); // Initialize Interrupt pins on SPARK detectors initSparkPinInputs(); + + // Init Wifi station + LOG_INFO("Initializing WiFi..."); + WiFi.mode(WIFI_AP); + IPAddress local_IP(10, 11, 12, 1); + IPAddress gateway(10, 11, 12, 1); + IPAddress subnet(255, 255, 255, 0); + WiFi.softAPConfig(local_IP, gateway, subnet); + if (WiFi.softAP(WIFI_SSID, WIFI_PASSWORD)) + { + LOG_INFO("WiFi AP Mode Started"); + LOG_INFO("Wifi SSID:", WIFI_SSID); + LOG_INFO("Wifi Password:", WIFI_PASSWORD); + LOG_INFO("WiFi IP:" + WiFi.softAPIP().toString()); + } + else + { + LOG_ERROR("Failed to start WiFi AP Mode"); + LOG_ERROR("5 seconds to restart..."); + vTaskDelay(pdMS_TO_TICKS(5000)); + esp_restart(); + } } void loop() @@ -79,7 +122,7 @@ void loop() .spark_pin_34 = SPARK_PIN_A34}, .rt_resets = rtTaskResets{.rst_io_12p = RST_EXT_A12P, .rst_io_12n = RST_EXT_A12N, .rst_io_34p = RST_EXT_A34P, .rst_io_34n = RST_EXT_A34N}}; - LOG_INFO("Task Variables OK"); + LOG_DEBUG("Task Variables OK"); #ifdef CH_B_ENABLE QueueHandle_t rt_taskB_queue = xQueueCreate(max_queue, sizeof(ignitionBoxStatus)); @@ -118,7 +161,7 @@ void loop() vTaskDelay(pdMS_TO_TICKS(5000)); esp_restart(); } - LOG_INFO("Init SPI OK"); + LOG_DEBUG("Init SPI OK"); // Init ADC_A dev.adc_a = new ADS1256(ADC_A_DRDY, ADS1256::PIN_UNUSED, ADC_A_SYNC, ADC_A_CS, 2.5, &SPI_A); @@ -134,7 +177,7 @@ void loop() dev.adc_a->setDRATE(DRATE_1000SPS); #endif - LOG_INFO("Init ADC OK"); + LOG_DEBUG("Init ADC OK"); // Ignition A on Core 0 auto ignA_task_success = pdPASS; @@ -168,17 +211,29 @@ void loop() esp_restart(); } - LOG_INFO("Real Time Tasks A & B initialized"); + LOG_DEBUG("Real Time Tasks A & B initialized"); ////////////////////// MAIN LOOP ////////////////////// - clearScreen(); - setCursor(0, 0); bool partial_save = false; // flag to indicate if a partial save has been done after a timeout uint32_t counter = 0; + uint32_t wait_count = 0; ignitionBoxStatus ign_info; int64_t last = esp_timer_get_time(); uint32_t missed_firings12 = 0; uint32_t missed_firings34 = 0; + ignitionBoxStatusAverage ignA_avg(max_queue); // moving average calculator for ignition box A with a window of 100 samples + + AsyncWebServer server(80); + AsyncWebSocket ws("/ws"); + ws.onEvent(onWsEvent); + server.addHandler(&ws); + + auto spiffs_guard = SPIFFSGuard(); // use RAII guard to ensure SPIFFS is properly mounted and unmounted + server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.html"); + server.begin(); + + server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) + { request->send(200, "text/html", htmlTest.c_str()); }); while (running) { @@ -189,23 +244,10 @@ void loop() auto *temp = active_history; active_history = writable_history; // switch active and writable buffers writable_history = temp; // ensure writable_history points to the buffer we just filled - dataSaveParams save_params { + dataSaveParams save_params{ .history = writable_history, .file_path = "ignition_history.csv"}; - save_history(*writable_history, "ignition_history.csv"); // directly call the save task function to save without delay, since we already switched buffers and writable_history is now empty and ready for new data - // if (SAVE_HISTORY_TO_SPIFFS) - // if (pdFAIL == - // xTaskCreatePinnedToCore( - // saveHistoryTask, - // "saveHistoryTask", - // RT_TASK_STACK, - // &save_params, - // RT_TASK_PRIORITY - 1, // higher priority to ensure it runs asap after buffer switch - // NULL, - // CORE_1)) - // { - // LOG_ERROR("Unable to create saveHistoryTask"); - // } + save_history(*writable_history, "ignition_history.csv"); // directly call the save task function to save without delay } if (xQueueReceive(rt_taskA_queue, &ign_info, pdMS_TO_TICKS(1000)) == pdTRUE) @@ -213,17 +255,26 @@ void loop() // printInfo(ign_info); auto &hist = *active_history; hist[counter++ % active_history->size()] = ign_info; + ignA_avg.update(ign_info); // update moving average with latest ignition status Serial.print("Data Received: " + String(counter) + "/" + String(hist.size()) + '\r'); + + if (ws.count() > 0 && counter % max_queue == 0) + { + Serial.println(); + LOG_INFO("Sending average ignition status to websocket clients..."); + auto msg = ignA_avg.toJson().as(); + ws.textAll(msg); + } } else { - Serial.println("Waiting for data... "); + Serial.printf("[%d] Waiting for data...\r", wait_count++); if (!partial_save && counter > 0) // if timeout occurs but we have unsaved data, save it before next timeout { active_history->resize(counter); // resize active history to actual number of records received to avoid saving empty records save_history(*active_history, "ignition_history.csv"); active_history->resize(max_history); // resize back to max history size for next data cycle - counter = 0; // reset counter after saving + counter = 0; // reset counter after saving partial_save = true; first_save = true; } diff --git a/RotaxMonitor/src/ui.h b/RotaxMonitor/src/ui.h index a260e19..2d439ec 100644 --- a/RotaxMonitor/src/ui.h +++ b/RotaxMonitor/src/ui.h @@ -2,6 +2,7 @@ #include #include +#include void clearScreen(); void setCursor(const uint8_t x, const uint8_t y); @@ -10,4 +11,191 @@ void printField(const char name[], const int64_t val); void printField(const char name[], const float val); void printField(const char name[], const char *val); -void printInfo(const ignitionBoxStatus &info); \ No newline at end of file +void printInfo(const ignitionBoxStatus &info); + +static const std::string htmlTest = R"rawliteral( + + + + + ESP32 Dashboard + + + + +

RotaxMonitor realtime data

+ + + + +
+

Timestamp: -

+

Generator voltage: -

+

Engine RPM: -

+

ADC read time: -

+

Queue errors: -

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PropertyCoils 12Coils 34
Spark delay--
Spark status--
Soft start status--
Peak P in--
Peak N in--
Peak P out--
Peak N out--
Level spark--
Events--
Missed firings--
+
+ + + + + +)rawliteral"; \ No newline at end of file