const express = require('express'); const { MongoClient, ObjectId } = require('mongodb'); const path = require('path'); const fs = require('fs'); // Package.json laden const packageInfo = JSON.parse( fs.readFileSync(path.join(__dirname, 'package.json'), 'utf8') ); const app = express(); const PORT = 3000; // MongoDB-Verbindung const MONGO_URL = 'mongodb://nuccy:27017'; const DB_NAME = 'smarthome'; // Konfiguration für verschiedene Collections const COLLECTION_CONFIG = { 'maschinen': { verbraucherFeld: 'maschine', arbeitsFeld: 'arbeit', zeitFeld: 'datetime', faktor: 1, // Wh einheit: 'Wh', // Verbraucher-spezifische Faktoren verbraucherFaktoren: { 'spuelmaschine': 1000 // kWh -> Wh } }, 'auto': { verbraucherFeld: null, // kein Verbraucher-Feld verbraucherName: 'Auto', // fester Name arbeitsFeld: 'gesamt', zeitFeld: '_id', // Zeitstempel aus ObjectId faktor: 100, // 0.1 kWh = 100 Wh einheit: 'Wh' } }; let db; // Verbindung zur MongoDB herstellen MongoClient.connect(MONGO_URL) .then(client => { console.log('Erfolgreich mit MongoDB verbunden'); db = client.db(DB_NAME); }) .catch(error => { console.error('MongoDB Verbindungsfehler:', error); process.exit(1); }); // View-Engine konfigurieren app.set('view engine', 'pug'); app.set('views', path.join(__dirname, 'views')); // Middleware app.use(express.json()); app.use(express.static('public')); // Hauptseite rendern app.get('/', (req, res) => { res.render('index', { version: packageInfo.version, versiondate: packageInfo.versiondate }); }); // Hilfsfunktion: Zeitstempel aus Dokument extrahieren function getTimestamp(doc, zeitFeld) { if (zeitFeld === '_id') { // Zeitstempel aus ObjectId extrahieren return doc._id.getTimestamp(); } return doc[zeitFeld]; } // Hilfsfunktion: Query für Zeitbereich erstellen function createTimeQuery(start, end, zeitFeld) { if (zeitFeld === '_id') { // Bei ObjectId: IDs im Zeitbereich generieren const startId = ObjectId.createFromTime(Math.floor(start.getTime() / 1000)); const endId = ObjectId.createFromTime(Math.floor(end.getTime() / 1000)); return { _id: { $gte: startId, $lte: endId } }; } return { [zeitFeld]: { $gte: start, $lte: end } }; } // Hilfsfunktion: Daten für eine Collection abrufen async function fetchCollectionData(collectionName, start, end) { const config = COLLECTION_CONFIG[collectionName]; if (!config) { return []; } const coll = db.collection(collectionName); const timeQuery = createTimeQuery(start, end, config.zeitFeld); let verbraucherList; if (config.verbraucherFeld) { // Alle Verbraucher im Zeitraum finden verbraucherList = await coll.distinct(config.verbraucherFeld, timeQuery); } else { // Nur ein Verbraucher mit festem Namen verbraucherList = [config.verbraucherName]; } // Für jeden Verbraucher den ersten und letzten Wert im Zeitraum holen const verbrauchsData = await Promise.all( verbraucherList.map(async (verbraucher) => { let query = { ...timeQuery }; // Verbraucher-Filter hinzufügen, falls vorhanden if (config.verbraucherFeld) { query[config.verbraucherFeld] = verbraucher; } // Sortierfeld festlegen const sortFeld = config.zeitFeld; // Erster Wert im Zeitraum const ersterWert = await coll .find(query) .sort({ [sortFeld]: 1 }) .limit(1) .toArray(); // Letzter Wert im Zeitraum const letzterWert = await coll .find(query) .sort({ [sortFeld]: -1 }) .limit(1) .toArray(); // Verbraucher-spezifischen Faktor prüfen let faktor = config.faktor; if (config.verbraucherFaktoren && config.verbraucherFaktoren[verbraucher]) { faktor = config.verbraucherFaktoren[verbraucher]; } const anfangsWert = (ersterWert[0][config.arbeitsFeld] || 0) * faktor; const endWert = (letzterWert[0][config.arbeitsFeld] || 0) * faktor; const verbrauch = endWert - anfangsWert; return { verbraucher: verbraucher, collection: collectionName, anfangsWert: anfangsWert, anfangsZeit: getTimestamp(ersterWert[0], config.zeitFeld), endWert: endWert, endZeit: getTimestamp(letzterWert[0], config.zeitFeld), verbrauch: verbrauch, einheit: 'Wh' // Normalisiert auf Wh }; }) ); // Null-Werte filtern (Verbraucher ohne Daten) return verbrauchsData.filter(item => item !== null); } // API-Endpoint zum Abrufen der Verbrauchsdaten app.get('/api/verbrauch', async (req, res) => { try { const { collections, startDate, endDate } = req.query; if (!collections || !startDate || !endDate) { return res.status(400).json({ error: 'Parameter fehlen: collections, startDate, endDate erforderlich' }); } const start = new Date(startDate); const end = new Date(endDate); // Ende auf 23:59:59 setzen end.setHours(23, 59, 59, 999); // Collections-Parameter kann kommaseparierte Liste sein const collectionList = typeof collections === 'string' ? collections.split(',').map(c => c.trim()) : [collections]; // Daten für alle Collections abrufen const allResults = await Promise.all( collectionList.map(collectionName => fetchCollectionData(collectionName, start, end) ) ); // Alle Ergebnisse zusammenführen const alleVerbraucher = allResults.flat(); res.json({ zeitraum: { von: start, bis: end }, collections: collectionList, verbraucher: alleVerbraucher }); } catch (error) { console.error('Fehler beim Abrufen der Daten:', error); res.status(500).json({ error: 'Serverfehler: ' + error.message }); } }); // API-Endpoint zum Abrufen verfügbarer Collections app.get('/api/collections', async (req, res) => { try { const collections = await db.listCollections().toArray(); const collectionNames = collections.map(c => c.name); res.json({ collections: collectionNames }); } catch (error) { console.error('Fehler beim Abrufen der Collections:', error); res.status(500).json({ error: 'Serverfehler: ' + error.message }); } }); // Server starten app.listen(PORT, () => { console.log(`Server läuft auf http://localhost:${PORT}`); });