Skip to content

Skip the boilerplate. Ship the sketch.

An optional Arduino library for ESP32 and ESP8266. It hides WiFi, TLS, the WebSocket/HTTP transport, JSON, and the nodrix control/telemetry protocol behind a tiny API — so a sketch is mostly your own device logic, not plumbing.

v0.1.0 MIT licensed ESP32 · ESP8266 C++ / Arduino
Get started

Install it

Pick a channel. It's in the Arduino IDE Library Manager, the PlatformIO registry, and the ESP Component Registry, or you can pull it straight from GitHub. The Arduino and PlatformIO channels bring ArduinoJson (v7) and WebSockets by Markus Sattler along with it.

Arduino IDE logo

Arduino IDE

Library Manager

Search the Library Manager and click Install — the dependencies come with it.

Nodrix
Arduino reference
PlatformIO logo

PlatformIO

Registry

Add one line to your platformio.ini:

lib_deps = decoded-cipher/Nodrix
Registry page
ESP-IDF logo

ESP-IDF

Component Registry

For ESP-IDF projects with arduino-esp32, add it from the ESP Component Registry:

idf.py add-dependency "decoded-cipher/nodrix"
Registry page
GitHub logo

GitHub

Source

Or pin any tagged release straight from the repo:

lib_deps = https://github.com/decoded-cipher/nodrix-sdk.git#v0.1.0
Release v0.1.0

Then pull it into your sketch with a single header:

#include <Nodrix.h>
Quickstart

The whole program

Hand-written, driving one LED from the cloud is about ninety lines of WiFi, TLS, JSON parsing, acking, and reconnect handling. With the library it's this — bind a dashboard toggle to led and it works end to end:

LedControl.ino
#include <Nodrix.h>
#include "secret.h"

const int LED_PIN = 2;

NODRIX_WRITE("led") {                 // cloud writes "led" -> this runs
  digitalWrite(LED_PIN, value.asBool() ? HIGH : LOW);
  Nodrix.send("led", value.asBool()); // report real state back
}

void setup() {
  pinMode(LED_PIN, OUTPUT);
  Nodrix.begin(WIFI_SSID, WIFI_PASS, HOST, TOKEN);
}

void loop() {
  Nodrix.run();
}

Everything below is what the library does underneath.

Under the hood

What it handles for you

Everything that isn't specific to your project — the transport, the protocol, and its sharp edges — lives below the API.

Blynk-style handlers

NODRIX_WRITE("var") { … } runs when the cloud writes a variable. Self-registering — no dispatch table, no wiring in setup().

Typed control values

value coerces the wire type, so a boolean toggle, a numeric slider, and a string select all just work — no fragile string matching.

One-call telemetry

Nodrix.send() stages a metric; the library coalesces many into one frame and enforces the wire limits before sending.

Two transports

An always-on WebSocket for instant control, or HTTP polling for battery deep-sleep nodes. Same handlers, one-line switch.

At-least-once + auto-ack

The library acks every write so the cloud stops re-sending it, and nothing is lost across a nap or a WiFi blip.

Control-variable seeding

It seeds each handled variable so the cloud will queue writes to it, and re-echoes real state on reconnect instead of clobbering it.

Multiple WiFi networks

addAP() registers fallbacks; the strongest reachable one is used and the device fails over between them mid-session.

Reconnect + heartbeat

The socket reconnects on its own and rides protocol heartbeats, so a silent link gets noticed instead of hanging.

Optional TLS pinning

Encrypted-but-unverified by default for a fast first run; pin a root CA (ESP32) or a fingerprint (ESP8266) when you ship.

Control

Receiving control

NODRIX_WRITE("var") { … } registers a handler for a variable. When a dashboard widget, an automation, or the API writes it, the block runs with a value in scope. Registration happens before setup(), so a handler is a single self-contained block anywhere in the sketch — no dispatch table.

The value is a NodrixValue that coerces the wire type, so a toggle sending true, a slider sending 42, and a select sending "on" all just work:

MethodReturns
value.asBool() true for true, any non-zero number, or "on"/"1"/"true"/"yes"
value.asInt() / asLong() integer (parses numeric strings)
value.asFloat() / asDouble() number
value.asString() the raw string
value.isNull() no value

Acknowledgements are automatic — the library acks every write it delivers, so the cloud stops re-sending it. Because delivery is at-least-once, a handler can run more than once for the same command across a reconnect, so keep it idempotent. Setting a pin to a definite state is naturally safe.

Telemetry

Sending telemetry

send() reports a reading; overloads cover every common type.

Nodrix.send("temperature", 22.5);
Nodrix.send("online", true);
Nodrix.send("status", "ok");

Calls stage a metric rather than transmitting immediately; the library coalesces them into a single frame on the next run() (WebSocket) or flush()/poll() (HTTP), so ten calls become one payload. The buffer also enforces the wire limits — it batches within the per-frame cap, drops over-long keys, and clamps oversized strings — so one bad reading can't get the whole batch rejected.

Transports

Two transports, same handlers

A device lives one of two ways, and the library matches both without changing your handlers — a one-line switch between begin() and beginHTTP().

begin() — WebSocket beginHTTP() — polling
Latencyinstantyour poll interval
Connectionone socket held opennone; one request per check
Best foralways-on controllersbattery / deep-sleep nodes
Loop callrun() every loop()poll() on each wake
Idle cost~zero (Cloudflare hibernates it)one request per interval

HTTP wake cycle

void setup() {
  Nodrix.beginHTTP(WIFI_SSID, WIFI_PASS, HOST, TOKEN);
  Nodrix.send("soil", analogRead(34));
  Nodrix.flush();   // POST telemetry
  Nodrix.poll();    // fetch + apply queued control, then ack
  // ... then esp_deep_sleep_start()
}
Reliability

The reliability the protocol needs

The protocol's sharp edges are the reason to use the library rather than hand-roll it — and they all live below the API.

At-least-once delivery

A control write stays queued until it's acknowledged and re-delivers on the next connect or poll, so nothing is lost across a nap or a WiFi blip.

Automatic acks

The library acknowledges every write it hands your code, so the cloud stops re-sending it. Forgetting the ack is the most common hand-rolled bug.

Control-variable seeding

The cloud only queues writes to a variable it has seen. The library seeds each registered handler on connect, and re-echoes the last known state on reconnect rather than clobbering it.

Reconnect & heartbeat

On the WebSocket it reconnects on its own and rides protocol heartbeats for liveness; run() and poll() also re-run WiFi failover if the connection drops.

Security

TLS pinning

By default the library connects encrypted but unverified — the shortest path to a first working device. To pin, call setCACert(pem) (ESP32, WebSocket and HTTP) or setFingerprint(fp) (ESP8266, HTTP) before begin(). Pin the root CA, not the leaf — the leaf rotates every ~90 days, the root does not. Your host serves its root as the last block of the chain:

openssl s_client -showcerts -servername yourproject.workers.dev \
  -connect yourproject.workers.dev:443 </dev/null 2>/dev/null \
| awk '/BEGIN CERTIFICATE/{c++; b=""} {b=b $0 ORS} /END CERTIFICATE/{last=b} END{printf "\n%s", last}'

For Cloudflare *.workers.dev that returns GTS Root R4. One limitation: on ESP8266 the WebSocket transport is always unvalidated — use an ESP32, or ESP8266 in HTTP mode with a fingerprint.

Hardware

Supported boards

Any ESP32 — the original plus the S2, S3, C3, C6, and H2 variants — or ESP8266. That covers common DevKits, the XIAO ESP32-C3/S3, Arduino Nano ESP32, Seeed ESP32 boards, NodeMCU, and the Wemos D1 mini.

Boards that reach WiFi through a coprocessor (Raspberry Pi Pico W, Arduino UNO R4 WiFi, WiFiNINA) and cellular modules aren't supported yet — point those at nodrix over plain HTTPS instead.

Reference

API reference

addAP(ssid, pass) Register a WiFi network before begin()
begin(ssid, pass, host, token[, port]) Connect over WebSocket
begin(host, token[, port]) WebSocket, using the addAP() networks
beginHTTP(ssid, pass, host, token[, port]) HTTP mode
beginHTTP(host, token[, port]) HTTP mode, using the addAP() networks
run() WebSocket: pump the socket and flush telemetry; call every loop()
poll() HTTP: send readings, fetch and apply control; call on wake
send(var, value) Stage a metric (bool/int/long/float/double/const char*/String)
flush() Transmit staged metrics now
event(name) / event(name, payload) Fire a server-side event
connected() Whether the link is up
onConnect(cb) / onDisconnect(cb) Connection callbacks
setInsecure() Skip certificate validation (default)
setCACert(pem) Pin a root CA (ESP32)
setFingerprint(fp) Pin a SHA-1 fingerprint (ESP8266 HTTP)
setDebug(on) Log connection and protocol activity to Serial
NODRIX_WRITE("var") { … } Handle a cloud write; value is in scope

Full configuration — a secret.h for credentials and addAP() for multiple networks:

#define WIFI_SSID "your-wifi"
#define WIFI_PASS "your-password"
#define HOST      "yourproject.workers.dev"   // Nodrix host, no https://
#define TOKEN     "your-project-token"         // Settings -> Tokens
Nodrix.addAP("home-ssid", "home-pass");
Nodrix.addAP("workshop-ssid", "workshop-pass");
Nodrix.begin(HOST, TOKEN);   // no ssid/pass — uses the list above

FAQ

Which boards does the Nodrix Arduino library support?

Every ESP32 — the original plus the S2, S3, C3, C6, and H2 variants — and ESP8266. That covers common DevKits, the XIAO ESP32-C3/S3, Arduino Nano ESP32, Seeed ESP32 boards, NodeMCU, and Wemos D1 mini. Boards that reach WiFi through a coprocessor (Raspberry Pi Pico W, Arduino UNO R4 WiFi, WiFiNINA) and cellular modules aren’t supported yet — those talk to nodrix over plain HTTPS instead.

How do I install the Nodrix Arduino library?

In the Arduino IDE, search "Nodrix" in the Library Manager and install it (it pulls in ArduinoJson and WebSockets). In PlatformIO, add decoded-cipher/Nodrix to lib_deps. Then include it with #include <Nodrix.h>.

Do I have to use the library to connect an ESP32 to nodrix?

No. The device protocol is plain HTTPS and WebSocket with JSON, so any board or language can talk to nodrix directly. The library is optional — it exists to remove the WiFi, TLS, JSON, ack, and reconnect boilerplate on ESP32/ESP8266, where hand-writing it is the most painful.

Should I use the WebSocket or HTTP transport?

Use the always-on WebSocket (Nodrix.begin) for mains-powered controllers that need instant control — the socket hibernates on Cloudflare, so an idle connection costs almost nothing. Use HTTP polling (Nodrix.beginHTTP, then Nodrix.poll() each wake) for battery devices that wake, report, and deep-sleep. The same NODRIX_WRITE handlers work in both modes.

What happens to a command sent while the device is offline or asleep?

It waits. Control delivery is at-least-once: the cloud holds a write until the device acknowledges it and re-delivers anything outstanding on the next connect or poll. The library acks every write it delivers, reconnects on its own, and seeds control variables so the cloud will queue writes to them — so a command sent during a nap still lands.

How do I turn on TLS certificate validation?

By default the library connects encrypted but unverified — the fastest path to a first working device. To pin, call Nodrix.setCACert(pem) before begin() on ESP32 (WebSocket and HTTP), or Nodrix.setFingerprint(fp) on ESP8266 in HTTP mode. The repo README includes the openssl command to fetch your host’s root CA.

Deploy the cloud your board talks to

Nodrix is free and open source — deploy it to your own Cloudflare account, then point an ESP32 at it with this library.

One-click deploy provisions everything into your own Cloudflare account — nothing leaves it.