PlaiiinLightOS

Open firmware for ESP32 lamps

A tiny OS that turns a $5 microcontroller into an AI-aware, scriptable LED lamp. Flash it once, set it up from the web, drop it into your home — Home Assistant, Homebridge, Node-RED, or just a browser tab. Stays on your network. Never phones home.

Free, open, and yours to tinker with — Apache 2.0.

AI Compose Local-first Local JS Open API OTA Updates MQTT Multi-form
Build profiles

Pick a form, flash the binary.

One file per shape and chip. Grab the .bin that matches your board — classic ESP32 or ESP32-C3 — and flash it over USB with esptool. After that first flash every update goes over the air.

FormHardwareESP32ESP32‑C3
strip Linear strip · ring · rope — any 1D layout
display N×M matrix · flat wall panel
tower N×M matrix · table lamp
cube Multiple N×N faces · cube lamp
wormhole N× 24-LED rings · paired across rooms
rocket 184-LED strip · rocket form
Supported LEDsWS2812 / NeoPixel, SK6812 (RGB & RGBW), SK9822 / APA102 — SPI+DMA driven for flicker-free rendering with WiFi active.
Supported ESP32Classic ESP32 dev boards — ESP32 D1 mini and friends — plus ESP32-C3. Per-chip binaries ship with every release.
First flash via USB, then OTA forever.

Once the initial *-flash.bin is on the chip, every subsequent update can be pushed wirelessly through /ota in any browser or through the POST /api/ota endpoint. Dual OTA partitions give you a free rollback on failure.

Features

Everything a modern lamp needs.

Designed around AI from the ground up — combined with the good old features any decent lamp should have.

AI ComposeDescribe a pattern in plain words — “slow aurora”, “fire crackling in a corner” — and the AI writes the JS that drives the LEDs. Iterate live; preview every frame before shipping it to the lamp.
AI IntegrationBring your own Claude or GPT key, or point the lamp at a local LLM running on your laptop. No vendor lock-in, no telemetry — your prompts never leave the model you picked.
Local-first, no cloudEvery feature works offline, on your LAN, without an account. The firmware never reaches out to a vendor server — there isn't one.
Local JS scriptsWrite effects in a tiny shade() DSL; the firmware compiles them to bytecode for fast on-device playback. Save, edit, play — all without a server.
GIF & image streamingDrop a GIF; the matrix becomes a tiny screen. Per-frame mapping with serpentine row order.
Built-in web UIEvery lamp serves its own day/night-themed control portal at /control, /compose, /stream, /js, and /config. No app required.
Open APIHTTP REST, WebSocket pixel streaming, BLE GATT — every transport documented as a stable contract. Build a client in any language.
Pairing & securityOptional token-based pairing locks the lamp to one client. BLE Just-Works bonding, encrypted writes, factory-reset flows. Off by default; opt in when you need it.
SharingMint role-scoped share keys (user / creator / admin). Hand them out via QR or over Bluetooth client-to-client. Revoke any time.
OTA updatesWireless firmware flashing with dual partitions and automatic rollback. NVS config survives every update.
MQTTSpeaks Home Assistant, Node-RED, Homebridge, anything that talks MQTT. Power, color, brightness topics; LWT-aware.
Multi-formTowers, wormholes, walls, cubes, rockets — same firmware, different profiles. Same APIs, same scripts, different shape.
For developers

Build your own client.

The wire contract between client and lamp is open and stable. HTTP for control, WebSocket for streaming, BLE for onboarding — pick the transports your project needs and target the spec directly. The firmware doesn't care whether the bytes come from our app, a CLI, or your own SDK.

Protocol spec

Canonical HTTP, WebSocket, and BLE contract. Versioned, additive within a major.

docs/protocol.md →

Role & sharing model

Bearer tokens, user / creator / admin roles, share-key endpoints. Multi-tenant from day one.

docs/sharing-api.md →

Firmware source under Apache 2.0 lives next to these docs in the repository.