Wire it. Register it. Read it. Three commands, any sensor - all over NATS.
Doesn't matter if it's a $0.50 thermistor or a $6 BME280. The workflow is always the same.
4 wires for I2C (3.3V, GND, SDA, SCL). 3 wires for analog (3.3V, GND, signal). Same pins every time.
ionode device add ionode-01 temp i2c_bme280 --channel 0 --unit C --i2c-addr 118
ionode read ionode-01 temp → 23.5 C
✓ Readable via CLI, NATS, web UI, and dashboard ✓ EMA-smoothed for stable readings ✓ History recorded every 5 minutes (sparkline) ✓ Threshold events with edge detection ✓ Persisted across reboots ✓ Discoverable by other tools (OpenClaw, scripts, etc.) All automatic. Zero config.
Raw Wire.h drivers. No external libraries. Under 18KB flash total. Five sensor families built in.
The king of environmental sensors. Temperature, humidity, and barometric pressure from one chip.
Calibrated ambient light in lux. One channel, one address, dead simple.
High-accuracy temperature and humidity. Slightly more precise than BME280 for humidity.
16-bit ADC with 4 channels. When the ESP32's 12-bit ADC isn't enough. Soil moisture, gas sensors, anything analog.
The escape hatch. Read any register, set address, length, and scale. Hundreds of sensors - no firmware update needed.
NTC thermistors ($0.50, Steinhart-Hart, EMA-smoothed) and LDRs (light level as 0–100%). One resistor, two wires.
$ ionode i2c ionode-01 scan ━━ I2C Scan · ionode-01 ADDR HEX COMMON DEVICE ──────────────────────────────────────── 35 0x23 BH1750 60 0x3C SSD1306 OLED 118 0x76 BME280 3 device(s) found
Plug in a sensor. Scan the bus. IOnode tells you what's there.
A live dashboard on a $3 screen. Two controllers, same template engine with auto-refresh. No code.
128×64 pixels · 8 lines × 21 chars · refreshes every 5 seconds
# Register display with a live template $ ionode device add ionode-01 screen ssd1306 0 --i2c-addr 60 \ --template "{name} {ip}\nT:{bme_temp}C H:{bme_humi}%\nUp:{uptime} {heap}KB" Tokens auto-resolve to live sensor values: {bme_temp} → current reading of the bme_temp sensor {ip} → node IP address {uptime} → time since boot {heap} → free memory in KB {name} → device name # Or send raw text anytime $ ionode write ionode-01 screen "!Hello World" ✓ screen ← Hello World
Every I2C device connects the same way. Multiple sensors share one bus.
ESP32 BME280 ───── ────── 3.3V ────────── VCC GND ────────── GND SDA ────────── SDA SCL ────────── SCL
ESP32 BME280 SSD1306/SH1106 ───── ────── ────────────── 3.3V ────── VCC ───── VCC GND ────── GND ───── GND SDA ────── SDA ───── SDA SCL ────── SCL ───── SCL
| ESP32-C6 | SDA: GPIO 6 · SCL: GPIO 7 |
|---|---|
| ESP32-S3 | SDA: GPIO 8 · SCL: GPIO 9 |
| ESP32-C3 | SDA: GPIO 4 · SCL: GPIO 6 |
| Classic ESP32 | SDA: GPIO 21 · SCL: GPIO 22 |
Fixed per chip. Auto-detected. No configuration.
BME280 + OLED display on the same I2C bus. Complete setup.
# Register the BME280 channels $ ionode device add ionode-01 bme_temp i2c_bme280 --channel 0 --unit C --i2c-addr 118 + bme_temp i2c_bme280 I2C 0x76 ch0 $ ionode device add ionode-01 bme_humi i2c_bme280 --channel 1 --unit % --i2c-addr 118 + bme_humi i2c_bme280 I2C 0x76 ch1 $ ionode device add ionode-01 bme_pres i2c_bme280 --channel 2 --unit hPa --i2c-addr 118 + bme_pres i2c_bme280 I2C 0x76 ch2 # Register the OLED with a live template $ ionode device add ionode-01 display ssd1306 0 --i2c-addr 60 \ --template "T:{bme_temp}C H:{bme_humi}%\nP:{bme_pres}hPa\n\n{name} {ip}\nUp:{uptime}" + display ssd1306 I2C 0x3C Done. Live readings on the OLED. Auto-refreshes. Survives reboots.
Debug the bus remotely. No serial cable needed.
| ionode i2c scan | Find every device on the bus |
|---|---|
| ionode i2c detect <addr> | Check if a specific address responds |
| ionode i2c read <addr> | Read register bytes |
| ionode i2c write <addr> | Write register bytes |
| ionode i2c recover | Bus stuck? 9× SCL toggle to unstick it |
Every I2C operation is also a NATS subject: {name}.hal.i2c.scan, {name}.hal.i2c.{addr}.read, etc.
Digital input → 0 or 1
ADC → 0–4095 (12-bit)
Thermistor → °C (Steinhart-Hart)
Photoresistor → 0–100%
Chip temperature (no hardware)
Current hour 0–23 (NTP)
Current minute 0–59
Combined HHMM (1430 = 2:30 PM)
Subscribes to a NATS subject
UART line → numeric value
Temp / humidity / pressure
Ambient light (lux)
Temp / humidity (high accuracy)
16-bit ADC (4 channels)
Any I2C register + scale
High or low
With inversion
0–255 duty
0xRRGGBB
OLED text display
OLED text display