Dead simple IoT data ingestion and device control for ESP32-C3 boards.
- Simple, beginner-friendly API
- Command handling - Receive and execute commands from the cloud
- Pulse commands - Non-blocking timed actions (pumps, buzzers, etc.)
- Automatic retry logic with exponential backoff
- Helpful error messages with debugging tips
- Built-in WiFi connection checking
- Support for schema-based validation
- Inventronix ESP32-C3 board
- USB cable for programming
- WiFi network
- Arduino IDE 1.8.x or later, OR
- PlatformIO
- Inventronix Connect - IoT platform
- Download this library as a ZIP file
- In Arduino IDE: Sketch > Include Library > Add .ZIP Library
- Select the downloaded ZIP file
- Install the ArduinoJson library:
- Tools > Manage Libraries
- Search for "ArduinoJson"
- Install version 6.x or later
Add to your platformio.ini:
lib_deps =
bblanchon/ArduinoJson@^6.21.0#include <WiFi.h>
#include <Inventronix.h>
#include <ArduinoJson.h>
// WiFi credentials
#define WIFI_SSID "your-wifi-ssid"
#define WIFI_PASSWORD "your-wifi-password"
// Inventronix credentials (from https://inventronix.club/iot-relay/projects)
#define PROJECT_ID "proj_abc123"
#define API_KEY "key_xyz789"
Inventronix inventronix;
void setup() {
Serial.begin(115200);
// Connect to WiFi
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
// Initialize Inventronix
inventronix.begin(PROJECT_ID, API_KEY);
}
void loop() {
// Create JSON payload
JsonDocument doc;
doc["temperature"] = 23.5;
doc["humidity"] = 65.2;
String jsonPayload;
serializeJson(doc, jsonPayload);
// Send to Inventronix
bool success = inventronix.sendPayload(jsonPayload.c_str());
if (success) {
Serial.println("Data sent!");
}
delay(60000); // Wait 1 minute
}Commands are triggered by rules you configure in the Inventronix dashboard. When conditions are met (e.g., "temperature > 30"), the server queues commands that your device receives on the next sendPayload() call.
For on/off controls like heaters, lights, or relays:
int heaterState = 0; // Track actual hardware state
void setup() {
// ... WiFi setup ...
inventronix.begin(PROJECT_ID, API_KEY);
// Register command handlers
inventronix.onCommand("heater_on", [](JsonObject args) {
digitalWrite(HEATER_PIN, HIGH);
heaterState = 1;
});
inventronix.onCommand("heater_off", [](JsonObject args) {
digitalWrite(HEATER_PIN, LOW);
heaterState = 0;
});
}
void loop() {
JsonDocument doc;
doc["temperature"] = readTemp();
doc["heater_on"] = heaterState; // Report actual state
String json;
serializeJson(doc, json);
inventronix.sendPayload(json.c_str()); // Commands auto-dispatch
delay(10000);
}For momentary actions like pumps, buzzers, or motors that need to run for a set duration then stop automatically. Non-blocking - uses hardware timers so your loop keeps running.
#define PUMP_PIN 5
void setup() {
// ... WiFi setup ...
inventronix.begin(PROJECT_ID, API_KEY);
// Simple: pulse pin HIGH for 5 seconds
inventronix.onPulse("pump_nutrients", PUMP_PIN, 5000);
}
void loop() {
JsonDocument doc;
doc["ec_level"] = readEC();
doc["pump_on"] = inventronix.isPulsing("pump_nutrients") ? 1 : 0;
String json;
serializeJson(doc, json);
inventronix.sendPayload(json.c_str());
delay(10000);
}Duration from server: Omit the duration to pull it from the command's arguments.duration:
// Server sends: {"command": "pump_nutrients", "arguments": {"duration": 3000}}
inventronix.onPulse("pump_nutrients", PUMP_PIN); // Uses args.durationCustom callbacks: For complex logic:
inventronix.onPulse("dispense", 5000,
[]() { digitalWrite(PUMP_PIN, HIGH); Serial.println("Pump ON"); },
[]() { digitalWrite(PUMP_PIN, LOW); Serial.println("Pump OFF"); }
);If a pulse command fires while already pulsing, it's ignored. This prevents issues when rules trigger faster than the action completes.
Inventronix inventronix;Creates a new Inventronix client instance.
void begin(const char* projectId, const char* apiKey)Initialize the library with your project credentials.
Parameters:
projectId: Your Inventronix project ID (from dashboard)apiKey: Your API key (from project settings)
Example:
inventronix.begin("proj_abc123", "key_xyz789");bool sendPayload(const char* jsonPayload)Send JSON data to the Inventronix platform.
Parameters:
jsonPayload: JSON string to send
Returns:
trueif successfulfalseif failed (error details printed to Serial)
Example:
bool success = inventronix.sendPayload("{\"temp\":23.5}");void setSchemaId(const char* schemaId)Set the schema ID for validation (optional).
Parameters:
schemaId: Schema ID from your Inventronix project
Example:
inventronix.setSchemaId("schema_xyz");void onCommand(const char* commandName, CommandCallback callback)Register a handler for toggle-style commands.
Parameters:
commandName: The command name to listen for (matchescommandfield from server)callback: Function called when command received, signature:void(JsonObject args)
Example:
inventronix.onCommand("light_on", [](JsonObject args) {
int brightness = args["brightness"] | 100; // Default 100 if not provided
analogWrite(LED_PIN, brightness);
});void onPulse(const char* commandName, int pin, unsigned long durationMs = 0)Register a pulse command that toggles a pin HIGH for a duration, then LOW.
Parameters:
commandName: The command name to listen forpin: GPIO pin to pulse (automatically configured as OUTPUT)durationMs: Pulse duration in milliseconds. If 0, pulls fromargs.duration
Example:
inventronix.onPulse("buzzer_alert", BUZZER_PIN, 1000); // 1 second beepvoid onPulse(const char* commandName, unsigned long durationMs,
PulseOnCallback onCb, PulseOffCallback offCb)Register a pulse command with custom on/off callbacks.
Parameters:
commandName: The command name to listen fordurationMs: Duration between on and off callbacks. If 0, pulls fromargs.durationonCb: Function called when pulse startsoffCb: Function called when pulse ends
Example:
inventronix.onPulse("motor_jog", 2000,
[]() { motor.forward(); },
[]() { motor.stop(); }
);bool isPulsing(const char* commandName)Check if a pulse command is currently active.
Parameters:
commandName: The pulse command name to check
Returns:
trueif the pulse is currently runningfalseif not pulsing or command not found
Example:
doc["pump_active"] = inventronix.isPulsing("pump_nutrients") ? 1 : 0;void setRetryAttempts(int attempts)Set the number of retry attempts (default: 3).
void setRetryDelay(int milliseconds)Set the initial retry delay in milliseconds (default: 1000).
void setVerboseLogging(bool enabled)Enable/disable verbose logging (default: true).
void setDebugMode(bool enabled)Enable/disable debug mode with full HTTP request/response logging (default: false).
The library provides helpful error messages for common issues:
Your data doesn't match the schema. Check your schema definition at the provided URL.
Your PROJECT_ID or API_KEY is incorrect. Double-check your credentials.
You've exceeded the rate limit. The library will automatically retry with exponential backoff.
Temporary server issues. The library will automatically retry.
See src/main.cpp for a complete hydroponic controller example with:
- Temperature/humidity monitoring
- Toggle commands (heater on/off)
- Pulse commands (nutrient pump)
Make sure you call WiFi.begin() and wait for connection before sending data:
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}Verify your PROJECT_ID and API_KEY are correct. Get them from: https://inventronix.club/iot-relay/projects
- Check USB cable connection
- Try holding the BOOT button while uploading
- Verify correct board selected in Arduino IDE
The library is designed for embedded systems with limited memory:
- Uses efficient C-style strings for function parameters
- Minimal heap allocation
- Up to 16 toggle commands + 8 pulse commands (configurable in
Inventronix.h) - Typical usage: ~12% RAM, ~68% Flash on ESP32-C3
MIT License - see LICENSE file for details
- Documentation: https://docs.inventronix.io
- Issues: https://github.com/inventronix/inventronix-arduino/issues
- Email: support@inventronix.io
Contributions are welcome! Please open an issue or pull request on GitHub.