updated and fixed charts
This commit is contained in:
@@ -185,11 +185,17 @@
|
||||
|
||||
<!-- TAB 2 (grafico) -->
|
||||
<div id="tab2" class="tab-content">
|
||||
<canvas id="chart" height="100"></canvas>
|
||||
<div class="chart-container">
|
||||
<h3>Box A</h3>
|
||||
<canvas id="chartA" height="100"></canvas>
|
||||
</div>
|
||||
|
||||
<div class="chart-container">
|
||||
<h3>Box B</h3>
|
||||
<canvas id="chartB" height="100"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="chart.js"></script>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
|
||||
<div class="upload-section">
|
||||
@@ -200,7 +206,7 @@
|
||||
<div id="uploadStatus" class="upload-status">No file uploaded yet.</div>
|
||||
</div>
|
||||
|
||||
<script src="chart.js"></script>
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -3,16 +3,23 @@ let lastMessageTimestamp = 0;
|
||||
const IDLE_THRESHOLD_MS = 1000;
|
||||
const loadingIndicator = document.getElementById("loadingIndicator");
|
||||
|
||||
let chart;
|
||||
let chartData = {
|
||||
let chartA, chartB;
|
||||
|
||||
let dataA = {
|
||||
labels: [],
|
||||
datasets: [
|
||||
{ label: "BoxA RPM", data: [] },
|
||||
{ label: "BoxB RPM", data: [] },
|
||||
{ label: "Coils12A Delay", data: [] },
|
||||
{ label: "Coils34A Delay", data: [] },
|
||||
{ label: "Coils12B Delay", data: [] },
|
||||
{ label: "Coils34B Delay", data: [] }
|
||||
{ label: "RPM", data: [] },
|
||||
{ label: "Coils12 Delay", data: [] },
|
||||
{ label: "Coils34 Delay", data: [] }
|
||||
]
|
||||
};
|
||||
|
||||
let dataB = {
|
||||
labels: [],
|
||||
datasets: [
|
||||
{ label: "RPM", data: [] },
|
||||
{ label: "Coils12 Delay", data: [] },
|
||||
{ label: "Coils34 Delay", data: [] }
|
||||
]
|
||||
};
|
||||
|
||||
@@ -64,7 +71,7 @@ function connectWS() {
|
||||
lastMessageTimestamp = Date.now();
|
||||
setLoadingIndicator(false);
|
||||
|
||||
updateChart(data)
|
||||
updateCharts(data)
|
||||
|
||||
// Update Box_A
|
||||
if (data.box_a) {
|
||||
@@ -138,42 +145,49 @@ function connectWS() {
|
||||
};
|
||||
}
|
||||
|
||||
function updateChart(data) {
|
||||
const time = new Date().toLocaleTimeString();
|
||||
function updateCharts(data) {
|
||||
|
||||
chartData.labels.push(time);
|
||||
const t = new Date().toLocaleTimeString();
|
||||
|
||||
// ===== BOX A =====
|
||||
dataA.labels.push(t);
|
||||
if (data.box_a) {
|
||||
const boxA = data.box_a;
|
||||
const coils12A = boxA.coils12 || {};
|
||||
const coils34A = boxA.coils34 || {};
|
||||
chartData.datasets[0].data.push(boxA.eng_rpm / 10);
|
||||
chartData.datasets[2].data.push(coils12A.spark_delay);
|
||||
chartData.datasets[3].data.push(coils34A.spark_delay);
|
||||
chartData.datasets[1].data.push(0);
|
||||
chartData.datasets[4].data.push(0);
|
||||
chartData.datasets[5].data.push(0);
|
||||
dataA.datasets[0].data.push(data.box_a.eng_rpm / 10);
|
||||
dataA.datasets[1].data.push(data.box_a.coils12.spark_delay);
|
||||
dataA.datasets[2].data.push(data.box_a.coils34.spark_delay);
|
||||
} else {
|
||||
dataA.datasets[0].data.push(undefined);
|
||||
dataA.datasets[1].data.push(undefined);
|
||||
dataA.datasets[2].data.push(undefined);
|
||||
}
|
||||
|
||||
// ===== BOX B =====
|
||||
dataB.labels.push(t);
|
||||
if (data.box_b) {
|
||||
const boxB = data.box_b;
|
||||
const coils12B = boxB.coils12 || {};
|
||||
const coils34B = boxB.coils34 || {};
|
||||
chartData.datasets[1].data.push(boxB.eng_rpm / 10);
|
||||
chartData.datasets[4].data.push(coils12B.spark_delay);
|
||||
chartData.datasets[5].data.push(coils34B.spark_delay);
|
||||
chartData.datasets[0].data.push(0);
|
||||
chartData.datasets[2].data.push(0);
|
||||
chartData.datasets[3].data.push(0);
|
||||
dataB.datasets[0].data.push(data.box_b.eng_rpm / 10);
|
||||
dataB.datasets[1].data.push(data.box_b.coils12.spark_delay);
|
||||
dataB.datasets[2].data.push(data.box_b.coils34.spark_delay);
|
||||
} else {
|
||||
dataB.datasets[0].data.push(undefined);
|
||||
dataB.datasets[1].data.push(undefined);
|
||||
dataB.datasets[2].data.push(undefined);
|
||||
}
|
||||
|
||||
// limite punti (tipo buffer)
|
||||
if (chartData.labels.length > 100) {
|
||||
chartData.labels.shift();
|
||||
chartData.datasets.forEach(d => d.data.shift());
|
||||
// limite buffer
|
||||
const maxPoints = 100;
|
||||
|
||||
if (dataA.labels.length > maxPoints) {
|
||||
dataA.labels.shift();
|
||||
dataA.datasets.forEach(d => d.data.shift());
|
||||
}
|
||||
|
||||
chart.update();
|
||||
if (dataB.labels.length > maxPoints) {
|
||||
dataB.labels.shift();
|
||||
dataB.datasets.forEach(d => d.data.shift());
|
||||
}
|
||||
|
||||
chartA.update();
|
||||
chartB.update();
|
||||
}
|
||||
|
||||
function start() {
|
||||
@@ -232,12 +246,29 @@ function openTab(tabId) {
|
||||
event.target.classList.add('active');
|
||||
}
|
||||
|
||||
function initChart() {
|
||||
const ctx = document.getElementById('chart').getContext('2d');
|
||||
function initCharts() {
|
||||
const ctxA = document.getElementById('chartA').getContext('2d');
|
||||
const ctxB = document.getElementById('chartB').getContext('2d');
|
||||
|
||||
chart = new Chart(ctx, {
|
||||
chartA = new Chart(ctxA, {
|
||||
type: 'line',
|
||||
data: chartData,
|
||||
data: dataA,
|
||||
options: {
|
||||
animation: false,
|
||||
responsive: true,
|
||||
scales: {
|
||||
x: {
|
||||
display: true
|
||||
},
|
||||
y: {
|
||||
beginAtZero: true
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
chartB = new Chart(ctxB, {
|
||||
type: 'line',
|
||||
data: dataB,
|
||||
options: {
|
||||
animation: false,
|
||||
responsive: true,
|
||||
@@ -254,7 +285,7 @@ function initChart() {
|
||||
}
|
||||
|
||||
window.onload = () => {
|
||||
initChart();
|
||||
initCharts();
|
||||
};
|
||||
|
||||
setInterval(updateLoadingState, 200);
|
||||
|
||||
@@ -248,3 +248,12 @@ span {
|
||||
.tab-content.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.chart-container {
|
||||
max-width: 1000px;
|
||||
margin: 20px auto;
|
||||
background: white;
|
||||
padding: 20px;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.08);
|
||||
}
|
||||
@@ -52,7 +52,7 @@ void setup()
|
||||
IPAddress gateway(10, 11, 12, 1);
|
||||
IPAddress subnet(255, 255, 255, 0);
|
||||
WiFi.softAPConfig(local_IP, gateway, subnet);
|
||||
WiFi.setTxPower(WIFI_POWER_5dBm); // reduce wifi power
|
||||
WiFi.setTxPower(WIFI_POWER_13dBm); // reduce wifi power
|
||||
if (WiFi.softAP(WIFI_SSID, WIFI_PASSWORD))
|
||||
{
|
||||
LOG_INFO("WiFi AP Mode Started");
|
||||
@@ -184,7 +184,7 @@ void loop()
|
||||
.rt_queue = nullptr,
|
||||
.dev = dev};
|
||||
|
||||
auto task_A = rtIgnitionTask(taskA_params, 4096, 256, CORE_1, fs_mutex);
|
||||
auto task_A = rtIgnitionTask(taskA_params, 4096, 256, CORE_0, fs_mutex);
|
||||
delay(50);
|
||||
auto task_B = rtIgnitionTask(taskB_params, 4096, 256, CORE_1, fs_mutex);
|
||||
|
||||
@@ -211,34 +211,38 @@ void loop()
|
||||
led.setStatus(RGBled::LedStatus::OK);
|
||||
|
||||
AstroWebServer webPage(80, LittleFS); // Initialize webserver and Websocket
|
||||
|
||||
task_A.onMessage([&webPage](ignitionBoxStatusFiltered sts){
|
||||
ArduinoJson::JsonDocument doc;
|
||||
doc["box_a"] = sts.toJson();
|
||||
doc["box_b"] = ArduinoJson::JsonDocument();
|
||||
webPage.sendWsData(doc.as<String>());
|
||||
ArduinoJson::JsonDocument json_data;
|
||||
bool data_a, data_b;
|
||||
task_A.onMessage([&webPage, &json_data, &data_a](ignitionBoxStatusFiltered sts){
|
||||
json_data["box_a"] = sts.toJson();
|
||||
data_a = true;
|
||||
});
|
||||
|
||||
task_B.onMessage([&webPage](ignitionBoxStatusFiltered sts){
|
||||
ArduinoJson::JsonDocument doc;
|
||||
doc["box_a"] = ArduinoJson::JsonDocument();
|
||||
doc["box_b"] = sts.toJson();
|
||||
webPage.sendWsData(doc.as<String>());
|
||||
task_B.onMessage([&webPage, &json_data, &data_b](ignitionBoxStatusFiltered sts){
|
||||
json_data["box_b"] = sts.toJson();
|
||||
data_b = true;
|
||||
});
|
||||
|
||||
task_A.enableSave(true, "ignitionA_test.csv");
|
||||
task_B.enableSave(true, "ignitionB_test.csv");
|
||||
// task_A.enableSave(true, "ignitionA_test.csv");
|
||||
// task_B.enableSave(true, "ignitionB_test.csv");
|
||||
|
||||
uint32_t last_loop = millis();
|
||||
uint32_t monitor_loop = millis();
|
||||
uint32_t data_loop = monitor_loop;
|
||||
//////////////// INNER LOOP /////////////////////
|
||||
while (running)
|
||||
{
|
||||
if ((millis() - last_loop) > 2000)
|
||||
uint32_t this_loop = millis();
|
||||
if (this_loop - monitor_loop > 2000)
|
||||
{
|
||||
clearScreen();
|
||||
printRunningTasksMod(Serial);
|
||||
delay(100);
|
||||
last_loop = millis();
|
||||
monitor_loop = millis();
|
||||
}
|
||||
if ((data_a && data_b) || (this_loop - data_loop > 500)) {
|
||||
webPage.sendWsData(json_data.as<String>());
|
||||
json_data.clear();
|
||||
data_a = data_b = false;
|
||||
data_loop = millis();
|
||||
}
|
||||
} //////////////// INNER LOOP /////////////////////
|
||||
|
||||
|
||||
@@ -360,7 +360,7 @@ void rtIgnitionTask::run()
|
||||
m_info_filtered.update(m_last_status);
|
||||
(*m_active_history)[m_counter_status] = m_last_status;
|
||||
|
||||
if (m_on_message_cb && m_counter_status % 10)
|
||||
if (m_on_message_cb && m_counter_status % 10 == 0)
|
||||
{
|
||||
m_on_message_cb(m_info_filtered);
|
||||
}
|
||||
|
||||
@@ -1,10 +1,19 @@
|
||||
#include <webserver.h>
|
||||
#include <ArduinoJson.h>
|
||||
|
||||
static const std::map<const std::string, AstroWebServer::c_commandEnum> s_webserverCommands = {
|
||||
static std::map<const std::string, AstroWebServer::c_commandEnum> s_webserverCommands = {
|
||||
{"setTime", AstroWebServer::SET_TIME},
|
||||
};
|
||||
|
||||
void on_ping(TimerHandle_t xTimer)
|
||||
{
|
||||
if (!xTimer)
|
||||
return;
|
||||
auto ws = (AsyncWebSocket *)pvTimerGetTimerID(xTimer);
|
||||
ws->pingAll();
|
||||
ws->cleanupClients();
|
||||
}
|
||||
|
||||
AstroWebServer::AstroWebServer(const uint8_t port, fs::FS &filesystem) : m_port(port), m_webserver(AsyncWebServer(port)), m_websocket(AsyncWebSocket("/ws")), m_filesystem(filesystem)
|
||||
{
|
||||
LOG_DEBUG("Initializing Web Server");
|
||||
@@ -20,11 +29,15 @@ AstroWebServer::AstroWebServer(const uint8_t port, fs::FS &filesystem) : m_port(
|
||||
{ onUploadHandler(request, filename, index, data, len, final); });
|
||||
|
||||
m_webserver.begin();
|
||||
m_websocket.enable(true);
|
||||
|
||||
m_pingTimer = xTimerCreate("wsPingTimer", pdMS_TO_TICKS(2000), pdTRUE, (void *)&m_websocket, on_ping);
|
||||
LOG_DEBUG("Webserver Init OK");
|
||||
}
|
||||
|
||||
AstroWebServer::~AstroWebServer()
|
||||
{
|
||||
xTimerDelete(m_pingTimer, pdMS_TO_TICKS(10));
|
||||
m_webserver.removeHandler(&m_websocket);
|
||||
m_webserver.end();
|
||||
}
|
||||
@@ -47,6 +60,9 @@ void AstroWebServer::onWsEvent(AsyncWebSocket *server, AsyncWebSocketClient *cli
|
||||
case WS_EVT_DISCONNECT:
|
||||
LOG_DEBUG("WS client IP[", client->remoteIP().toString().c_str(), "]-ID[", client->id(), "] DISCONNECTED");
|
||||
break;
|
||||
case WS_EVT_PONG:
|
||||
LOG_DEBUG("WS client IP[", client->remoteIP().toString().c_str(), "]-ID[", client->id(), "] PONG");
|
||||
break;
|
||||
case WS_EVT_DATA:
|
||||
{
|
||||
AwsFrameInfo *info = (AwsFrameInfo *)arg;
|
||||
|
||||
@@ -38,6 +38,7 @@ private:
|
||||
AsyncWebSocket m_websocket;
|
||||
bool m_uploadFailed = false;
|
||||
fs::File m_uploadFile;
|
||||
TimerHandle_t m_pingTimer = NULL;
|
||||
|
||||
public:
|
||||
enum c_commandEnum
|
||||
|
||||
Reference in New Issue
Block a user