First commit
This commit is contained in:
197
server.js
Normal file
197
server.js
Normal file
@@ -0,0 +1,197 @@
|
||||
import 'dotenv/config';
|
||||
import express from 'express';
|
||||
import sqlite3Pkg from 'sqlite3';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
const sqlite3 = sqlite3Pkg.verbose();
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const app = express();
|
||||
|
||||
// Configuration
|
||||
const DB_FILE = process.env.DB_FILE || 'wetterdaten.db';
|
||||
const HTTP_PORT = parseInt(process.env.HTTP_PORT || '5003', 10);
|
||||
|
||||
// View engine setup
|
||||
app.set('views', path.join(__dirname, 'views'));
|
||||
app.set('view engine', 'pug');
|
||||
|
||||
// Middleware
|
||||
app.use(express.json());
|
||||
app.use('/static', express.static(path.join(__dirname, 'static')));
|
||||
|
||||
// Database handling class
|
||||
class WetterDB {
|
||||
constructor(dbFile) {
|
||||
this.dbFile = dbFile;
|
||||
this.initDb();
|
||||
}
|
||||
|
||||
initDb() {
|
||||
const db = new sqlite3.Database(this.dbFile);
|
||||
db.serialize(() => {
|
||||
db.run(`
|
||||
CREATE TABLE IF NOT EXISTS wetterdaten (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
dateTime INTEGER NOT NULL,
|
||||
barometer REAL,
|
||||
outTemp REAL,
|
||||
outHumidity INTEGER,
|
||||
windSpeed REAL,
|
||||
windDir REAL,
|
||||
windGust REAL,
|
||||
rainRate REAL,
|
||||
rain REAL
|
||||
)
|
||||
`);
|
||||
db.run(`
|
||||
CREATE INDEX IF NOT EXISTS idx_dateTime ON wetterdaten(dateTime)
|
||||
`);
|
||||
});
|
||||
db.close();
|
||||
}
|
||||
|
||||
saveData(data) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const db = new sqlite3.Database(this.dbFile);
|
||||
const sql = `
|
||||
INSERT INTO wetterdaten
|
||||
(dateTime, barometer, outTemp, outHumidity, windSpeed, windDir, windGust, rainRate, rain)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
`;
|
||||
const params = [
|
||||
data.dateTime,
|
||||
data.barometer,
|
||||
data.outTemp,
|
||||
data.outHumidity,
|
||||
data.windSpeed,
|
||||
data.windDir,
|
||||
data.windGust,
|
||||
data.rainRate,
|
||||
data.rain
|
||||
];
|
||||
|
||||
db.run(sql, params, function(err) {
|
||||
db.close();
|
||||
if (err) {
|
||||
console.error("Error saving data:", err);
|
||||
reject(err);
|
||||
} else {
|
||||
console.log(`Daten gespeichert: ${data.dateTime}`);
|
||||
resolve(this.lastID);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getData(hours = 24) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const db = new sqlite3.Database(this.dbFile);
|
||||
|
||||
// Calculate timestamp threshold (current time - hours) in seconds (Unix Timestamp)
|
||||
const timeThreshold = Math.floor((Date.now() - hours * 60 * 60 * 1000) / 1000);
|
||||
|
||||
const sql = `
|
||||
SELECT * FROM wetterdaten
|
||||
WHERE dateTime >= ?
|
||||
ORDER BY dateTime ASC
|
||||
`;
|
||||
|
||||
db.all(sql, [timeThreshold], (err, rows) => {
|
||||
db.close();
|
||||
if (err) reject(err);
|
||||
else resolve(rows);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getHourlyRain(hours = 24) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const db = new sqlite3.Database(this.dbFile);
|
||||
|
||||
// Calculate timestamp threshold (current time - hours) in seconds (Unix Timestamp)
|
||||
const timeThreshold = Math.floor((Date.now() - hours * 60 * 60 * 1000) / 1000);
|
||||
|
||||
const sql = `
|
||||
SELECT
|
||||
strftime('%Y-%m-%d %H:00:00', datetime(dateTime, 'unixepoch', 'localtime')) as hour,
|
||||
SUM(rainRate) as total_rain
|
||||
FROM wetterdaten
|
||||
WHERE dateTime >= ?
|
||||
GROUP BY hour
|
||||
ORDER BY hour ASC
|
||||
`;
|
||||
|
||||
db.all(sql, [timeThreshold], (err, rows) => {
|
||||
db.close();
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
const result = rows.map(row => ({
|
||||
hour: row.hour,
|
||||
rain: row.total_rain || 0
|
||||
}));
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Global DB instance
|
||||
const db = new WetterDB(DB_FILE);
|
||||
|
||||
// Routes
|
||||
app.get('/', (req, res) => {
|
||||
res.render('index');
|
||||
});
|
||||
|
||||
app.post('/api/data/upload', async (req, res) => {
|
||||
try {
|
||||
const data = req.body;
|
||||
|
||||
if (!data || Object.keys(data).length === 0) {
|
||||
return res.status(400).json({ error: 'Keine Daten empfangen' });
|
||||
}
|
||||
|
||||
await db.saveData(data);
|
||||
|
||||
res.status(200).json({
|
||||
status: 'success',
|
||||
message: 'Daten empfangen und gespeichert'
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(`Fehler beim Verarbeiten der POST-Anfrage: ${e}`);
|
||||
res.status(400).json({ error: e.toString() });
|
||||
}
|
||||
});
|
||||
|
||||
app.get('/api/data/:period', async (req, res) => {
|
||||
const period = req.params.period;
|
||||
const hours = period === 'day' ? 24 : 168; // 168h = 1 week
|
||||
|
||||
try {
|
||||
const [data, rainData] = await Promise.all([
|
||||
db.getData(hours),
|
||||
db.getHourlyRain(hours)
|
||||
]);
|
||||
|
||||
res.json({
|
||||
data: data,
|
||||
rain_hourly: rainData
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
res.status(500).json({ error: 'Internal Server Error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Start server
|
||||
app.listen(HTTP_PORT, '0.0.0.0', () => {
|
||||
console.log("Wetterstation wird gestartet...");
|
||||
console.log(`\nWeb-Interface verfügbar unter: http://localhost:${HTTP_PORT}`);
|
||||
console.log(`HTTP-POST Endpoint: http://localhost:${HTTP_PORT}/api/data/upload`);
|
||||
console.log("Drücke CTRL+C zum Beenden\n");
|
||||
});
|
||||
Reference in New Issue
Block a user