First commit

This commit is contained in:
2026-04-03 22:24:22 +02:00
commit d1cfee0dea
13 changed files with 1464 additions and 0 deletions

98
wetter.js Normal file
View File

@@ -0,0 +1,98 @@
/**
* wetter.js Hauptprogramm
*
* Ablauf beim Start:
* 1. SQLite-Datenbank öffnen (wetter.db)
* 2. Letzten archivierten Zeitstempel lesen → Archiv nachladen
* 3. Archivdaten in DB schreiben
* 4. LOOP-Schleife starten: alle 30 s Echtzeit-Daten holen & in DB schreiben
*/
import "dotenv/config";
import path from "path";
import { fileURLToPath } from "url";
import { openDb, getLatestTs, insertRecords, insertRecord } from "./db.js";
import { readArchiveSince, connectStation, fetchLoopData } from "./davis.js";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
const DB_PATH = process.env.DB_PATH ?? path.join(__dirname, "wetter.db");
const LOOP_INTERVAL_MS = Number(process.env.LOOP_INTERVAL_MS ?? 30_000);
// ── Hilfsfunktionen ────────────────────────────────────────────────────────
const fmt24h = (d) => d.toLocaleTimeString("de-DE", { hour12: false });
const fmtDateTime = (d) => d.toLocaleString("de-DE", { hour12: false });
function log(msg) { console.log (`[${fmt24h(new Date())}] ${msg}`); }
function warn(msg) { console.warn(`[${fmt24h(new Date())}] WARN ${msg}`); }
function err(msg) { console.error(`[${fmt24h(new Date())}] ERROR ${msg}`); }
// ── Archiv nachladen ───────────────────────────────────────────────────────
async function catchUpArchive(db) {
const latestTs = getLatestTs(db);
const since = latestTs
? new Date(latestTs * 1000) // ab letztem DB-Eintrag
: new Date(Date.now() - 24 * 60 * 60 * 1000); // Fallback: letzte 24 h
log(`Lade Archiv ab ${fmtDateTime(since)} ...`);
let lastPct = -1;
const records = await readArchiveSince(since, (cur, total) => {
const pct = Math.floor(cur / total * 100);
if (pct !== lastPct) {
process.stdout.write(`\r Archiv: ${pct}% (Seite ${cur}/${total})`);
lastPct = pct;
}
});
process.stdout.write("\r\x1b[K"); // Fortschrittszeile löschen
if (records.length === 0) {
log("Archiv: keine neuen Datensätze.");
return;
}
const inserted = insertRecords(db, records, "archive");
log(`Archiv: ${inserted} neue Datensätze gespeichert (${records.length} empfangen).`);
}
// ── LOOP-Schleife ──────────────────────────────────────────────────────────
async function runLoop(db) {
let station = null;
async function connect() {
station = await connectStation();
log("Verbunden mit Wetterstation.");
}
async function tick() {
try {
const data = await fetchLoopData(station);
insertRecord(db, data, "loop");
log(
`Außen: ${data.tempOut?.toFixed(1)}°C ` +
`Feuchte: ${data.humOut}% ` +
`Wind: ${data.windAvg} km/h ` +
`Druck: ${data.pressure} hPa`
);
} catch (e) {
warn("LOOP-Fehler: " + e.message + " Verbindung wird neu aufgebaut.");
try { await station?.disconnect(); } catch {}
station = null;
try { await connect(); } catch (ce) { err("Reconnect fehlgeschlagen: " + ce.message); }
}
setTimeout(tick, LOOP_INTERVAL_MS);
}
await connect();
tick();
}
// ── Hauptprogramm ──────────────────────────────────────────────────────────
const db = openDb(DB_PATH);
log(`Datenbank: ${DB_PATH}`);
await catchUpArchive(db);
await runLoop(db);