node-red-contrib-rosepetal-serialport
These nodes mirror the stock Node-RED serial in/out experience over NATS so that the physical serial port can live inside a Docker container (or any other isolated host). Node-RED itself never touches the UART; it publishes writes to a subject and subscribes to reads, keeping editor/runtime behaviour as close to the originals as possible.
Features
- Serial config, serial in, and serial out nodes retain the upstream editor UX and message shapes
- All deployments share the same channels:
rosepetal.serial.out,.in, and.control - Payloads are JSON envelopes with base64 data so you can fan-out monitoring consumers without extra code
- Control and heartbeat messages keep the Docker bridge aligned with Node-RED, so node LEDs always match the real serial link
- The accompanying Docker engine (see
engine/) opens the real serial device and implements the contract
Installing the Node-RED nodes
cd ~/.node-red
npm install rosepetal-labs/node-red-contrib-rosepetal-serialportRestart Node-RED. The palette exposes rosepetal serial in, rosepetal serial out, and the shared rosepetal serial config node.
Running the Docker engine
The Node-RED nodes expect a companion service that owns the hardware and speaks the channels described in CHANNELS.md. A reference implementation lives in engine/.
Build
cd engine
npm install
docker build -t rosepetal-serial-engine .Run
docker run --rm \
--network host \
--privileged \
-e NATS_URL=nats://localhost:4222 \
-e SUBJECT_ROOT=rosepetal.serial \
-e STATUS_HEARTBEAT_MS=5000 \
rosepetal-serial-engineThe container expects access to the serial device (easiest with --privileged), a reachable NATS broker (default nats://localhost:4222), and matching SUBJECT_ROOT. Multiple bridges can share the broker by choosing unique subject roots. The engine publishes heartbeat status frames every STATUS_HEARTBEAT_MS (default 5000 ms) so the Node-RED nodes always know when the serial device is healthy.
Node usage
Serial config node
Describe the port (/dev/ttyUSB0, COM3, …), baud rate, parity, stop bits, and splitting rules just like the stock node. Those values are forwarded verbatim in the configure control message so the engine can apply them before opening the serial device. Changing any field re-emits the snapshot. The NATS bridge is always enabled; use the fields to override the server URL or subject root (leave blank to keep rosepetal.serial).
Serial out node
msg.payload accepts Buffer, string, number, array, or object (objects are JSON-stringified before sending). Optional msg.baudrate publishes a baudrate control request to the .control channel. Every write is encoded according to the config node's terminator rule and published as JSON on rosepetal.serial.out (or your custom subject root). The node also emits a node-status control frame when it starts or stops so the engine can log which flows are active.
Serial in node
The serial in node subscribes to rosepetal.serial.in and applies the same splitting/timeout rules as the upstream module. msg.payload is a Buffer when the config node is set to binary mode, otherwise a UTF-8 string. msg.port reflects the configured port, and msg.nats contains any metadata that the engine attached to the frame (timestamps, request ids, signal quality, …). It also publishes node-status updates about its lifecycle.
NATS channel reference
See CHANNELS.md for the exact subjects and payload contracts expected by the engine and the Node-RED nodes.
Requirements and notes
- Node.js 18 or later (matches current Node-RED LTS baseline)
- Running NATS broker (default:
nats://localhost:4222) - External bridge/container (like
engine/) that opens the serial port and implements the channel contract - The module closes its NATS subscription when unused and reconnects automatically when the broker restarts
- Use
nats sub 'rosepetal.serial.>'to watch the traffic in parallel with Node-RED