Some checks failed
CI / lint-and-test (push) Has been cancelled
Submodule bumps land the deadlock fix (state.js residue unpark + MGC optimalControl dispatch reorder) and pumpingStation stopLevel hysteresis. - Renames examples/pumpingstation-3pumps-dashboard → pumpingstation-complete-example with regenerated flow.json. New dashboard groups, demand-broadcast wiring, S88 placement rule applied, ui-chart trend-split and link-channel naming follow .claude/rules/node-red-flow-layout.md. - New cross-node test harness under test/: end-to-end-pumpingstation drives PS + MGC + 3 pumps + physics simulator end-to-end and verifies the ~5/15 min cycle. - Adds Grafana provisioning dashboards (pumping-station.json) and a helper sync-example.sh script for export/import to live Node-RED. - Docker entrypoint + settings + compose tweaks for the persistent user dir layout used by the demo. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
112 lines
5.6 KiB
Markdown
112 lines
5.6 KiB
Markdown
# EVOLV Examples — Team Workflow
|
||
|
||
This file is the canonical guide for working with the example flows that live under `examples/`. Each subfolder is a Node-RED **project**; the Docker stack is set up so switching between them is two clicks in the editor.
|
||
|
||
## Stack at a glance
|
||
|
||
| Container | What | URL |
|
||
|---|---|---|
|
||
| `evolv-nodered` | Node-RED runtime + dashboard | <http://localhost:1880> · dashboard at <http://localhost:1880/dashboard> |
|
||
| `evolv-influxdb` | Time-series store (port-1 telemetry) | <http://localhost:8086> · `evolv` / `evolv-dev-pw` |
|
||
| `evolv-grafana` | Provisioned dashboards (anonymous viewer enabled) | <http://localhost:3000> |
|
||
|
||
The `evolv_nodered_data` named volume keeps `/data` (flows, projects, sessions) across `docker compose down && up`. The `examples/` directory in this repo is the **source of truth**; the Node-RED Projects feature operates on a copy in the volume.
|
||
|
||
## Quick start
|
||
|
||
```bash
|
||
cd /path/to/EVOLV
|
||
docker compose up -d
|
||
# Node-RED: http://localhost:1880
|
||
# Dashboard: http://localhost:1880/dashboard
|
||
# Grafana: http://localhost:3000 (anonymous viewer)
|
||
```
|
||
|
||
The first time you start it, the entrypoint copies every `examples/<name>/` into `/data/projects/<name>/` and `git init`s each. Subsequent starts skip folders that already exist in the volume.
|
||
|
||
## Switching examples
|
||
|
||
Open the editor → **menu → Projects → Open Project** → pick another project. The editor reloads the chosen flow.
|
||
|
||
The default active project on first boot is `pumpingstation-complete-example`. To change the default for fresh volumes, set `DEFAULT_PROJECT=<name>` on the `nodered` service in `docker-compose.yml`.
|
||
|
||
## Editing a flow
|
||
|
||
You have two paths. They serve different purposes — pick based on what you're doing.
|
||
|
||
### Path A — edit `build_flow.py` (canonical, recommended)
|
||
|
||
```bash
|
||
# 1. Edit the Python generator
|
||
vim examples/<name>/build_flow.py
|
||
|
||
# 2. Regenerate flow.json
|
||
python3 examples/<name>/build_flow.py > examples/<name>/flow.json
|
||
|
||
# 3. Push to the runtime
|
||
./scripts/sync-example.sh <name>
|
||
```
|
||
|
||
The Python is the **source of truth**. It's diff-friendly and the right place for any change you intend to commit.
|
||
|
||
### Path B — edit in the Node-RED editor (experimentation)
|
||
|
||
```
|
||
Open editor → Make changes → Deploy
|
||
```
|
||
|
||
Edits go into the volume (`/data/projects/<name>/flow.json`). They survive `docker compose down && up` but are **not in the EVOLV git repo**. To incorporate them back:
|
||
|
||
```bash
|
||
docker cp evolv-nodered:/data/projects/<name>/flow.json examples/<name>/flow.json
|
||
```
|
||
|
||
Then commit `examples/<name>/flow.json` (and reverse-engineer the change into `build_flow.py` if you want it diff-friendly going forward).
|
||
|
||
## Adding a new example
|
||
|
||
```bash
|
||
mkdir examples/<scenario>-<focus>
|
||
# Build a flow.json (recommended: a build_flow.py that generates it)
|
||
vim examples/<scenario>-<focus>/{build_flow.py,README.md,flow.json}
|
||
|
||
# Restart Node-RED so the entrypoint bootstraps the new project
|
||
docker compose restart nodered
|
||
```
|
||
|
||
The entrypoint synthesizes `package.json`, runs `git init`, and makes an initial commit so Node-RED recognises it as a project. Bootstrap is idempotent — if a `/data/projects/<name>/` already exists, it's left alone.
|
||
|
||
After restart, **Projects → Open Project** in the editor will list the new entry.
|
||
|
||
## Resetting state
|
||
|
||
| Goal | Command |
|
||
|---|---|
|
||
| Push the repo's `flow.json` into the runtime, reload | `./scripts/sync-example.sh <name>` |
|
||
| Wipe one project's volume copy and re-bootstrap | `docker exec evolv-nodered rm -rf /data/projects/<name>` then `docker compose restart nodered` |
|
||
| Wipe **everything** in the volume (flows, sessions, all projects, but NOT InfluxDB/Grafana) | `docker compose down && docker volume rm evolv_nodered_data && docker compose up -d` |
|
||
| Wipe everything including telemetry | `docker compose down -v && docker compose up -d` |
|
||
|
||
## Debugging
|
||
|
||
| Symptom | Where to look |
|
||
|---|---|
|
||
| Flow not loading after deploy | `docker logs evolv-nodered` for crash backtraces |
|
||
| InfluxDB empty / not receiving | Telemetry tab in editor → status of the `Count writes` node. Should show `N POSTs · M lines (0 err)`. |
|
||
| Dashboard widget shows `n/a` | Check the Process Plant tab → output formatter function for that node — `c.<key>` keys the dispatcher reads from |
|
||
| Grafana dashboard panels empty | Open InfluxDB UI (<http://localhost:8086>) → Data Explorer → confirm the field name the panel queries actually exists. Field names are flat dotted keys like `level.predicted.atequipment.default`. |
|
||
| `interpolation configuration: New f =... is constrained` warnings | The pump curve f-axis is out-of-range. f = downstream − upstream pressure differential, in Pa, must be inside the curve's range (e.g. 70 000 – 390 000 Pa for `hidrostal-H05K-S03R`). Check the per-pump physics feeder formula. |
|
||
| High CPU in Node-RED | Per-tick HTTP fan-out to InfluxDB; the pumpingstation example uses a 500 ms batch in the Telemetry tab. If CPU is still high, lower `tickIntervalMs` in the EVOLV node configs (currently 1000). |
|
||
|
||
## File map per example
|
||
|
||
```
|
||
examples/<name>/
|
||
├── build_flow.py ← canonical source of flow.json (Python generator)
|
||
├── flow.json ← regenerated artefact, also tracked in Git
|
||
├── README.md ← topology, control modes, dashboard map, things to try
|
||
└── package.json ← (synthesized in volume by entrypoint, not in repo)
|
||
```
|
||
|
||
The repo tracks `build_flow.py`, `flow.json`, and `README.md`. The `package.json` and `.git/` directory of the project live only in the named volume — they're created by the entrypoint on first bootstrap and don't leak back into the EVOLV Git history.
|