build(agent): molt-b#d1f4fd iteration
This commit is contained in:
parent
f8b2833760
commit
a7122d53b3
|
|
@ -0,0 +1,21 @@
|
|||
node_modules/
|
||||
.npmrc
|
||||
.env
|
||||
.env.*
|
||||
__tests__/
|
||||
coverage/
|
||||
.nyc_output/
|
||||
dist/
|
||||
build/
|
||||
.cache/
|
||||
*.log
|
||||
.DS_Store
|
||||
tmp/
|
||||
.tmp/
|
||||
__pycache__/
|
||||
*.pyc
|
||||
.venv/
|
||||
venv/
|
||||
*.egg-info/
|
||||
.pytest_cache/
|
||||
READY_TO_PUBLISH
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# Open-EnergyMesh Agents
|
||||
|
||||
- Architecture: Node.js in-memory MVP for offline-first mesh orchestration.
|
||||
- Tech Stack: JavaScript (CommonJS), minimal data models for Device/DER/Forecast, simple flow engine.
|
||||
- Testing: node test/test.js; run via npm test.
|
||||
- Commands:
|
||||
- Install (if needed): npm install
|
||||
- Run tests: npm test
|
||||
- Publish readiness: not yet; see READY_TO_PUBLISH marker when ready.
|
||||
30
README.md
30
README.md
|
|
@ -1,3 +1,29 @@
|
|||
# open-energymesh-offline-first-distribute
|
||||
Open-EnergyMesh (Offline-First MVP)
|
||||
|
||||
An open, modular platform to orchestrate energy flows in local microgrids (homes, businesses, community solar) with offline-first operation and mesh networking. It provides a common data model for energy devices (inverters, storage, meters), a plugga
|
||||
Overview
|
||||
- A minimal, open MVP for offline-first distributed microgrid orchestration.
|
||||
- Core concepts implemented in this MVP:
|
||||
- Simple in-memory data model for devices, DERs, forecasts, and price quotes.
|
||||
- This repository is a stepping stone toward a larger ecosystem; features are intentionally scoped to allow rapid iteration and testing.
|
||||
|
||||
Project layout
|
||||
- package.json: npm metadata and test script.
|
||||
- src/mesh.js: Core in-memory energy mesh model (EnergyMesh, Device, Inverter, Meter, DER, PriceQuote, Forecast).
|
||||
- test/test.js: Basic unit test verifying energy-flow calculation.
|
||||
- AGENTS.md: Architecture and testing guidance for future agents.
|
||||
- README.md: This file.
|
||||
- test.sh: Executable to run tests in CI/local environment.
|
||||
- READY_TO_PUBLISH: marker file to signal completion (created when ready).
|
||||
|
||||
How to run locally
|
||||
- Install dependencies: npm install
|
||||
- Run tests: npm test
|
||||
- Or run the provided test script: ./test.sh
|
||||
|
||||
Extending the MVP
|
||||
- Add more detailed data models (Event, Trade, etc.).
|
||||
- Implement a lightweight mesh protocol layer and offline-sync logic.
|
||||
- Introduce a forecasting and pricing plug-in interface.
|
||||
- Add governance/peer-to-peer trading scaffolding in a separate module.
|
||||
|
||||
This repository is intentionally lightweight to enable rapid experimentation and iterative improvement.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"name": "@community/open-energymesh-offline-first-distribute",
|
||||
"version": "0.1.0",
|
||||
"description": "Open-EnergyMesh: Offline-first distributed microgrid orchestration (minimal MVP)",
|
||||
"main": "src/mesh.js",
|
||||
"type": "commonjs",
|
||||
"scripts": {
|
||||
"test": "node test/test.js"
|
||||
},
|
||||
"license": "MIT",
|
||||
"homepage": "",
|
||||
"dependencies": {}
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
// 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
|
||||
};
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
echo "Running tests..."
|
||||
npm test
|
||||
|
||||
echo "Tests completed."
|
||||
|
|
@ -0,0 +1 @@
|
|||
This folder contains simple tests for the Open-EnergyMesh MVP.
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
const assert = require('assert');
|
||||
const {
|
||||
EnergyMesh,
|
||||
Inverter,
|
||||
Meter
|
||||
} = require('../src/mesh.js');
|
||||
|
||||
function run() {
|
||||
// Create mesh
|
||||
const mesh = new EnergyMesh();
|
||||
|
||||
// Create devices and components
|
||||
const inv = new Inverter('inv1', 'dev-inv1', 1000, 600); // generates 600W
|
||||
const meter = new Meter('m1', 'dev-mtr1', 400); // consumes 400W
|
||||
|
||||
mesh.addInverter(inv);
|
||||
mesh.addMeter(meter);
|
||||
|
||||
const result = mesh.computeFlow();
|
||||
|
||||
// Expect generation > consumption by 200W
|
||||
assert.strictEqual(result.generationW, 600);
|
||||
assert.strictEqual(result.consumptionW, 400);
|
||||
assert.strictEqual(result.netFlowW, 200);
|
||||
}
|
||||
|
||||
try {
|
||||
run();
|
||||
console.log('ALL TESTS PASSED');
|
||||
process.exit(0);
|
||||
} catch (err) {
|
||||
console.error('TEST FAILED', err);
|
||||
process.exit(1);
|
||||
}
|
||||
Loading…
Reference in New Issue