View examples on GitHubgithub.com / TexhFexLabs / HydroNode-Library→

Get the Sensor ID and Secret

The library signs every request with your sensor's credentials. Create the sensor first (Integration Guide, step 01), then copy them:

  1. 1
    Open the sensor
    On the Dashboard, click the sensor's name in the device list.
  2. 2
    Open its settings
    Press Settings at the top right, then Connection on the left.
  3. 3
    Copy both
    Under Direct connection you find the Sensor ID and the Secret, each with a copy button.
Connection settings of a sensor with the Sensor ID, a hidden Secret and Replace secretConnection settings of a sensor with the Sensor ID, a hidden Secret and Replace secret
Settings, Connection: Sensor ID and Secret for the direct connection.
The Secret authenticates every request. Keep it on the device, never publish it and never commit it to source control. If it leaks, press Replace secret on the same page and flash the new one.

Install the library

The library is in the official Arduino Library Manager. Open Tools → Manage Libraries, search for HydroNode-Library and install it. The IDE offers to install the dependencies along with it: say yes. For reference, these are:

ArduinoJson
JSON parsing, version 7
ArduinoJson
ArduinoHttpClient
HTTP client for Arduino
ArduinoHttpClient
WiFiManager
Only for the captive portal example
WiFiManager

In PlatformIO, pin the Git tag. The registry does not always carry the newest version right away:

platformio.ini
[env:esp32dev]
platform = espressif32
board = esp32dev
framework = arduino
monitor_speed = 115200
lib_deps =
  https://github.com/TexhFexLabs/HydroNode-Library.git#1.8.0

Or clone the repository into your libraries/ folder and install the dependencies above by hand:

shell
git clone https://github.com/TexhFexLabs/HydroNode-Library.git ~/Arduino/libraries/HydroNode

A complete .ino sketch

Fill in YOUR_WIFI_SSID, YOUR_WIFI_PASSWORD, your Sensor ID and your Secret, then upload. sendValues() sends every value of one round in a single signed request, stamped with the time it was measured. That saves one connection per value, which is several seconds on an ESP8266. The library fetches the time itself and refreshes it every 30 minutes.

arduino / C++
#include <HydroNode.h>

const char* WIFI_SSID     = "YOUR_WIFI_SSID";
const char* WIFI_PASSWORD = "YOUR_WIFI_PASSWORD";

// Settings > Connection on the sensor page
const char* SENSOR_ID  = "YOUR_SENSOR_ID";
const char* SECRET_KEY = "YOUR_SECRET";

HydroNode hydro(SENSOR_ID, SECRET_KEY);

// Command "pump" with type UINT32 from the HydroNode app
void pumpCallback(uint32_t ms) {
  if (ms > 10000) ms = 10000;  // never trust a network value blindly
  Serial.printf("Pump for %u ms\n", ms);
  // run the pump for ms milliseconds
}

void setup() {
  Serial.begin(115200);
  hydro.setDebug(Serial);  // optional: prints every request and answer

  while (!hydro.connectWiFi(WIFI_SSID, WIFI_PASSWORD)) {
    Serial.println("WiFi failed, retrying");
  }
  hydro.begin();  // fetches the time, needed for every signature

  hydro.onUInt32("pump", pumpCallback);
}

void loop() {
  // Replace with real readings from your hardware
  HydroNodeValue reading[] = {
    {"TEMPERATURE", 22.4},  // °C
    {"HUMIDITY",    65.2},  // %
  };
  int status = hydro.sendValues(reading, 2);
  Serial.printf("HydroNode answered %d\n", status);

  delay(60000);  // one round per minute
}

HydroNode accepts one value per measurement type every 10 seconds, and up to 64 values in one request. sendValue("TEMPERATURE", 22.4) still works for a single value.

Check that the values arrive

Open the serial monitor at 115200 baud. HydroNode answered 202 means accepted. Then open the sensor page in HydroNode and press the ` key. The device console shows every request the moment it arrives, with the signature check and how far the device clock is off.

The Live tab of the device console with accepted HTTP requestsThe Live tab of the device console with accepted HTTP requests
One line per request: time, status, values, signature check and clock offset.
AnswerMeaningWhat to do
202AcceptedNothing, all good.
401Signature or time wrongCheck the Sensor ID and Secret. The console names the exact reason.
429Too fastSend at most one value per measurement type every 10 seconds.
-1No WiFiCheck the network name, password and signal.
-2No timeAllow UDP port 123 (NTP) on your network.
-3Connection failedTLS or network error. The library tries again with the next round.
-4Invalid type nameUse upper case: TEMPERATURE, not temperature.
-5Invalid valueThe value is NaN or infinite. Check the sensor reading.

A rejected request shows up in red in the console, with the exact reason. The Rejected filter shows only those.

Send commands to the device

A command has a name, a value type and a value. On the device you register one callback per name and type. One name can have several types, for example relay1 true and relay1 1400.

BOOL
true or false
hydro.onBool(name, fn)
INT32
-2,147,483,648 to 2,147,483,647
hydro.onInt32(name, fn)
UINT32
0 to 4,294,967,295, hex like 0x20124 works
hydro.onUInt32(name, fn)
INT64
about ±9.2 × 10¹⁸
hydro.onInt64(name, fn)
UINT64
0 to about 1.8 × 10¹⁹, hex works
hydro.onUInt64(name, fn)
STRING
Any text up to 500 characters
hydro.onString(name, fn)
arduino / C++
// App: name "lamp", type BOOL, value true
hydro.onBool("lamp", [](bool on) {
  digitalWrite(LAMP_PIN, on ? HIGH : LOW);
});

// Same name, type UINT32: "lamp 1400" lights it for 1.4 s
hydro.onUInt32("lamp", [](uint32_t ms) {
  ms = min(ms, (uint32_t)10000);  // local safety limit
  digitalWrite(LAMP_PIN, HIGH);
  delay(ms);
  digitalWrite(LAMP_PIN, LOW);
});

// App: name "display", type STRING, value "Hello"
hydro.onString("display", [](const String& text) {
  lcd.print(text);
});
  1. 1
    Send it
    On the sensor page press Send command and fill in name, type and value. Or type lamp:bool true in the Commands tab of the console.
  2. 2
    Wait for the next round
    Commands travel with the answer to the next value the device sends. With one round per minute, that takes up to a minute.
  3. 3
    Read the status
    Confirmed means the device has a matching callback and started it. Declined names the reason and the callback never runs: No handler on the device when the name is unknown, Type does not match when the callback expects another type, Value not accepted when the value does not fit, for example -1 for UINT32.
The Commands tab of the device console with a prompt and sent commandsThe Commands tab of the device console with a prompt and sent commands
The Commands tab: type name, type and value, and follow each command's status.

Hex like 0x20124 is accepted for the integer types and arrives as the number 131364. There is no float type: send a whole number in a fixed unit, for example tenths of a degree. Commands are delivered at most once. If a response is lost, send the command again.

Confirmed means the device received the command, not that the pump actually ran. Values come over the network, so clamp them on the device to what your hardware can safely do, like the 10 second cap in the sketch above.

Protect a battery device

From library 1.8.0, HydroNodeBatteryGuard looks after the battery the same way HydroNode firmware does: it sends less often below Save, turns WiFi and outputs off below Radio off, sleeps an hour at a time below Standby and runs normally again from Resume. Before it goes quiet it sends one last round, so HydroNode shows Low battery standby instead of Offline.

With onSettings() the sketch also takes a new send interval and new thresholds that you change in HydroNode under Settings → Pressure and battery → On the device. The example PowerThresholds in the library shows the whole round, including deep sleep. Every threshold and rule is in Battery and Power.

Captive portal setup via WiFiManager

The example WiFiManagerSetup uses WiFiManager instead of a hardcoded network. On first boot the device opens an access point named HydroNode-Setup-XXXX (the last four characters of your Sensor ID, from hydro.getApName()). Connect to it from a phone or laptop, and a captive portal asks for your network. The device saves it to flash and restarts into normal operation. No password is compiled into the firmware.

All examples are in the library's examples/ folder on GitHub.

Make an outdoor sensor a station

If this board is part of an outdoor weather or environmental installation, it can become a station without changing the sketch or switching to LoRaWAN. A station has a location and can appear on the public map.

  1. 1
    Save the sensor as Outdoor
    On the sensor page open Settings → General, set Environment to Outdoor and save. Indoor sensors cannot be stations.
  2. 2
    Turn on Use as a station
    The switch sits in the Station group of the same section. The Sensor ID, the Secret and every reading stay as they are.
  3. 3
    Set the location
    Location and public map opens the station settings. Enter the location, and turn on Show on the public map only if you want others to see it.
Switching Use as a station off removes the location and the place on the map. The sensor and every reading stay.
The type name, such as TEMPERATURE, is case-sensitive. Always use the exact uppercase key. The library refuses names that are not upper case letters, digits and underscores (-4), and a typo like TEMPERATUR creates a new measurement instead of an error. See every type on the Sensor Types reference.