![]() |
|
Uniot Core
|
| 0.9.0 |
Uniot Core is a lightweight, open-source framework for building IoT devices on ESP8266 and ESP32 microcontrollers. It handles the heavy lifting of task scheduling, network management, and device communication, letting you focus on what makes your device unique. With an embedded Lisp interpreter for runtime scripting and a developer-friendly API, Uniot Core gives you both flexibility and control.
From home automation to custom devices and prototypes, Uniot Core simplifies the development process while providing the power and reliability needed for production deployments.
setTimeout, setInterval and setImmediateSee the reference for how each of these is used.
| Family | Boards |
|---|---|
| ESP8266 | ESP-12E, ESP-12F, NodeMCU, Wemos D1 Mini |
| ESP32 | ESP32 DevKit, ESP32-C3, ESP32-S2, ESP32-S3 |
Ready-made build environments live in platformio.ini as ESP12E, ESP32 and ESP32C3. The framework targets the Arduino core and requires C++17.
Install PlatformIO:
Create a new project:
Configure platformio.ini:
Platform and Framework: Ensure that the platform and framework settings match your microcontroller (e.g., espressif8266 for ESP8266 or espressif32 for ESP32).
Every flag is described under Configuration. UNIOT_CREATOR_ID is the only required one — the build fails without it.
Build and upload:
Here's a minimal example to get you started with Uniot Core:
(dwrite 0 ...)Note: Call at least one
configWiFi*method beforeUniot.begin()— that is what creates the network controller. Without it there is no status LED, reset button, or WiFi status events. A device with neither button nor LED can still create it withconfigWiFiResetOnReboot().
Scripts are written in UniotLisp, delivered over MQTT, and run without reflashing. Your sketch decides what they can reach:
Pins are not addressed by GPIO number. Each registerLisp* call assigns its pins a 0-based index in registration order, per primitive, and scripts use that index — so (dwrite 0 #t) drives whichever pin was registered first as a digital output. This is what lets one script run on boards with different pin maps. Registering again replaces the previous set rather than adding to it, so list every pin in a single call.
Each directory is a self-contained PlatformIO project.
| Example | Hardware | Shows |
|---|---|---|
| WittyCloud | WittyCloud ESP8266 board | RGB output, light sensor, button, everything exposed to scripts |
| My9231Lamp | ESP8266 smart bulb with a MY9231 LED driver | A custom Lisp primitive, and a device with no button or status LED |
| S20Socket | ESP8266 smart socket or relay board | Relay control and a scriptable GPIO |
| LispHooks | Any ESP8266 board | Powering a sensor from the script lifecycle hooks |
| Buttons | WittyCloud ESP8266 board | Two buttons exposed to scripts, and clearing stale presses |
Configure Uniot Core behavior through build flags in platformio.ini:
lib/Core/Common.h carries a default for every value below, so define one only to override it:
| Flag | Default | Purpose |
|---|---|---|
UNIOT_MQTT_HOST | "mqtt.uniot.io" | Broker to connect to |
UNIOT_MQTT_PORT | 1883 | Broker port |
UNIOT_WIFI_AP_PREFIX | "UNIOT" | SSID prefix of the configuration portal |
UNIOT_WIFI_AP_PASSWORD | "" (open) | Password for that portal |
UNIOT_WIFI_NO_SLEEP | 0 | Disable WiFi modem sleep |
UNIOT_WIFI_REBOOT_RESET_COUNT | 5 | Power cycles that clear stored credentials, once configWiFiResetOnReboot() enables it |
UNIOT_WIFI_REBOOT_WINDOW_MS | 10000 | How long a reboot still counts towards that |
UNIOT_LISP_HEAP | 24576 (ESP32) / 12288 (ESP8266) | Interpreter heap, in bytes |
UNIOT_LISP_MAX_EVAL_STACK | 3072 (ESP32) / 1280 (ESP8266) | Evaluation stack budget, in bytes |
The two Lisp values were measured against the full firmware rather than chosen, and the ESP8266 numbers have little room: the old 1280 budget's predecessor ran 112 bytes from a stack overflow. Raise UNIOT_LISP_MAX_EVAL_STACK only with a measurement from tools/LispEvalDepth on the same board and build.
To disable logging entirely, set UNIOT_LOG_ENABLED=0 — there is no "none" level.
Uniot Core automatically manages these dependencies:
tools/ holds standalone PlatformIO sketches that measure interpreter behaviour on real hardware — LispEvalDepth reports how much stack an evaluation consumes, and LispGC exercises the collector under memory pressure. Each is its own project, built from its own directory:
These are measuring instruments, not a test suite: they print numbers for a human to read, and the eval-stack and heap budgets in lib/Core/Common.h were set from their output.
./scripts/generate_docs.shWe welcome contributions! Here's how you can help:
Branch from master, keep the existing code style, add Doxygen comments for new APIs, and say in the description which boards you tested on.
This project is licensed under the GNU General Public License v3.0 - see the [LICENSE](LICENSE) file for details.