Embedded OOCSI Client (ESP & Arduino)
The OOCSI-ESP library connects physical computing prototypes and microcontrollers directly to the OOCSI middleware over WiFi. It allows sensor nodes, actuators, wearables, and connected interactive products to exchange structured data with other devices, web dashboards, and Python/Processing applications.
Supported Hardware Platforms
While originally created for the ESP32 and ESP8266, the library supports several WiFi-enabled microcontroller platforms:
- ESP32 (all common variants: ESP32-WROOM, ESP32-S2/S3, ESP32-C3)
- ESP8266 (NodeMCU, Wemos D1 Mini)
- Arduino Nano 33 IoT (supported from v1.5.1+)
- Arduino UNO WiFi Rev2 (supported from v1.5.5+)
- Other WiFi-enabled Arduino-compatible boards
Installation
Via Arduino Library Manager (Recommended)
- Open the Arduino IDE.
- Navigate to Sketch > Include Library > Manage Librariesā¦
- In the search bar, enter OOCSI.
- Click Install.
Dependencies
- ArduinoJson: The library requires
ArduinoJson(version 6.x or higher). Install it via the Arduino Library Manager. - ArduinoHttpClient: If you are compiling for the Arduino Nano 33 IoT or Arduino UNO WiFi Rev2, you must also install the
ArduinoHttpClientlibrary.
Source code and releases are available on GitHub: iddi/oocsi-esp.
Connecting to OOCSI
#include "OOCSI.h"
// WiFi configuration
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
// OOCSI server address (hostname or IP)
const char* hostserver = "oocsi.example.com";
// Client handle
// IMPORTANT: Use '####' in the client name so the server replaces them with random digits,
// guaranteeing a unique connection name and avoiding collisions on reboot.
const char* OOCSIName = "sensor_node_####";
// Instantiate the OOCSI client
OOCSI oocsi = OOCSI();
// Forward declaration of incoming message handler
void processOOCSI();
void setup() {
Serial.begin(115200);
// Connect to WiFi and then to the OOCSI server
// Parameters: clientName, host, wifiSSID, wifiPassword, messageHandler
oocsi.connect(OOCSIName, hostserver, ssid, password, processOOCSI);
// Optional: subscribe to additional channels
oocsi.subscribe("lighting_channel");
}
The Main Loop: check() vs keepAlive()
In your loop() function, you must allow OOCSI to service incoming network events:
oocsi.check(): Use this when your device needs to receive and process incoming messages from subscribed channels.oocsi.keepAlive(): Use this lightweight alternative if your device only sends data and does not listen for incoming messages.
void loop() {
// Service the connection and process incoming messages
oocsi.check();
// Your sensor reading and logic here...
delay(100);
}
Sending Messages
To send data, begin a new message with oocsi.newMessage(), append key-value pairs using type-specific helper methods, and dispatch it with oocsi.sendMessage():
// Target can be a channel or an individual client handle
oocsi.newMessage("climate");
// Add key-value data of various types
oocsi.addFloat("temperature", 21.8);
oocsi.addInt("humidity", 58);
oocsi.addBool("fan_running", true);
oocsi.addString("location", "Studio Lab");
// Send the message
oocsi.sendMessage();
Supported Data Types
addInt(key, int_value)addLong(key, long_value)addFloat(key, float_value)addBool(key, bool_value)addString(key, string_value)
Receiving Messages
When a message arrives on a subscribed channel (or directly for this device), the callback function passed to connect() or subscribe() is invoked:
void processOOCSI() {
// Check whether a specific key is contained in the message
if (oocsi.has("power")) {
bool power = oocsi.getBool("power", false);
digitalWrite(LED_BUILTIN, power ? HIGH : LOW);
}
if (oocsi.has("brightness")) {
int brightness = oocsi.getInt("brightness", 0);
Serial.print("New brightness: ");
Serial.println(brightness);
}
}
Retrieving Values with Defaults
All getter methods accept an optional default value returned if the key is missing or cannot be converted:
oocsi.getInt("key", defaultValue)oocsi.getLong("key", defaultValue)oocsi.getFloat("key", defaultValue)oocsi.getBool("key", defaultValue)oocsi.getString("key", defaultValue)
Battery & Deep Sleep Strategies
For battery-powered IoT devices that enter deep sleep, use retained messages (_RETAIN) to pin sensor readings to the channel before sleeping:
// Publish reading pinned for 1 hour (3600 seconds)
oocsi.newMessage("garden_soil");
oocsi.addFloat("moisture", 42.1);
oocsi.addInt("_RETAIN", 3600);
oocsi.sendMessage();
// Flush and enter deep sleep for 10 minutes
delay(200);
ESP.deepSleep(10 * 60 * 1000000);
Complete Standalone Example
#include "OOCSI.h"
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
const char* hostserver = "oocsi.example.com";
const char* OOCSIName = "esp_sensor_####";
OOCSI oocsi = OOCSI();
void handleOOCSI() {
if (oocsi.has("led")) {
digitalWrite(LED_BUILTIN, oocsi.getBool("led", false) ? HIGH : LOW);
}
}
void setup() {
Serial.begin(115200);
pinMode(LED_BUILTIN, OUTPUT);
// Connect to WiFi and OOCSI
oocsi.connect(OOCSIName, hostserver, ssid, password, handleOOCSI);
// Subscribe to channel
oocsi.subscribe("device_controls");
}
unsigned long lastSend = 0;
void loop() {
oocsi.check();
// Send periodic sensor reading every 5 seconds
if (millis() - lastSend > 5000) {
lastSend = millis();
oocsi.newMessage("sensor_readings");
oocsi.addFloat("uptime_sec", millis() / 1000.0);
oocsi.addInt("analog_val", analogRead(34));
oocsi.sendMessage();
}
}