// Minimal Open-EnergyMesh scaffold (offline-first MVP) // Provides a tiny in-memory data model: Device, Inverter, Meter, DER, PriceQuote, Forecast // and a lightweight EnergyMesh orchestrator with a simple energy-flow calculation. class Device { constructor(id, name, type) { this.id = id; this.name = name; this.type = type; // e.g., 'inverter', 'meter', 'storage', 'der' } } class Inverter { constructor(id, deviceId, capacityW, outputW) { this.id = id; this.deviceId = deviceId; this.capacityW = capacityW; this.outputW = typeof outputW === 'number' ? outputW : 0; // current output in Watts } } class Meter { constructor(id, deviceId, consumptionW) { this.id = id; this.deviceId = deviceId; this.consumptionW = typeof consumptionW === 'number' ? consumptionW : 0; // current consumption in Watts } } class DER { constructor(id, type, capacityW) { this.id = id; this.type = type; // 'inverter' | 'storage' this.capacityW = capacityW; } } class PriceQuote { constructor(timestamp, pricePerKWh) { this.timestamp = timestamp; // epoch ms this.pricePerKWh = pricePerKWh; // number } } class Forecast { constructor(horizonHours, value) { this.horizonHours = horizonHours; this.value = value; // simple numeric forecast placeholder } } class EnergyMesh { constructor() { this.devices = new Map(); // id -> Device this.inverters = new Map(); // id -> Inverter this.meters = new Map(); // id -> Meter this.ders = new Map(); // id -> DER this.quotes = []; this.forecasts = []; } // Device helpers addDevice(device) { if (!(device instanceof Device)) { throw new Error('addDevice expects a Device instance'); } this.devices.set(device.id, device); } addInverter(inverter) { if (!(inverter instanceof Inverter)) { throw new Error('addInverter expects an Inverter instance'); } this.inverters.set(inverter.id, inverter); // implicitly ensure a device exists for this inverter if (!this.devices.has(inverter.deviceId)) { this.addDevice(new Device(inverter.deviceId, `Inverter-${inverter.deviceId}`, 'inverter')); } } addMeter(meter) { if (!(meter instanceof Meter)) { throw new Error('addMeter expects a Meter instance'); } this.meters.set(meter.id, meter); if (!this.devices.has(meter.deviceId)) { this.addDevice(new Device(meter.deviceId, `Meter-${meter.deviceId}`, 'meter')); } } addDER(der) { if (!(der instanceof DER)) { throw new Error('addDER expects a DER instance'); } this.ders.set(der.id, der); } addPriceQuote(quote) { if (!(quote instanceof PriceQuote)) { throw new Error('addPriceQuote expects a PriceQuote'); } this.quotes.push(quote); } addForecast(forecast) { if (!(forecast instanceof Forecast)) { throw new Error('addForecast expects a Forecast'); } this.forecasts.push(forecast); } // Simple energy-flow calculation: total generation minus total consumption // Assumes inverter.outputW is generation and meter.consumptionW is load computeFlow() { let generation = 0; for (const inv of this.inverters.values()) { generation += typeof inv.outputW === 'number' ? inv.outputW : 0; } let consumption = 0; for (const m of this.meters.values()) { consumption += typeof m.consumptionW === 'number' ? m.consumptionW : 0; } return { generationW: generation, consumptionW: consumption, netFlowW: generation - consumption }; } } module.exports = { EnergyMesh, Device, Inverter, Meter, DER, PriceQuote, Forecast };