Getting started

Field gateways with Node-RED

Get readings out of equipment that speaks Modbus, OPC-UA, MQTT or serial and into the platform, through a small computer at the site.

When you need a gateway

Geronimo IoT speaks HTTP. A lot of field equipment does not. A submersible level sensor on an RS-485 bus speaks Modbus RTU; a pump-house controller speaks OPC-UA or BACnet; a LoRaWAN base station drops its payloads on an MQTT broker; an older datalogger writes lines to a serial port and nothing else. None of those can be pointed at an upload URL.

A gateway is a small computer at the site — a Raspberry Pi, an industrial DIN-rail box, a spare PC in the control room — that speaks the local protocol on one side and this platform's upload API on the other. It sits between the equipment and the internet, holds the sensor's credential, and keeps the readings safe while the link is down.

You do not need one if your sensor already pushes to the upload API, or if the platform pulls its data from a provider on a timer. See Adding sensors for those two paths; this page is about the third case, where something has to translate.

What Node-RED brings

Node-RED is a free, widely deployed flow editor for exactly this job: you wire up blocks in a browser and it runs as a service on the gateway. Its palette already covers the protocols this platform has no way to speak:

  • Modbus RTU over RS-485 and TCP over Ethernet — the common language of level, flow and pressure transmitters;
  • OPC-UA — SCADA and PLC systems in water and wastewater plants;
  • MQTT — LoRaWAN network servers (ChirpStack, The Things Stack), most cellular IoT platforms, and site brokers;
  • serial — RS-232/RS-485 dataloggers and anything with a console port;
  • BACnet, SNMP, S7, CAN, Zigbee and a long tail of others, plus reading files off a share and scraping a local web page.

We publish a Node-RED node — node-red-contrib-nightheron — that is the last block in such a flow. Whatever the flow produced, it signs it, queues it and delivers it here. Nothing on the server side changes: it uses the same upload API and the same per-sensor credential a device would.

Installing the node

On the gateway, with Node-RED already installed and running:

cd ~/.node-red
npm install node-red-contrib-nightheron
sudo systemctl restart nodered

It needs Node 18 or newer and Node-RED 3 or newer, and it pulls in no other packages. After the restart, Night Heron appears in the palette under network.

Getting the sensor's upload credential

The gateway authenticates as one sensor. Register that sensor first — Sensors → + Add a New Sensor, with Data Source set to Geronimo IoT API (device push) — then open it for editing and expand API access & tokens.

  1. Under Upload credential, press Rotate credential. The confirmation shows the full credential (sk_<storage key>_<secret>) and its signing key once. Copy both before you leave the page; only a one-way digest is kept, so they cannot be shown again.
  2. Leave How this device authenticates on Signed requests (recommended), which is what a new sensor is set to. The node supports it and it is the mode to use: the secret never travels, and a captured request can be neither replayed nor edited.
  3. Legacy bearer token exists for firmware that cannot sign. A gateway can sign, so it has no reason to use it.

If the gateway feeds several sensors, give each one its own credential and its own Night Heron node in the flow. A credential names its sensor, so one can never write another's readings — which is the property that makes handing a gateway to a customer safe.

Configuring the node

Drag Night Heron into a flow, open it, and add a deployment:

FieldWhat to put in it
Base URL The deployment root, including its URL prefix — for this one, everything before /api/ in https://app-iot.geronimoengineering.com/night-heron-multi/api/upload-sensor-data/. The prefix is part of what gets signed, so a wrong one produces a perfectly formed signature over the wrong string and a 401.
Auth mode Signed, unless the sensor has been switched to legacy on its edit page.
Credential and Signing key The two values the app showed once. They are stored in Node-RED's credentials file, not in flows.json, so an exported flow does not carry them.
Batch, Queue size, Queue age How many readings go in one request (500 is the server's cap), and how many readings and how many hours of them the gateway keeps on disk while it cannot deliver. Size the queue for the longest outage you intend to survive: past those bounds the oldest readings are dropped — loudly, but they are dropped.

An example flow

The shape of every gateway flow is the same: read something, turn it into {variable: value}, hand it to the node. This one fabricates a reading on a timer so you can prove the path end to end before any hardware is involved — paste it into Import in the Node-RED editor, then open the Night Heron node and fill in the deployment.

[
  {"id":"t1","type":"inject","z":"f1","name":"every 5 minutes",
   "props":[{"p":"payload"}],"repeat":"300","once":true,"onceDelay":"1",
   "payloadType":"date","x":160,"y":120,"wires":[["f2"]]},
  {"id":"f2","type":"function","z":"f1","name":"read the sensor",
   "func":"msg.payload = { Meter_Hydros21_Depth: 1.24, EnviroDIY_Mayfly_Batt: 3.9 };\nreturn msg;",
   "outputs":1,"x":380,"y":120,"wires":[["f3"]]},
  {"id":"f3","type":"nightheron","z":"f1","name":"","server":"cfg1",
   "batchSize":"500","maxQueue":"10000","maxAgeHours":"168",
   "x":600,"y":120,"wires":[["f4"]]},
  {"id":"f4","type":"debug","z":"f1","name":"delivered","complete":"true",
   "x":800,"y":120,"wires":[]},
  {"id":"cfg1","type":"nightheron-config","name":"my deployment",
   "url":"https://example.org/night-heron-multi","mode":"signed",
   "skewSeconds":"300","timeoutMs":"20000"},
  {"id":"f1","type":"tab","label":"Gateway"}
]

To make it real, replace the read the sensor function with a modbus read, an mqtt in or a serial in node and whatever arithmetic turns raw counts into a measurement. The last two nodes stay as they are.

Any key in the payload that is a valid variable name — a letter or underscore, then letters, digits, _ or -, up to 64 characters — becomes a variable on the sensor, exactly as if a device had posted it. The node warns in the debug pane about keys the server would ignore, so a typo surfaces immediately rather than as missing data three weeks later.

Reading the node while it runs

The badge under the node is the whole status display:

BadgeWhat it means
green sent 412Everything taken so far has been stored; nothing is waiting.
green sent 412 — 30 queuedWorking through a backlog after an outage.
red offline: 30 queued, retry in 16sNo route to the server. The readings are on disk; the retry interval doubles up to a ceiling.
red clock 912s off — 4 queuedThe gateway's clock is outside the signature window. Fix the clock (a Pi with no battery-backed clock boots at the wrong time); nothing has been lost.
red, with a sentenceThe server's own reason, verbatim — e.g. Replayed X-NH-Nonce; every request needs a fresh one.

Readings are written to the gateway's disk before they are sent and deleted only once the server has stored them, so an outage, a power cut or a reboot in the middle of one costs nothing: the queue drains in order when the link returns, and the readings keep the times they were taken, not the time they finally arrived. Re-sending a reading the platform already holds overwrites it in place rather than duplicating it, which is what makes a retry after a timed-out request safe.

What this is not

  • Not a replacement for the platform's own ingestion. If the sensor can push to the upload API itself, or if its data is published somewhere the platform already pulls from — Monitor My Watershed, USGS, a county CSV feed — a gateway adds a computer, a power supply and a patching obligation for nothing.
  • Not managed by us. The gateway is yours: the hardware, the operating system, the Node-RED install and this node are on your site and in your care, including security updates. We can tell you a sensor has gone quiet; we cannot tell you why a box in a cabinet stopped.
  • Not unlimited buffering. The on-disk queue is bounded by the size and age you set. A gateway offline for longer than that will drop its oldest readings. It says so, on the badge and in the log, but it does drop them.
  • Not a data-quality step. Readings arrive as raw values, the same as any pushed reading. Calibration, unit conversion and quality flagging happen here, under Data quality and Rating curves — not in the flow, where nothing records what was applied.
  • Not a way around the rate limit. Uploads are capped per sensor (600 requests an hour by default). The node batches up to 500 readings per request, which is what keeps a fast-polling gateway comfortably inside it; a flow that pushes every reading the instant it is taken will not be.