# 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 | · dashboard at | | `evolv-influxdb` | Time-series store (port-1 telemetry) | · `evolv` / `evolv-dev-pw` | | `evolv-grafana` | Provisioned dashboards (anonymous viewer enabled) | | 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//` into `/data/projects//` 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=` 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//build_flow.py # 2. Regenerate flow.json python3 examples//build_flow.py > examples//flow.json # 3. Push to the runtime ./scripts/sync-example.sh ``` 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//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//flow.json examples//flow.json ``` Then commit `examples//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/- # Build a flow.json (recommended: a build_flow.py that generates it) vim examples/-/{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//` 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 ` | | Wipe one project's volume copy and re-bootstrap | `docker exec evolv-nodered rm -rf /data/projects/` 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.` keys the dispatcher reads from | | Grafana dashboard panels empty | Open InfluxDB UI () → 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// ├── 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.