Files
dashboardAPI/wiki/Home.md
znetsixe a9fc51d6f0 docs(wiki): full 5-page wiki matching the rotatingMachine reference format
Replaces the prior stub/partial wiki with a Home + Reference-{Architecture,
Contracts,Examples,Limitations} + _Sidebar structure. Topic-contract and
data-model sections wrapped in AUTOGEN markers for the future wiki-gen tool.
Source-vs-spec contradictions surfaced and flagged inline (not silently
fixed). Pending-review notes mark sections that need a full node review.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 09:42:14 +02:00

8.3 KiB

dashboardAPI

code-ref s88 status

A dashboardAPI node converts EVOLV node topology into Grafana dashboards. On each inbound child.register event it resolves the child source, walks its direct children, loads per-softwareType Grafana JSON templates from config/, and emits one HTTP upsert request per dashboard on Port 0 to a downstream http request node. Sits adjacent to the S88 hierarchy as a passive HTTP emitter — no measurements, no tick loop, no parent registration.

Note

Pending full node review (2026-05). Content reflects CONTRACT.md and current source only.


At a glance

Thing Value
What it represents Utility bridge between EVOLV topology and Grafana — auto-generates dashboards from child.register events
S88 level Utility — not in the S88 hierarchy; sits adjacent to it
Use it when You want Grafana dashboards to materialise automatically when an EVOLV node graph is deployed
Don't use it for Maintaining hand-curated Grafana dashboards (will overwrite); arbitrary Grafana API calls; tick / measurement data plumbing
Children it accepts Any EVOLV node whose nodeSource.config carries functionality.softwareType
Parents it talks to None — dashboardAPI is a passive sink; it does not register with a parent

How it fits

flowchart LR
    ps[pumpingStation<br/>Process Cell]:::pc -.child.register.-> dash
    mgc[machineGroupControl<br/>Unit]:::unit -.child.register.-> dash
    rm[rotatingMachine<br/>Equipment]:::equip -.child.register.-> dash
    meas[measurement<br/>Control Module]:::ctrl -.child.register.-> dash
    dash[dashboardAPI<br/>Utility]:::neutral -->|"POST /api/dashboards/db"| http[http request<br/>node-red core]:::neutral
    http --> grafana[(Grafana<br/>HTTP API)]
    grafana -.renders dashboards for.-> ff[FlowFuse / Browser]
    classDef pc fill:#0c99d9,color:#fff
    classDef unit fill:#50a8d9,color:#000
    classDef equip fill:#86bbdd,color:#000
    classDef ctrl fill:#a9daee,color:#000
    classDef neutral fill:#dddddd,color:#000

Dashed arrows = inbound child.register events from any EVOLV process node. The solid arrow is the outbound HTTP upsert envelope on Port 0 — emitted once per generated dashboard in the walked graph. S88 colours and the utility-neutral #dddddd are anchored in .claude/rules/node-red-flow-layout.md.


Try it — 3-minute demo

Import the basic example flow, deploy, and watch a child.register payload turn into a Grafana dashboard upsert request.

curl -X POST -H 'Content-Type: application/json' \
  --data @nodes/dashboardAPI/examples/basic.flow.json \
  http://localhost:1880/flow

What to click after deploy:

  1. Open the inject node (basic trigger) and edit the payload to a {source: {config: {...}}} shape — see Reference — Examples for the minimal inline-payload shape.
  2. Fire the inject. Watch the debug pane: one topic: 'create' HTTP envelope appears per dashboard in the walked graph (root + direct children).
  3. Wire a downstream http request node (method POST) to the dashboardAPI output to actually POST the envelope to Grafana.

Important

GIF needed. Demo recording of the inject → Port-0 envelope → Grafana dashboard upsert path. Save as wiki/_partial-gifs/dashboardAPI/01-basic-demo.gif, target ≤ 1 MB after gifsicle -O3 --lossy=80.

Warning

The shipped basic.flow.json / integration.flow.json / edge.flow.json are stubs — the inject payloads do not yet conform to the child.register resolver's expected shape. They will trigger Missing or invalid child node errors until updated. Tracked in Limitations — Example flow stubs.


The one thing you'll send

Topic Aliases Payload What it does
child.register registerChild string (child node id) or {source: {...}} or {config: {...}} (optionally msg.includeChildren: boolean, default true) Resolves the child source (RED.nodes.getNodenode._flow.getNode → inline payload), calls source.generateDashboardsForGraph(child, {includeChildren}), then emits one topic: 'create' HTTP-upsert message on Port 0 per generated dashboard.

That's it. There is no set.*, no cmd.*, no query.* — the registry has a single canonical topic (alias-with-deprecation). The legacy registerChild alias logs a one-time deprecation warning on first use.


What you'll see come out

Sample Port 0 message after a child.register for a pumpingStation node with two direct children:

{
  "topic": "create",
  "url": "http://grafana:3000/api/dashboards/db",
  "method": "POST",
  "headers": {
    "Accept": "application/json",
    "Content-Type": "application/json",
    "Authorization": "Bearer eyJ..."
  },
  "payload": {
    "dashboard": { "uid": "a1b2c3d4e5f6", "title": "Pumping Station Demo", "templating": {...} },
    "folderId": 0,
    "overwrite": true
  },
  "meta": {
    "nodeId": "ps_demo",
    "softwareType": "pumpingStation",
    "uid": "a1b2c3d4e5f6",
    "title": "Pumping Station Demo"
  }
}
Field Meaning
topic Always 'create' — signals a dashboard-upsert HTTP envelope.
url grafanaUpsertUrl() = <protocol>://<host>:<port>/api/dashboards/db.
method Always POST.
headers.Authorization Present only when bearerToken is configured; omitted otherwise.
payload.dashboard The composed Grafana dashboard JSON (template + templating vars filled in).
payload.dashboard.uid sha1(softwareType:nodeId).slice(0, 12) — stable across re-deploys.
meta.* Correlation fields for the downstream consumer (nodeId, softwareType, uid, title).

Inbound msg fields propagate via spread ({...msg, ...envelope}) so any caller-supplied correlation / trace fields survive.

Port 1 (InfluxDB telemetry) and Port 2 (registration / control plumbing) are unused — dashboardAPI has no measurements and does not register with a parent. See Reference — Architecture.


The new bit — no BaseNodeAdapter / BaseDomain

Most EVOLV nodes extend BaseNodeAdapter + BaseDomain from generalFunctions/. dashboardAPI does not — per OPEN_QUESTIONS.md (2026-05-10) the decision is to keep a bespoke adapter until BaseNodeAdapter grows passive / HTTP-only flags.

Reasons:

  • No generalFunctions/src/configs/dashboardapi.jsonBaseDomain's constructor unconditionally calls configManager.getConfig(ctor.name) and would throw. The local dependencies/dashboardapi/dashboardapiConfig.json is for the editor menu endpoint, not the runtime config pipeline.
  • No periodic output — BaseNodeAdapter._emitOutputs() / outputUtils.formatMsg assumes a delta-compressed Port 0 / 1 stream; dashboardAPI emits HTTP-shaped messages instead.
  • No registration to a parent — BaseNodeAdapter._scheduleRegistration would emit a spurious child.register of its own.
  • No status badge / tick / measurements / children of its own.

dashboardAPI uses the shared commandRegistry (canonical-topic naming + alias-with-deprecation) and stops there. See Reference — Architecture for the full rationale.


Need more?

Page What you'll find
Reference — Contracts Full topic contract, config schema, child resolution rules, template alias table
Reference — Architecture Code map, HTTP-endpoint lifecycle, template loader, UID stability, graph walk
Reference — Examples Shipped example flows + debug recipes
Reference — Limitations Legacy filename drift, stub flows, missing template handling, open questions

EVOLV master wiki · Topology Patterns · Topic Conventions