diff --git a/README.md b/README.md index 05bb0e8..8df2e6c 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,21 @@ -# Open-EnergyMesh Offline-First MVP (Node.js) +# Open-EnergyMesh MVP: Offline-First Distributed Microgrid Orchestration (0.2 protocol) -This repository provides a minimal Open-EnergyMesh scaffold focused on an offline-first, distributed microgrid orchestration flow. It implements a small in-memory data model (Device, Inverter, Meter, DER, PriceQuote, Forecast) and a lightweight EnergyMesh orchestrator with a simple energy-flow calculation. It also includes a placeholder ADMM-like solver to demonstrate how a compositional optimization layer can be integrated on top of the runtime. +This repository contains a minimal Open-EnergyMesh MVP focused on offline-first operation +and displacement of vendor lock-in through a lightweight, pluggable architecture. -What you get in this MVP: -- Core data model for energy devices and components -- Basic energy-flow computation: generation minus consumption -- A lightweight ADMM-lite adapter surface (solver_admm.js) -- Delta-sync helper and an API surface to apply per-device deltas -- Simple tests that exercise computeFlow, delta-sync, and ADMM integration -- Lightweight, well-scoped scaffolding suitable for MVP testing and iteration +- Core MVP: in-memory mesh with Inverter and Meter models and a tiny ADMM-lite integration path +- 0.2 protocol scaffold: LocalProblem / SharedVariables / PlanDelta contracts (protocol.js) +- Adapters: reference adapters for inverter and meter demonstrating plug-and-play interoperability +- Solver: lightweight ADMM placeholder (solver_admm.js) to illustrate integration points +- Delta-sync: MVP delta application via EnergyMesh.applyDeltaSync -Usage -- Install dependencies: npm install -- Run tests: npm test -- The repository exports Open-EnergyMesh primitives via src/mesh.js for extension. +How to run tests +- npm install +- npm test -Roadmap (high level) -- Finalize a 0.2 core protocol and two starter adapters -- Implement an ADMM-lite local solver with offline/partially-connected rounds (delta-sync) -- Add privacy-preserving options and governance hooks -- Provide a small reference adapter SDK and HIL testbed +Notes +- This MVP intentionally keeps the surface small and extensible for future CatOpt-style composition and cross-vendor adapters. +- See src/mesh.js for the current MVP data model and orchestration primitives. -This project is designed to be extended incrementally. See AGENTS.md for architectural rules and contribution guidelines. - -Commit messages follow a concise rationale-focused style suitable for collaborative reviews. +Marketing and publishing +- When ready, publish readiness is signaled by creating a READY_TO_PUBLISH file at the repo root. diff --git a/adapters/inverter_adapter.js b/adapters/inverter_adapter.js new file mode 100644 index 0000000..75aaeee --- /dev/null +++ b/adapters/inverter_adapter.js @@ -0,0 +1,26 @@ +// Minimal inverter adapter scaffold +// Demonstrates a plug-in adapter exposing a small interface. + +class InverterAdapter { + constructor(id) { + this.id = id; + } + + // Example: read current state from the device (mock) + readState() { + return { + id: this.id, + outputW: 0 + }; + } + + // Example: apply a command to the device (mock) + applyCommand(cmd) { + // no-op in MVP + return { success: true, command: cmd }; + } +} + +module.exports = { + InverterAdapter +}; diff --git a/adapters/meter_adapter.js b/adapters/meter_adapter.js new file mode 100644 index 0000000..4eea33a --- /dev/null +++ b/adapters/meter_adapter.js @@ -0,0 +1,21 @@ +// Minimal meter adapter scaffold +class MeterAdapter { + constructor(id) { + this.id = id; + } + + readState() { + return { + id: this.id, + consumptionW: 0 + }; + } + + applyCommand(cmd) { + return { success: true, command: cmd }; + } +} + +module.exports = { + MeterAdapter +}; diff --git a/src/protocol.js b/src/protocol.js new file mode 100644 index 0000000..fbbf3a8 --- /dev/null +++ b/src/protocol.js @@ -0,0 +1,31 @@ +// Lightweight protocol scaffold for Open-EnergyMesh 0.2 core ontology +// This file provides tiny, versioned data contracts used by adapters. + +class LocalProblem { + constructor(version = '0.2') { + this.version = version; + this.variables = {}; // local optimization variables + this.constraints = []; // local constraints + this.objective = null; // objective description or function reference + } +} + +class SharedVariables { + constructor() { + this.variables = {}; // dual/shared variables (e.g., Lagrange multipliers) + this.metadata = {}; + } +} + +class PlanDelta { + constructor(timestamp = Date.now()) { + this.timestamp = timestamp; + this.changes = {}; // delta payload describing what changed + } +} + +module.exports = { + LocalProblem, + SharedVariables, + PlanDelta +}; diff --git a/src/solver_admm.js b/src/solver_admm.js index 4b829c3..cfb2a36 100644 --- a/src/solver_admm.js +++ b/src/solver_admm.js @@ -1,35 +1,27 @@ -// Minimal ADMM-lite solver scaffold for Open-EnergyMesh MVP -// This is deliberately small and deterministic to support offline-first testing +// Minimal ADMM-lite solver placeholder for Open-EnergyMesh MVP +// This module is intentionally lightweight: it provides a skeleton class +// that can be extended by adapters in downstream integrations. class AdmmSolver { constructor() { - // internal state kept for demonstration purposes - this.lastPrimal = null; - this.lastDual = null; + // no state for MVP; placeholder for future stateful solvers } - // Simulated solve step for a local problem. Accepts simple objects but does not - // perform real optimization in order to keep MVP lightweight. - step(localProblem, sharedVariables) { - // Very small, deterministic envelope: echo inputs with tiny adjustments - const primal = { - vars: (localProblem && localProblem.vars) ? { ...localProblem.vars } : {}, - objective: (localProblem && localProblem.objective) ? localProblem.objective : 0 - }; - const dual = { - multipliers: (sharedVariables && sharedVariables.multipliers) ? { ...sharedVariables.multipliers } : {} - }; - - // Simple synthetic adjustment to demonstrate progress without external solvers - if (primal.vars && typeof primal.vars.value === 'number') { - primal.vars.value = primal.vars.value * 1.0; // no-op, placeholder for real update - primal.objective = (primal.objective || 0) + 0; - } - - this.lastPrimal = primal; - this.lastDual = dual; - return { primal, dual }; + /** + * Solve a local optimization problem given a shared variable state. + * For the MVP, we return null to indicate no local adaptation is applied, + * allowing the caller to fall back to baseline flow calculation. + * + * @param {Object} localProblem - simplified representation of the local optimization problem + * @param {Object} sharedVariables - shared variables/state used in ADMM iterations + * @returns {Object|null} adaptation results or null to indicate no adaptation + */ + solve(localProblem, sharedVariables) { + // MVP: do not modify flow; keep baseline behavior. + return null; } } -module.exports = { AdmmSolver }; +module.exports = { + AdmmSolver +};