Heat-Tracker/server.js
2025-04-21 22:52:26 -04:00

85 lines
2.8 KiB
JavaScript

const express = require('express');
const sqlite3 = require('sqlite3').verbose();
const bodyParser = require('body-parser');
const path = require('path');
const app = express();
const PORT = process.env.PORT || 3000;
// Initialize SQLite database
const db = new sqlite3.Database('./readings.db');
db.serialize(() => {
db.run(`
CREATE TABLE IF NOT EXISTS readings (
id INTEGER PRIMARY KEY AUTOINCREMENT,
dockDoor INTEGER,
timestamp TEXT,
temperature REAL,
humidity REAL,
heatIndex REAL
)
`);
});
// Compute heat index (NOAA formula)
function computeHeatIndex(T, R) {
const c1 = -42.379, c2 = 2.04901523, c3 = 10.14333127;
const c4 = -0.22475541, c5 = -6.83783e-3, c6 = -5.481717e-2;
const c7 = 1.22874e-3, c8 = 8.5282e-4, c9 = -1.99e-6;
const HI = c1 + c2*T + c3*R + c4*T*R + c5*T*T + c6*R*R + c7*T*T*R + c8*T*R*R + c9*T*T*R*R;
return Math.round(HI * 100) / 100;
}
// Middleware & static
app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'public')));
// SSE clients
let clients = [];
app.get('/api/stream', (req, res) => {
res.set({ 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', Connection: 'keep-alive' });
res.flushHeaders();
clients.push(res);
req.on('close', () => { clients = clients.filter(c => c !== res); });
});
function broadcast(event, data) {
const payload = `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
clients.forEach(res => res.write(payload));
}
// APIs
app.post('/api/readings', (req, res) => {
const { dockDoor, timestamp, temperature, humidity } = req.body;
const heatIndex = computeHeatIndex(temperature, humidity);
db.run(
`INSERT INTO readings (dockDoor, timestamp, temperature, humidity, heatIndex) VALUES (?, ?, ?, ?, ?)`,
[dockDoor, timestamp, temperature, humidity, heatIndex],
function(err) {
if (err) return res.status(500).json({ error: err.message });
const reading = { id: this.lastID, dockDoor, timestamp, temperature, humidity, heatIndex };
broadcast('new-reading', reading);
res.json(reading);
}
);
});
app.get('/api/readings', (req, res) => {
db.all(`SELECT * FROM readings ORDER BY timestamp ASC`, (err, rows) => {
if (err) return res.status(500).json({ error: err.message });
res.json(rows);
});
});
app.get('/api/export', (req, res) => {
db.all(`SELECT * FROM readings ORDER BY timestamp ASC`, (err, rows) => {
if (err) return res.status(500).send(err.message);
res.setHeader('Content-disposition', 'attachment; filename=readings.csv');
res.set('Content-Type', 'text/csv');
res.write('id,dockDoor,timestamp,temperature,humidity,heatIndex\n');
rows.forEach(r => res.write(`${r.id},${r.dockDoor},${r.timestamp},${r.temperature},${r.humidity},${r.heatIndex}\n`));
res.end();
});
});
app.listen(PORT, () => console.log(`Server running on http://localhost:${PORT}`));