let isESP32; fetch("/isESP32") .then((res) => res.text()) .then((textResponse) => { isESP32 = textResponse; if (isESP32 == 0) { document.querySelector("#chanGH").style.display = "none"; } }); fetch("/int") .then((res) => res.text()) .then((textResponse) => { document.querySelector("#updInt").innerText = textResponse; }); let lightbox = document.querySelector("#lightbox"); const canvasA = document.querySelector("#chartA"); const canvasB = document.querySelector("#chartB"); const canvasC = document.querySelector("#chartC"); const canvasD = document.querySelector("#chartD"); const canvasE = document.querySelector("#chartE"); const canvasF = document.querySelector("#chartF"); const canvasG = document.querySelector("#chartG"); const canvasH = document.querySelector("#chartH"); const chartUpdateInt = document.querySelector("#chartUpd").value; document.querySelector("#stopRec").disabled = true; let data; let record = 0; let filename; let csvData = []; let labelA, labelB, labelC, labelD, labelE, labelF, labelG, labelH; const options = { animation: false, elements: { point: { pointStyle: false, }, }, responsive: true, plugins: { legend: { labels: { color: "rgba(250, 250, 250, 1)", }, }, }, scales: { y: { title: { display: true, text: "Temperature (°C)", color: "rgb(250, 250, 250)", }, grid: { color: "rgba(250, 250, 250, 0.5)", }, ticks: { color: "rgba(250, 250, 250, 0.5)", }, suggestedMin: 0, suggestedMax: 50, }, x: { title: { display: true, text: "Time (s)", color: "rgb(250, 250, 250)", }, grid: { color: "rgba(250, 250, 250, 0.5)", }, ticks: { color: "rgba(250, 250, 250, 0.5)", }, }, }, }; document.querySelector("#cupdInt").innerText = chartUpdateInt; document.querySelector("#recInfo").style.display = "none"; const chartA = new Chart(canvasA, { type: "line", data: { labels: [], datasets: [ { label: "Channel A temperature", backgroundColor: "red", borderColor: "red", data: [], }, ], }, options: options, }); const chartB = new Chart(canvasB, { type: "line", data: { labels: [], datasets: [ { label: "Channel B temperature", backgroundColor: "blue", borderColor: "blue", data: [], }, ], }, options: options, }); const chartC = new Chart(canvasC, { type: "line", data: { labels: [], datasets: [ { label: "Channel C temperature", backgroundColor: "red", borderColor: "red", data: [], }, ], }, options: options, }); const chartD = new Chart(canvasD, { type: "line", data: { labels: [], datasets: [ { label: "Channel D temperature", backgroundColor: "blue", borderColor: "blue", data: [], }, ], }, options: options, }); const chartE = new Chart(canvasE, { type: "line", data: { labels: [], datasets: [ { label: "Channel E temperature", backgroundColor: "red", borderColor: "red", data: [], }, ], }, options: options, }); const chartF = new Chart(canvasF, { type: "line", data: { labels: [], datasets: [ { label: "Channel F temperature", backgroundColor: "blue", borderColor: "blue", data: [], }, ], }, options: options, }); const chartG = new Chart(canvasG, { type: "line", data: { labels: [], datasets: [ { label: "Channel G temperature", backgroundColor: "red", borderColor: "red", data: [], }, ], }, options: options, }); const chartH = new Chart(canvasH, { type: "line", data: { labels: [], datasets: [ { label: "Channel H temperature", backgroundColor: "blue", borderColor: "blue", data: [], }, ], }, options: options, }); var gateway = `ws://${window.location.hostname}/ws`; var websocket; // Init web socket when the page loads window.addEventListener("load", onload); function onload(event) { initWebSocket(); } function getReadings() { websocket.send("getReadings"); } function setUpdateInterval() { let updateInt = document.querySelector("#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.querySelector("#upd").value = this.responseText; } }; xhttp.open("GET", "/int", true); xhttp.send(); } function initWebSocket() { console.log("Trying to open a WebSocket connection..."); websocket = new WebSocket(gateway); websocket.onopen = onOpen; websocket.onclose = onClose; websocket.onmessage = onMessage; } // When websocket is established, call the getReadings() function function onOpen(event) { console.log("Connection opened"); getReadings(); } function onClose(event) { console.log("Connection closed"); setTimeout(initWebSocket, 2000); csvData.length = 0; } function addData(chart, label, data) { chart.data.labels.push(label); chart.data.datasets.forEach((dataset) => { dataset.data.push(data); }); chart.update(); } function removeFirstData(chart) { chart.data.labels.splice(0, 1); chart.data.datasets.forEach((dataset) => { dataset.data.shift(); }); } // Function that receives the message from the ESP32 with the readings function onMessage(event) { //console.log(event.data); data = JSON.parse(event.data); let timestamp = new Date(); document.querySelector("#time").innerHTML = timestamp.getTime(); data["time"] = timestamp.getTime(); if (record == 1) { csvData.push(createCSV(data)); } } setInterval(function () { if (isNaN(data["tempA"])) { document.querySelector("#error-tempA").innerHTML = "

" + data["tempA"] + "

"; } else { document.querySelector("#error-tempA").innerText = ""; } if (isNaN(data["tempB"])) { document.querySelector("#error-tempB").innerHTML = "

" + data["tempB"] + "

"; } else { document.querySelector("#error-tempB").innerText = ""; } if (isNaN(data["tempC"])) { document.querySelector("#error-tempC").innerHTML = "

" + data["tempC"] + "

"; } else { document.querySelector("#error-tempC").innerText = ""; } if (isNaN(data["tempD"])) { document.querySelector("#error-tempD").innerHTML = "

" + data["tempD"] + "

"; } else { document.querySelector("#error-tempD").innerText = ""; } if (isNaN(data["tempE"])) { document.querySelector("#error-tempE").innerHTML = "

" + data["tempE"] + "

"; } else { document.querySelector("#error-tempE").innerText = ""; } if (isNaN(data["tempF"])) { document.querySelector("#error-tempF").innerHTML = "

" + data["tempF"] + "

"; } else { document.querySelector("#error-tempF").innerText = ""; } if (isNaN(data["tempG"])) { document.querySelector("#error-tempG").innerHTML = "

" + data["tempG"] + "

"; } else { document.querySelector("#error-tempG").innerText = ""; } if (isNaN(data["tempH"])) { document.querySelector("#error-tempH").innerHTML = "

" + data["tempH"] + "

"; } else { document.querySelector("#error-tempH").innerText = ""; } addData(chartA, data["time"], data["tempA"]); addData(chartB, data["time"], data["tempB"]); addData(chartC, data["time"], data["tempC"]); addData(chartD, data["time"], data["tempD"]); addData(chartE, data["time"], data["tempE"]); addData(chartF, data["time"], data["tempF"]); addData(chartG, data["time"], data["tempG"]); addData(chartH, data["time"], data["tempH"]); }, 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() { let timedRec = document.querySelector("#timedRec").checked; date = new Date(); let filedate = date.toISOString().slice(0, -5).replaceAll(":", ""); filename = "therminator-" + filedate + ".csv"; document.querySelector("#filename").innerText = filename; labelA = document.querySelector("#labelA").value; labelB = document.querySelector("#labelB").value; labelC = document.querySelector("#labelC").value; labelD = document.querySelector("#labelD").value; labelE = document.querySelector("#labelE").value; labelF = document.querySelector("#labelF").value; labelG = document.querySelector("#labelG").value; labelH = document.querySelector("#labelH").value; if (isESP32 == 1) { csvData = [ 'time,"' + labelA + '","' + labelB + '","' + labelC + '","' + labelD + '","' + labelE + '","' + labelF + '","' + labelG + '","' + labelH + '"', ]; } else { csvData = [ 'time,"' + labelA + '","' + labelB + '","' + labelC + '","' + labelD + '","' + labelE + '","' + labelF + '"', ]; } record = 1; document.querySelector("#startRec").disabled = true; document.querySelector("#stopRec").disabled = false; document.querySelector("#recInfo").style.display = "inline-grid"; document.querySelector("#timedSettings").style.display = "none"; document.querySelector("#timedCheck").style.display = "none"; if (timedRec) { let timer = document.querySelector("#timer").value; if (timer == 0) { alert("Recording time must be non-zero"); return; } timer = timer * 60000; let timeleft = timer / 1000; let disp = document.querySelector("#timeLeftCtr"); document.querySelector("#timeLeft").style.display = "inherit"; startTimer(timeleft, disp); setTimeout(stopRecording, timer); } } function startTimer(duration, display) { var timer = duration, minutes, seconds; setInterval(function () { minutes = parseInt(timer / 60, 10); seconds = parseInt(timer % 60, 10); minutes = minutes < 10 ? "0" + minutes : minutes; seconds = seconds < 10 ? "0" + seconds : seconds; display.textContent = minutes + ":" + seconds; if (--timer < 0) { timer = duration; } }, 1000); } function fancyTimeFormat(e) { const h = Math.floor(e / 3600) .toString() .padStart(2, "0"), m = Math.floor((e % 3600) / 60) .toString() .padStart(2, "0"), s = Math.floor(e % 60) .toString() .padStart(2, "0"); return h + ":" + m + ":" + s; } 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 = 0; document.querySelector("#startRec").disabled = false; document.querySelector("#stopRec").disabled = true; document.querySelector("#recInfo").style.display = "none"; document.querySelector("#timedSettings").style.display = "none"; document.querySelector("#timedCheck").style.display = "inline-block"; document.querySelector("#timedRec").checked = false; document.querySelector("#timeLeft").style.display = "none"; } const beforeUnloadHandler = (event) => { // Recommended event.preventDefault(); // Included for legacy support, e.g. Chrome/Edge < 119 event.returnValue = true; }; onbeforeunload = function () { if (record) { return "You are still recording data! Are you sure you want to leave?"; } }; document.querySelector("#timedRec").onchange = function () { if (this.checked) { document.querySelector("#timedSettings").style.display = "inherit"; } else { document.querySelector("#timedSettings").style.display = "none"; } }; function showCredits() { lightbox.style.visibility = "visible"; lightbox.style.opacity = "1" } function hideCredits() { lightbox.style.visibility = "hidden"; lightbox.style.opacity = "0" }