Add sensor fault simulation and health display

This commit is contained in:
root
2026-06-03 00:22:57 -06:00
parent fbac6063b9
commit cdff42ddd4
4 changed files with 134 additions and 31 deletions
+72 -23
View File
@@ -35,14 +35,14 @@
</div>
<div class="grid">
<div class="card"><h2>Fridge A</h2><p><span id="dashFridge1">--</span>°F</p></div>
<div class="card"><h2>Fridge B</h2><p><span id="dashFridge2">--</span>°F</p></div>
<div class="card kid-card">
<div class="card" id="cardFridge1"><h2>Fridge A</h2><p><span id="dashFridge1">--</span></p><small id="healthFridge1">OK</small></div>
<div class="card" id="cardFridge2"><h2>Fridge B</h2><p><span id="dashFridge2">--</span></p><small id="healthFridge2">OK</small></div>
<div class="card kid-card" id="cardRear">
<h2>👧 Kid Area</h2>
<p><span id="dashRear">--</span>°F</p>
<p><span id="dashRear">--</span></p>
<small id="kidStatus">Normal</small>
</div>
<div class="card"><h2>Outside</h2><p><span id="dashOutside">--</span>°F</p></div>
<div class="card" id="cardOutside"><h2>Outside</h2><p><span id="dashOutside">--</span></p><small id="healthOutside">OK</small></div>
</div>
<div class="relay-row">
@@ -66,10 +66,10 @@
<section id="temps" class="screen">
<h2>Temperatures</h2>
<div class="grid">
<div class="card"><h2>Fridge Zone 1</h2><p><span id="tempFridge1">--</span>°F</p></div>
<div class="card"><h2>Fridge Zone 2</h2><p><span id="tempFridge2">--</span>°F</p></div>
<div class="card"><h2>Rear Seat</h2><p><span id="tempRear">--</span>°F</p></div>
<div class="card"><h2>Outside</h2><p><span id="tempOutside">--</span>°F</p></div>
<div class="card"><h2>Fridge Zone 1</h2><p><span id="tempFridge1">--</span></p></div>
<div class="card"><h2>Fridge Zone 2</h2><p><span id="tempFridge2">--</span></p></div>
<div class="card"><h2>Rear Seat</h2><p><span id="tempRear">--</span></p></div>
<div class="card"><h2>Outside</h2><p><span id="tempOutside">--</span></p></div>
</div>
</section>
@@ -90,6 +90,14 @@
<button onclick="enableWifi()">Enable WiFi 10 min</button>
<button onclick="toggleIgnition()">Toggle Ignition</button>
<h2>Sensor Fault Simulation</h2>
<div class="settings-list">
<button onclick="toggleSensorFault('fridge_zone_1')">Toggle Fridge Zone 1 Fault</button>
<button onclick="toggleSensorFault('fridge_zone_2')">Toggle Fridge Zone 2 Fault</button>
<button onclick="toggleSensorFault('rear_seat')">Toggle Rear Seat Fault</button>
<button onclick="toggleSensorFault('outside')">Toggle Outside Fault</button>
</div>
<h2>Alarm Settings</h2>
<div class="settings-list">
<label>
@@ -155,25 +163,50 @@ function onOff(value) {
return value ? 'ON' : 'OFF';
}
function tempText(value) {
return value === null || value === undefined ? 'FAULT' : `${value}°F`;
}
function setSensorCard(cardId, healthId, healthy) {
const card = document.getElementById(cardId);
const health = document.getElementById(healthId);
if (!card || !health) return;
if (healthy) {
card.classList.remove('sensor-fault');
health.textContent = 'OK';
} else {
card.classList.add('sensor-fault');
health.textContent = 'SENSOR FAULT';
}
}
function checkAlarms(data) {
const alarms = [];
const warnings = [];
if (data.temps.rear_seat >= alarmConfig.rear_seat_critical) {
for (const [name, healthy] of Object.entries(data.sensor_health)) {
if (!healthy) {
warnings.push(`Sensor fault: ${name.replaceAll('_', ' ')}`);
}
}
if (data.sensor_health.rear_seat && data.temps.rear_seat >= alarmConfig.rear_seat_critical) {
alarms.push({
key: 'rear_seat_critical',
title: 'REAR SEAT TEMP CRITICAL',
message: `${data.temps.rear_seat}°F detected near car seat area`
});
} else if (data.temps.rear_seat >= alarmConfig.rear_seat_warning) {
} else if (data.sensor_health.rear_seat && data.temps.rear_seat >= alarmConfig.rear_seat_warning) {
warnings.push(`Rear seat temp high: ${data.temps.rear_seat}°F`);
}
if (data.temps.fridge_zone_1 >= alarmConfig.fridge_zone_1_warm) {
if (data.sensor_health.fridge_zone_1 && data.temps.fridge_zone_1 >= alarmConfig.fridge_zone_1_warm) {
warnings.push(`Fridge Zone 1 warm: ${data.temps.fridge_zone_1}°F`);
}
if (data.temps.fridge_zone_2 >= alarmConfig.fridge_zone_2_warm) {
if (data.sensor_health.fridge_zone_2 && data.temps.fridge_zone_2 >= alarmConfig.fridge_zone_2_warm) {
warnings.push(`Fridge Zone 2 warm: ${data.temps.fridge_zone_2}°F`);
}
@@ -260,19 +293,24 @@ async function loadStatus() {
document.getElementById('dashSoc').textContent = data.battery.soc;
document.getElementById('dashRuntime').textContent = data.battery.runtime_hours;
document.getElementById('dashFridge1').textContent = data.temps.fridge_zone_1;
document.getElementById('dashFridge2').textContent = data.temps.fridge_zone_2;
document.getElementById('dashRear').textContent = data.temps.rear_seat;
document.getElementById('dashFridge1').textContent = tempText(data.temps.fridge_zone_1);
document.getElementById('dashFridge2').textContent = tempText(data.temps.fridge_zone_2);
document.getElementById('dashRear').textContent = tempText(data.temps.rear_seat);
setSensorCard('cardFridge1', 'healthFridge1', data.sensor_health.fridge_zone_1);
setSensorCard('cardFridge2', 'healthFridge2', data.sensor_health.fridge_zone_2);
setSensorCard('cardRear', 'kidStatus', data.sensor_health.rear_seat);
setSensorCard('cardOutside', 'healthOutside', data.sensor_health.outside);
const kidStatus = document.getElementById('kidStatus');
if (data.temps.rear_seat >= alarmConfig.rear_seat_critical) {
if (data.sensor_health.rear_seat && data.temps.rear_seat >= alarmConfig.rear_seat_critical) {
kidStatus.textContent = 'CRITICAL';
} else if (data.temps.rear_seat >= alarmConfig.rear_seat_warning) {
} else if (data.sensor_health.rear_seat && data.temps.rear_seat >= alarmConfig.rear_seat_warning) {
kidStatus.textContent = 'Warning';
} else {
kidStatus.textContent = 'Normal';
}
document.getElementById('dashOutside').textContent = data.temps.outside;
document.getElementById('dashOutside').textContent = tempText(data.temps.outside);
document.getElementById('dashStarlink').textContent = `Starlink: ${onOff(data.relays.starlink)}`;
document.getElementById('dashFridgeRelay').textContent = `Fridge: ${onOff(data.relays.fridge)}`;
@@ -283,10 +321,10 @@ async function loadStatus() {
document.getElementById('batRuntime').textContent = data.battery.runtime_hours;
document.getElementById('batTemp').textContent = data.battery.temperature_f;
document.getElementById('tempFridge1').textContent = data.temps.fridge_zone_1;
document.getElementById('tempFridge2').textContent = data.temps.fridge_zone_2;
document.getElementById('tempRear').textContent = data.temps.rear_seat;
document.getElementById('tempOutside').textContent = data.temps.outside;
document.getElementById('tempFridge1').textContent = tempText(data.temps.fridge_zone_1);
document.getElementById('tempFridge2').textContent = tempText(data.temps.fridge_zone_2);
document.getElementById('tempRear').textContent = tempText(data.temps.rear_seat);
document.getElementById('tempOutside').textContent = tempText(data.temps.outside);
document.getElementById('starlinkBtn').textContent = `Starlink: ${onOff(data.relays.starlink)}`;
document.getElementById('fridgeBtn').textContent = `Fridge: ${onOff(data.relays.fridge)}`;
@@ -347,6 +385,17 @@ async function toggleIgnition() {
loadStatus();
}
async function toggleSensorFault(name) {
await fetch(`/sensor/${name}/fault`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({})
});
acknowledgedAlarms.clear();
loadStatus();
}
async function enableWifi() {
await fetch('/network/wifi', {
method: 'POST',