Quantum Saltwell Telemetry With Esp32 And Nats
Written by
Sky
Overview
This article covers a small, self-contained IoT pattern: a device publishes quantum saltwell telemetry events to a NATS message broker using an ESP32. The telemetry includes a monotonically increasing sequence number, a device timestamp, a 16-byte “saltwell nonce,” and a simulated sensor payload derived from on-device readings.
NATS is used for lightweight pub/sub. The ESP32 publishes to a subject named telemetry.saltwell.v1.
Hardware and Software
Hardware
- ESP32 dev board
- USB cable
- NATS server reachable from the ESP32 network
Software
- Arduino framework for ESP32
- Libraries:
WiFi.hArduinoJson.hWiFiClient.h
The code below uses a minimal TCP publish over the NATS protocol (no TLS, plain TCP). For production deployments, use TLS and proper credentials.
NATS Protocol Primer (Minimal Publish)
For a NATS server, a publish command in the plain protocol looks like:
PUB <subject> <reply-to> <#bytes>\r\n<payload>\r\n
The reply-to field can be empty (_ is sometimes used in examples, but empty is valid for no reply).
ESP32 Publisher (Arduino)
#include <WiFi.h> #include <WiFiClient.h> #include <ArduinoJson.h> static const char* WIFI_SSID = "YOUR_SSID"; static const char* WIFI_PASS = "YOUR_PASSWORD"; static const char* NATS_HOST = "192.168.1.50"; static const uint16_t NATS_PORT = 4222; WiFiClient client; uint64_t seqNo = 0; String randHex16() { static const char* hex = "0123456789abcdef"; uint8_t b[16]; for (int i = 0; i < 16; i++) b[i] = (uint8_t)(esp_random() & 0xFF); char out[33]; for (int i = 0; i < 16; i++) { out[i * 2] = hex[(b[i] >> 4) & 0x0F]; out[i * 2 + 1] = hex[b[i] & 0x0F]; } out[32] = '\0'; return String(out); } uint32_t msNow() { // Milliseconds since boot; sufficient for telemetry correlation. return (uint32_t)millis(); } bool natsConnect() { if (client.connected()) return true; if (!client.connect(NATS_HOST, NATS_PORT)) return false; // Read server INFO line (ends with \r\n). Not strictly needed for PUB, // but consuming it keeps stream state sane. uint32_t start = millis(); while (client.connected() && (millis() - start) < 2000) { if (client.available()) { String line = client.readStringUntil('\n'); if (line.startsWith("INFO")) return true; break; } delay(10); } return true; } bool natsPublish(const char* subject, const String& payload) { if (!natsConnect()) return false; // PUB <subject> [reply-to] <#bytes>\r\n<payload>\r\n // Use empty reply-to by omitting token is not valid; NATS expects tokens. // Use "-" as reply-to placeholder. String cmd = String("PUB ") + subject + " - " + payload.length() + "\r\n" + payload + "\r\n"; size_t written = client.write((const uint8_t*)cmd.c_str(), cmd.length()); client.flush(); return written == cmd.length(); } void setup() { Serial.begin(115200); delay(200); WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASS); uint32_t start = millis(); while (WiFi.status() != WL_CONNECTED && (millis() - start) < 15000) { delay(250); } // NATS connection is established on demand by natsPublish(). } void loop() { // Simulated sensor payload: convert ADC reading to a stable-looking metric. // GPIO34 is input-only on many ESP32 boards; adjust pin if needed. int raw = analogRead(34); float scaled = (float)raw * (3.30f / 4095.0f); // Build JSON payload. StaticJsonDocument<256> doc; doc["type"] = "saltwell.telemetry"; doc["seq"] = seqNo++; doc["t_ms"] = msNow(); doc["nonce"] = randHex16(); doc["payload"] = scaled; // Example: a voltage-like scalar String payload; serializeJson(doc, payload); bool ok = natsPublish("telemetry.saltwell.v1", payload); // Backoff on failures; NATS server may be unavailable. if (!ok) { delay(2000); } else { delay(750); } }
NATS Subscriber (Node.js)
A matching subscriber prints incoming telemetry and validates JSON.
Install and Run
npm init -y npm i nats node subscriber.js
subscriber.js
import { connect, StringCodec } from "nats"; const nc = await connect({ servers: "nats://192.168.1.50:4222" }); const sc = StringCodec(); const sub = nc.subscribe("telemetry.saltwell.v1"); console.log("Subscribed to telemetry.saltwell.v1"); for await (const msg of sub) { const text = sc.decode(msg.data); const obj = JSON.parse(text); console.log({ seq: obj.seq, t_ms: obj.t_ms, nonce: obj.nonce, payload: obj.payload, }); }
Concluding Notes
The presented implementation demonstrates a compact IoT telemetry pipeline where an ESP32 publishes JSON events to NATS using plain TCP and a Node.js subscriber consumes the stream in real time. The resulting design separates device telemetry production from downstream processing through subject-based pub/sub, enabling resilient message routing and straightforward verification of event fields and sequencing.