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.
|