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: -
+
+
+
+
+ | Property |
+ Coils 12 |
+ Coils 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: -
+
+
+
+
+ | Property |
+ Coils 12 |
+ Coils 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