Add CSV recording capabilities
This commit is contained in:
parent
4ea73aa32c
commit
688e8f03bb
|
@ -9,39 +9,22 @@
|
|||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
||||
<h1>/* therminator */</h1>
|
||||
<p>last sensor update: <span id="time"></span></p>
|
||||
<div id="options">
|
||||
<div id="mv">
|
||||
<p>
|
||||
max data points:
|
||||
<select id="maxVals" onchange="location.reload()">
|
||||
<option>15</option>
|
||||
<option>20</option>
|
||||
<option>30</option>
|
||||
<option>50</option>
|
||||
<option>100</option>
|
||||
</select>
|
||||
</p>
|
||||
</div>
|
||||
<div id="ui">
|
||||
<p>
|
||||
update interval (ms):
|
||||
<select id="updateInterval" onchange="changeUpdateInterval()">
|
||||
<option selected>500</option>
|
||||
<option>1000</option>
|
||||
<option>3000</option>
|
||||
</select>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div id="chart-small">
|
||||
<h2>Channel A:</h2>
|
||||
<div id="error-tempA"></div>
|
||||
<canvas id="chartA-mobile"></canvas>
|
||||
<h2>Channel B:</h2>
|
||||
<div id="error-tempB"></div>
|
||||
<canvas id="chartB-mobile"></canvas>
|
||||
</div>
|
||||
<div id="chart-large">
|
||||
<p>chart update interval (ms): <select id="chartUpd" onchange="location.reload()">
|
||||
<option>200</option>
|
||||
<option selected>500</option>
|
||||
<option>1000</option>
|
||||
</select></p>
|
||||
<p>data update interval (ms): <select id="upd" onload="getUpdateInterval()" onchange="setUpdateInterval()">
|
||||
<option>10</option>
|
||||
<option>20</option>
|
||||
<option>50</option>
|
||||
<option>100</option>
|
||||
<option>200</option>
|
||||
<option selected>500</option>
|
||||
<option>1000</option>
|
||||
</select></p>
|
||||
<button id="startRec" onclick="startRecording()">Start recording</button>
|
||||
<button id="stopRec" onclick="stopRecording()">Stop recording</button>
|
||||
<table>
|
||||
<tr>
|
||||
<td class="chart-container">
|
||||
|
@ -56,8 +39,6 @@
|
|||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<script src="script.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
166
data/script.js
166
data/script.js
|
@ -1,11 +1,11 @@
|
|||
const canvasA = document.getElementById("chartA");
|
||||
const canvasB = document.getElementById("chartB");
|
||||
const mobCanvasA = document.getElementById("chartA-mobile");
|
||||
const mobCanvasB = document.getElementById("chartB-mobile");
|
||||
|
||||
const maxValsSelect = document.getElementById("maxVals");
|
||||
let maxVals = maxValsSelect.options[maxValsSelect.selectedIndex].text;
|
||||
|
||||
const chartUpdateInt = document.getElementById("chartUpd").value;
|
||||
document.getElementById("stopRec").disabled = true;
|
||||
let data;
|
||||
let record = 0;
|
||||
let filename;
|
||||
const csvData = ["time, tempA, tempB"];
|
||||
const chartAdata = {
|
||||
data: {
|
||||
labels: [],
|
||||
|
@ -35,6 +35,12 @@ const chartBdata = {
|
|||
};
|
||||
|
||||
const options = {
|
||||
animation: false,
|
||||
elements: {
|
||||
point: {
|
||||
pointStyle: false,
|
||||
},
|
||||
},
|
||||
responsive: true,
|
||||
plugins: {
|
||||
legend: {
|
||||
|
@ -107,38 +113,6 @@ const chartB = new Chart(canvasB, {
|
|||
options: options,
|
||||
});
|
||||
|
||||
const mobChartA = new Chart(mobCanvasA, {
|
||||
type: "line",
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [
|
||||
{
|
||||
label: "Channel A temperature",
|
||||
backgroundColor: "red",
|
||||
borderColor: "red",
|
||||
data: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
options: options,
|
||||
});
|
||||
|
||||
const mobChartB = new Chart(mobCanvasB, {
|
||||
type: "line",
|
||||
data: {
|
||||
labels: [],
|
||||
datasets: [
|
||||
{
|
||||
label: "Channel B temperature",
|
||||
backgroundColor: "blue",
|
||||
borderColor: "blue",
|
||||
data: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
options: options,
|
||||
});
|
||||
|
||||
var gateway = `ws://${window.location.hostname}/ws`;
|
||||
var websocket;
|
||||
// Init web socket when the page loads
|
||||
|
@ -152,6 +126,22 @@ function onload(event) {
|
|||
function getReadings() {
|
||||
websocket.send("getReadings");
|
||||
}
|
||||
function setUpdateInterval() {
|
||||
let updateInt = document.getElementById("upd").value;
|
||||
websocket.send("u" + updateInt);
|
||||
location.reload();
|
||||
}
|
||||
|
||||
function getUpdateInterval() {
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function () {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("upd").value = this.responseText;
|
||||
}
|
||||
};
|
||||
xhttp.open("GET", "/int", true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function initWebSocket() {
|
||||
console.log("Trying to open a WebSocket connection...");
|
||||
|
@ -187,30 +177,19 @@ function removeFirstData(chart) {
|
|||
});
|
||||
}
|
||||
|
||||
function changeUpdateInterval() {
|
||||
const updateSelect = document.getElementById("updateInterval");
|
||||
let updateInt = updateSelect.options[updateSelect.selectedIndex].text;
|
||||
websocket.send("u" + updateInt);
|
||||
location.reload();
|
||||
}
|
||||
|
||||
// Function that receives the message from the ESP32 with the readings
|
||||
function onMessage(event) {
|
||||
console.log(event.data);
|
||||
var data = JSON.parse(event.data);
|
||||
var today = new Date();
|
||||
var date =
|
||||
today.getFullYear() + "-" + (today.getMonth() + 1) + "-" + today.getDate();
|
||||
var time =
|
||||
today.getHours() + ":" + today.getMinutes() + ":" + today.getSeconds();
|
||||
var dateTime = date + " " + time;
|
||||
document.getElementById("time").innerHTML = dateTime;
|
||||
if (chartA.data.labels.length > maxVals) {
|
||||
removeFirstData(chartA);
|
||||
}
|
||||
if (chartB.data.labels.length > maxVals) {
|
||||
removeFirstData(chartB);
|
||||
//console.log(event.data);
|
||||
data = JSON.parse(event.data);
|
||||
let timestamp = new Date();
|
||||
document.getElementById("time").innerHTML = timestamp.getTime();
|
||||
data["time"] = timestamp.getTime();
|
||||
if (record == 1) {
|
||||
csvData.push(createCSV(data));
|
||||
}
|
||||
}
|
||||
|
||||
setInterval(function () {
|
||||
if (isNaN(data["tempA"])) {
|
||||
document.getElementById("error-tempA").innerHTML =
|
||||
"<h3>" + data["tempA"] + "</h3>";
|
||||
|
@ -223,8 +202,69 @@ function onMessage(event) {
|
|||
} else {
|
||||
document.getElementById("error-tempB").innerText = "";
|
||||
}
|
||||
addData(chartA, data["time"] / 1000, data["tempA"]);
|
||||
addData(chartB, data["time"] / 1000, data["tempB"]);
|
||||
addData(mobChartA, data["time"] / 1000, data["tempA"]);
|
||||
addData(mobChartB, data["time"] / 1000, data["tempB"]);
|
||||
addData(chartA, data["time"], data["tempA"]);
|
||||
addData(chartB, data["time"], data["tempB"]);
|
||||
}, chartUpdateInt);
|
||||
|
||||
function escapeValue(value) {
|
||||
var result = "";
|
||||
var escape = false;
|
||||
|
||||
for (var i = 0; i < value.length; ++i) {
|
||||
var entry = value[i];
|
||||
|
||||
result += entry;
|
||||
|
||||
switch (entry) {
|
||||
case '"':
|
||||
result += '"';
|
||||
case ",":
|
||||
escape = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (escape) return '"' + result + '"';
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function createCSV(object) {
|
||||
var body = "";
|
||||
|
||||
for (var column in object) {
|
||||
if (object.hasOwnProperty(column)) {
|
||||
if (body) body += ",";
|
||||
|
||||
var value = object[column];
|
||||
|
||||
if (value == null) continue;
|
||||
|
||||
body += escapeValue(value.toString());
|
||||
}
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
function startRecording() {
|
||||
date = new Date();
|
||||
let filedate = date.toISOString().slice(0, -5).replaceAll(":", "");
|
||||
filename = "therminator-" + filedate + ".csv";
|
||||
record = 1;
|
||||
document.getElementById("startRec").disabled = true;
|
||||
document.getElementById("stopRec").disabled = false;
|
||||
}
|
||||
function stopRecording() {
|
||||
record = 0;
|
||||
let csvFile = csvData.join("\n");
|
||||
const blob = new Blob([csvFile], { type: "text/csv;charset=utf-8," });
|
||||
const objUrl = URL.createObjectURL(blob);
|
||||
const link = document.createElement("a");
|
||||
link.setAttribute("href", objUrl);
|
||||
link.setAttribute("download", filename);
|
||||
document.querySelector("body").append(link);
|
||||
link.click();
|
||||
csvData.length = 1;
|
||||
document.getElementById("startRec").disabled = false;
|
||||
document.getElementById("stopRec").disabled = true;
|
||||
}
|
||||
|
|
12
src/main.cpp
12
src/main.cpp
|
@ -8,9 +8,12 @@
|
|||
#include <SPI.h>
|
||||
#include <pinout.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#define CS_A D2
|
||||
#define CS_B D3
|
||||
|
||||
|
||||
Adafruit_MAX31855 thermocoupleA(CS_A);
|
||||
Adafruit_MAX31855 thermocoupleB(CS_B);
|
||||
|
||||
|
@ -39,9 +42,9 @@ String checkSensor(Adafruit_MAX31855 &sensor) {
|
|||
return String(sensor.readCelsius());
|
||||
}
|
||||
String getSensorReadings() {
|
||||
readings["time"] = String(lastTime);
|
||||
readings["tempA"] = checkSensor(thermocoupleA);
|
||||
readings["tempB"] = checkSensor(thermocoupleB);
|
||||
readings["time"] = String(lastTime);
|
||||
String jsonString = JSON.stringify(readings);
|
||||
return jsonString;
|
||||
}
|
||||
|
@ -59,7 +62,7 @@ void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
|
|||
if (strcmp((char *)data, "getReadings") == 0) {
|
||||
// if it is, send current sensor readings
|
||||
String sensorReadings = getSensorReadings();
|
||||
Serial.print(sensorReadings);
|
||||
Serial.printf("%s\n", sensorReadings.c_str());
|
||||
notifyClients(sensorReadings);
|
||||
}
|
||||
if (message.startsWith("u")) {
|
||||
|
@ -126,6 +129,10 @@ void setup() {
|
|||
request->send(404, "text/plain", "404 Not Found");
|
||||
});
|
||||
|
||||
server.on("/int", HTTP_GET, [](AsyncWebServerRequest *request) {
|
||||
request->send_P(200, "text/plain", String(timerDelay).c_str());
|
||||
});
|
||||
|
||||
server.serveStatic("/", LittleFS, "/");
|
||||
server.begin();
|
||||
Serial.printf("webserver init\n");
|
||||
|
@ -136,7 +143,6 @@ void loop() {
|
|||
String sensorReadings = getSensorReadings();
|
||||
Serial.println(sensorReadings);
|
||||
notifyClients(sensorReadings);
|
||||
|
||||
lastTime = millis();
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue