SDK for any device
Send readings from a Raspberry Pi, a Pico W with MicroPython, a Node.js gateway, a Go service or a shell script. One file per language, no dependencies. It signs every request the way HydroNode checks it and takes commands back.
Copy one file
Copy the file for your language from the repository above. No package manager, no dependencies. The SDK signs every request with your sensor's Sensor ID and Secret:
| Language | File | Runs on |
|---|---|---|
| Python | python/hydronode.py | Raspberry Pi, Linux, macOS, Windows (Python 3.8+) |
| MicroPython | python/hydronode.py | ESP32, ESP8266, Raspberry Pi Pico W |
| JavaScript | node/hydronode.mjs | Node.js 18+, Deno, Bun |
| Go | github.com/TexhFexLabs/hydronode-sdk/go | Go 1.21+ |
| Shell | shell/hydronode.sh | bash with curl and openssl |
Send a round
All values of one reading go out in one request. 202 means stored. Then open the sensor in HydroNode and press `: the device console shows the request, the signature check and how far your clock is off.
from hydronode import HydroNode
hydro = HydroNode("YOUR_SENSOR_ID", "YOUR_SECRET")
hydro.send_values({"TEMPERATURE": 21.5, "HUMIDITY": 48})import { HydroNode } from './hydronode.mjs';
const hydro = new HydroNode({ sensorId: 'YOUR_SENSOR_ID', secret: 'YOUR_SECRET' });
await hydro.sendValues({ TEMPERATURE: 21.5, HUMIDITY: 48 });client := hydronode.New("YOUR_SENSOR_ID", "YOUR_SECRET")
client.SendValues(ctx, hydronode.Values{{"TEMPERATURE", 21.5}, {"HUMIDITY", 48}})SENSOR_ID=... SECRET=... ./hydronode.sh send TEMPERATURE=21.5 HUMIDITY=48ntptime.settime()), because every request carries the time. Copy hydronode_roots.py along and pass ca=ROOTS, then the board checks the server certificate. Without it the connection is encrypted but not verified. CPython, Node and Go use the system certificates on their own.Store now, send later
record() keeps a reading with the time it was measured, flush() sends what is stored in one request, up to 100 rounds and 7 days back. Use it so a reading is never lost while the network is down, or to send once an hour from a battery device. A round sent twice is stored once.
hydro.load_buffer("buffer.json") # what waited before a restart
hydro.record({"TEMPERATURE": 12.3}) # no network needed
hydro.save_buffer("buffer.json")
try:
hydro.flush() # every stored round, each with its own time
except OSError:
pass # offline: the rounds stay for the next tryTake commands from HydroNode
A command has a name, a type and a value, for example pump, UINT32, 4000. It arrives with the answer to the next reading. The SDK confirms it to HydroNode before your handler runs, and declines what has no handler or the wrong type, so the app shows Confirmed or the reason.
def run_pump(ms):
ms = min(ms, 10000) # never trust a network value
pump_on(ms)
hydro.on("pump", run_pump, "UINT32")
hydro.on("lamp", lambda on: relay(on), "BOOL")
hydro.send_values({"WATER_LEVEL": 72}) # commands arrive with this answerComplete programs to start from
Each example runs as it is once Sensor ID and Secret are filled in, and explains every step in its comments.
| Example | What it shows |
|---|---|
python/examples/send_once.py | The smallest complete program |
python/examples/raspberry_pi_offline_safe.py | Raspberry Pi loop that never loses a reading (buffer file) |
python/examples/commands.py | Pump, lamp and text commands from HydroNode |
python/examples/micropython_esp32.py | MicroPython on ESP32 or Pico W: WiFi, NTP, verified TLS |
python/examples/micropython_collect_hourly.py | Battery: measure every 6 min, send 10 readings once an hour, deep sleep |
node/examples/send.mjs | One reading from Node.js |
node/examples/gateway.mjs | Forward readings from anywhere, buffered to a file, with commands |
go/examples/send/main.go | One reading and a command handler in Go |
shell/hydronode.sh | dry-run shows what would be signed, to find the cause of a 401 |
Any other language
If it can do HTTPS and HMAC-SHA256, it can talk to HydroNode. The full protocol is in PROTOCOL.md: every endpoint, answer and limit. In short:
X-Sensor-Id: <sensor id>
X-Timestamp: <Unix seconds, within 2 minutes of the server>
X-Signature: Base64(HMAC-SHA256(secret, canonical + X-Timestamp))
canonical: {"sensorId":"<id>","timestamp":<ts>,"values":[{"type":"TEMPERATURE","value":21.50}]}
POST https://hydronode.tech/api/webhook/sensor-values (the body is the canonical text)21.125 becomes 21.13, not the 21.12 that printf gives. Check your client against the shared test vectors (vectors/signature-vectors.json): HydroNode itself, the Arduino library and every SDK pass the same file.A walk through all of it, with a Raspberry Pi that never loses a reading and a Pico W on batteries: Send sensor data from Python, MicroPython, Node.js and Go. On an ESP32 with Arduino, the Arduino library does the same over WiFi, Ethernet and LTE-M.