225 lines
6.3 KiB
JavaScript
225 lines
6.3 KiB
JavaScript
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
|
|
'kaffeemaschine': 1000
|
|
}
|
|
},
|
|
'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}`);
|
|
});
|