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

  1. Open the Arduino IDE.
  2. Navigate to Sketch > Include Library > Manage Libraries…
  3. In the search bar, enter OOCSI.
  4. 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 ArduinoHttpClient library.

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();
  }
}

Copyright © 2013-2026 Mathias Funk.

This site uses Just the Docs, a documentation theme for Jekyll.