GruppeC/frontend/app.js

114 lines
4.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

// Fragt alle paar Sekunden die Messwerte vom Backend ab und zeigt sie an.
const API_URL = "/api/messwerte";
const ABFRAGE_INTERVALL_MS = 2000;
const VERALTET_NACH_MS = 10000;
const CO2_GRENZWERT_PPM = 1000; // Hard-Constraint laut Konzept (Standard 1000 ppm)
const el = (id) => document.getElementById(id);
function formatiere(wert, stellen) {
return wert === null || wert === undefined ? "–" : wert.toFixed(stellen);
}
function zeigeStatus(text, klasse) {
const status = el("status");
status.textContent = text;
status.className = "status " + klasse;
}
function zeigeWerte(aktuell, veraltet) {
el("wert-temperatur").textContent = formatiere(aktuell && aktuell.temperatur, 1);
el("wert-luftfeuchte").textContent = formatiere(aktuell && aktuell.luftfeuchte, 1);
el("wert-eco2").textContent = formatiere(aktuell && aktuell.eco2, 0);
el("wert-tvoc").textContent = formatiere(aktuell && aktuell.tvoc, 0);
for (const kachel of document.querySelectorAll(".kachel")) {
kachel.classList.toggle("veraltet", veraltet);
}
const co2Alarm = !veraltet && aktuell && aktuell.eco2 !== null && aktuell.eco2 >= CO2_GRENZWERT_PPM;
el("kachel-eco2").classList.toggle("alarm", Boolean(co2Alarm));
el("hinweis-eco2").hidden = !co2Alarm;
el("hinweis-eco2").textContent = `Grenzwert ${CO2_GRENZWERT_PPM} ppm erreicht – bitte lüften`;
}
function zeichneDiagramm(verlauf) {
const canvas = el("diagramm");
const ctx = canvas.getContext("2d");
const stil = getComputedStyle(document.documentElement);
const farbe = (name) => stil.getPropertyValue(name).trim();
const b = canvas.width;
const h = canvas.height;
ctx.clearRect(0, 0, b, h);
if (verlauf.length < 2) return;
// Temperatur (links) und CO2 (rechts) haben getrennte Skalen
const reihen = [
{ feld: "temperatur", farbe: farbe("--linie-temp"), einheit: "°C" },
{ feld: "eco2", farbe: farbe("--linie-co2"), einheit: "ppm" },
];
const rand = 8;
const text = farbe("--text-leise");
ctx.font = "12px system-ui, sans-serif";
reihen.forEach((reihe, index) => {
const werte = verlauf.map((e) => e[reihe.feld]);
const vorhanden = werte.filter((w) => w !== null);
if (vorhanden.length === 0) return;
let min = Math.min(...vorhanden);
let max = Math.max(...vorhanden);
if (max - min < 1) { min -= 1; max += 1; }
ctx.strokeStyle = reihe.farbe;
ctx.lineWidth = 2;
ctx.beginPath();
let gestartet = false;
werte.forEach((w, i) => {
if (w === null) { gestartet = false; return; }
const x = rand + (i / (werte.length - 1)) * (b - 2 * rand);
const y = h - rand - 16 - ((w - min) / (max - min)) * (h - 2 * rand - 32);
if (gestartet) ctx.lineTo(x, y); else ctx.moveTo(x, y);
gestartet = true;
});
ctx.stroke();
ctx.fillStyle = reihe.farbe;
ctx.textAlign = index === 0 ? "left" : "right";
ctx.fillText(`${reihe.feld === "eco2" ? "CO₂" : "Temperatur"} ${min.toFixed(0)}–${max.toFixed(0)} ${reihe.einheit}`,
index === 0 ? rand : b - rand, 14);
});
ctx.fillStyle = text;
ctx.textAlign = "center";
ctx.fillText(`${verlauf.length} Messungen`, b / 2, h - 4);
}
async function aktualisiere() {
try {
const antwort = await fetch(API_URL, { cache: "no-store" });
if (!antwort.ok) throw new Error("HTTP " + antwort.status);
const { aktuell, verlauf } = await antwort.json();
if (!aktuell) {
zeigeWerte(null, true);
zeigeStatus("Noch keine Daten vom Sensor empfangen", "status-warte");
return;
}
const alter = Date.now() - new Date(aktuell.zeit).getTime();
const veraltet = alter > VERALTET_NACH_MS;
zeigeWerte(aktuell, veraltet);
zeichneDiagramm(verlauf);
const uhrzeit = new Date(aktuell.zeit).toLocaleTimeString("de-DE");
zeigeStatus(
veraltet ? `Daten veraltet – letzte Messung um ${uhrzeit}` : `Live – letzte Messung um ${uhrzeit}`,
veraltet ? "status-veraltet" : "status-ok"
);
} catch (fehler) {
zeigeWerte(null, true);
zeigeStatus("Server nicht erreichbar", "status-veraltet");
}
}
aktualisiere();
setInterval(aktualisiere, ABFRAGE_INTERVALL_MS);