Initial commit: Auto-Charger Logging Web-App
MQTT-Collector (Python/paho-mqtt) speichert abgeschlossene go-e Wallbox-Ladungen in SQLite; Next.js-Web-App zeigt sie als Tabelle mit Energie-Summen (Monat/Jahr/gesamt) im werte-next-Design. Zwei Docker-Container mit gemeinsamem DB-Volume. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
import Database from "better-sqlite3";
|
||||
|
||||
const DB_PATH = process.env.DB_PATH || "/data/charges.db";
|
||||
|
||||
export interface Charge {
|
||||
id: number;
|
||||
start_time: string;
|
||||
end_time: string;
|
||||
duration_s: number;
|
||||
energy_wh: number;
|
||||
}
|
||||
|
||||
export interface Totals {
|
||||
month_wh: number;
|
||||
year_wh: number;
|
||||
total_wh: number;
|
||||
install_date: string | null;
|
||||
}
|
||||
|
||||
let db: Database.Database | null = null;
|
||||
|
||||
/**
|
||||
* Öffnet die DB read-only. Gibt null zurück, falls die Datei noch nicht
|
||||
* existiert (Collector legt sie beim ersten Start an) oder noch kein Schema
|
||||
* vorhanden ist — die Seite bleibt dann leer statt zu crashen.
|
||||
*/
|
||||
function getDb(): Database.Database | null {
|
||||
if (db) return db;
|
||||
try {
|
||||
const conn = new Database(DB_PATH, { readonly: true, fileMustExist: true });
|
||||
const hasTable = conn
|
||||
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name='charges'")
|
||||
.get();
|
||||
if (!hasTable) {
|
||||
conn.close();
|
||||
return null;
|
||||
}
|
||||
db = conn;
|
||||
return db;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function getCharges(): Charge[] {
|
||||
const conn = getDb();
|
||||
if (!conn) return [];
|
||||
return conn
|
||||
.prepare(
|
||||
`SELECT id, start_time, end_time, duration_s, energy_wh
|
||||
FROM charges ORDER BY start_time DESC`,
|
||||
)
|
||||
.all() as Charge[];
|
||||
}
|
||||
|
||||
export function getTotals(): Totals {
|
||||
const conn = getDb();
|
||||
if (!conn) {
|
||||
return { month_wh: 0, year_wh: 0, total_wh: 0, install_date: null };
|
||||
}
|
||||
const month = conn
|
||||
.prepare(
|
||||
`SELECT COALESCE(SUM(energy_wh), 0) AS s FROM charges
|
||||
WHERE strftime('%Y-%m', start_time) = strftime('%Y-%m', 'now', 'localtime')`,
|
||||
)
|
||||
.get() as { s: number };
|
||||
const year = conn
|
||||
.prepare(
|
||||
`SELECT COALESCE(SUM(energy_wh), 0) AS s FROM charges
|
||||
WHERE strftime('%Y', start_time) = strftime('%Y', 'now', 'localtime')`,
|
||||
)
|
||||
.get() as { s: number };
|
||||
const total = conn
|
||||
.prepare(`SELECT COALESCE(SUM(energy_wh), 0) AS s FROM charges`)
|
||||
.get() as { s: number };
|
||||
const install = conn
|
||||
.prepare(`SELECT value FROM meta WHERE key = 'install_date'`)
|
||||
.get() as { value: string } | undefined;
|
||||
|
||||
return {
|
||||
month_wh: month.s,
|
||||
year_wh: year.s,
|
||||
total_wh: total.s,
|
||||
install_date: install?.value ?? null,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user