An offline BLE controller for Casambi lighting systems, running on ESP32. Control your Casambi lights without cloud dependency after initial setup.
- ✅ Hybrid WiFi/BLE Operation - One-time WiFi setup, then fully offline BLE control
- ✅ HTTP REST API - Control lights from home automation systems (Loxone, Home Assistant, etc.)
- ✅ Complete Protocol Support - Full Casambi Evolution protocol implementation
- ✅ Encrypted Communication - ECDH key exchange, AES-CTR encryption, CMAC authentication
- ✅ Scene Control - Activate and control scenes with full state restoration
- ✅ Unit Control - Individual light control (on/off, brightness, color, temperature)
- ✅ Group Control - Control multiple lights simultaneously
- 🚀 Auto-Connect - Automatically connects to your gateway on boot
- 🔧 Debug Toggle - Clean operation by default, verbose debugging when needed
- 💾 Persistent Storage - Configuration stored in LittleFS (survives reboots)
- 🔍 Auto-Discovery - Setup wizard scans and finds your Casambi network
Supported ESP32 Boards:
- AZDelivery ESP32 Dev Kit C V4 - Primary development board
- ESP32-C3 Super Mini - Compact alternative
- Any ESP32 board with BLE support
Additional Requirements:
- USB cable for programming and serial communication
- Casambi network with at least one BLE-enabled device
- PlatformIO (recommended) or Arduino IDE
-
Clone the repository:
git clone https://github.com/lian/esp32-casambi.git cd esp32-casambi -
Build and upload:
# For ESP32 Dev Kit V4 (default) pio run -t upload # For ESP32-C3 Super Mini pio run -e esp32-c3 -t upload
-
Open serial monitor:
pio device monitor --echo
On first boot, the device enters setup mode. Run the setup wizard:
> setup
The wizard will:
- Scan for nearby Casambi networks
- Auto-discover your network UUID from the device MAC
- Connect to WiFi (you provide credentials)
- Download network configuration from Casambi Cloud
- Save everything to flash
- Reboot into operation mode
After setup: WiFi stays connected to provide the HTTP REST API for home automation systems, while BLE handles all Casambi protocol communication.
scan # Scan for Casambi devices
connect 0 # Connect to first device found (auto-saves for next boot)
disconnect # Disconnect from deviceson 1 # Turn scene 1 ON
soff 1 # Turn scene 1 OFF
slevel 1 255 # Set scene 1 to full intensity
slevel 1 128 # Set scene 1 to 50% intensityuon 2 # Turn unit 2 ON
uoff 2 # Turn unit 2 OFF
ulevel 2 200 # Set unit 2 brightness to 200/255
ucolor 2 255 0 0 # Set unit 2 to red
utemp 2 3000 # Set unit 2 to warm white (3000K)
uvertical 2 200 # Set light balance (0=top only, 127=both, 255=bottom only)
uslider 2 200 # Set motor position (0=up, 255=down)glevel 1 128 # Set group 1 brightness to 50%
gvertical 1 200 # Set light balance (0=top only, 127=both, 255=bottom only)
gslider 1 200 # Set motor position (0=up, 255=down)status # Show connection status
refresh # Sync config from Casambi cloud
list units # Show all units
list groups # Show all groups
list scenes # Show all scenes
debug on/off # Toggle verbose debug output| Command | Description |
|---|---|
help |
Show all commands |
status |
Show connection status |
refresh |
Refresh config from Casambi cloud |
clearconfig |
Factory reset |
| BLE Commands | |
scan |
Scan for BLE devices |
connect <n> |
Connect to device number n |
disconnect |
Disconnect from device |
autoconnect on/off/status |
Auto-connect control |
autoconnect set <mac> |
Set MAC for auto-connect |
wifi status |
Show WiFi connection status |
wifi set <ssid> <password> |
Update WiFi credentials |
debug on/off/status |
Debug output control |
| Scene Commands | |
son <id> |
Activate scene |
soff <id> |
Deactivate scene |
slevel <id> <0-255> |
Set scene intensity |
| Unit Commands | |
uon <id> |
Turn unit on |
uoff <id> |
Turn unit off |
ulevel <id> <0-255> |
Set unit brightness |
ucolor <id> <r> <g> <b> |
Set unit RGB color (0-255 each) |
utemp <id> <kelvin> |
Set unit color temperature (e.g., 2700-6500K) |
uvertical <id> <0-255> |
Set unit motor position |
uslider <id> <0-255> |
Set unit top/bottom light balance (0=bottom, 127=middle, 255=top) |
| Group Commands | |
glevel <id> <0-255> |
Set group brightness |
gvertical <id> <0-255> |
Set group motor position |
gslider <id> <0-255> |
Set group top/bottom light balance |
| Info Commands | |
list units |
List all units |
list groups |
List all groups |
list scenes |
List all scenes |
Motor and Light Distribution Controls:
- Vertical (light balance): Controls light distribution between top and bottom emitters (0=top only, 127=both equally, 255=bottom only)
- Slider (motor position): Controls physical motor position (0=up, 255=down)
Note: The actual behavior of vertical/slider controls depends on your specific light fixtures. Different manufacturers map these Casambi protocol controls differently. The descriptions above reflect typical motorized lights with dual emitters. Test with your fixtures to verify behavior.
Auto-connect is enabled by default. Simply connect once and the MAC address is saved:
connect 0 # Connect to device (MAC address auto-saved)On next boot, the controller automatically reconnects to your Casambi gateway.
Disable auto-connect:
autoconnect off # Disable auto-connect
autoconnect on # Re-enable auto-connectControl output verbosity:
debug off # Clean operation (default) - only shows important messages
debug on # Verbose mode - shows packet details, encryption, noncesUpdate WiFi credentials without losing your Casambi configuration:
wifi status # Show WiFi connection status
wifi set MyNetwork MyPassword123 # Update WiFi credentialsThe wifi set command will:
- Save new credentials to flash
- Disconnect from current WiFi
- Connect to new network
- Restart the web server
- Display the new IP address
This is useful when:
- Your WiFi password changes
- You move the ESP32 to a different network
- You need to troubleshoot WiFi issues
If you add new lights, rename devices, or modify scenes in the official Casambi app, use the refresh command to sync:
refreshThe command will:
- Download fresh configuration from Casambi cloud
- Update all units, groups, and scenes
- Preserve your local settings (auto-connect, debug mode)
- Require your network password for authentication
This is useful when:
- Adding new lights to your Casambi network
- Renaming devices, groups, or scenes
- Modifying scene configurations
- Changes made by other users need to be synced
Note: You need WiFi connected. The command will auto-connect if WiFi credentials are saved.
The ESP32 provides a REST API for integration with home automation systems like Loxone, Home Assistant, Node-RED, and others.
After setup, the API is available at:
http://<esp32-ip>/api
The ESP32's IP address is displayed in the serial console on boot.
GET /api/status
curl http://192.168.1.100/api/status{
"ble_connected": true,
"network_name": "Home Lights",
"wifi_ssid": "MyNetwork",
"wifi_ip": "192.168.1.100",
"uptime_ms": 123456,
"gateway_mac": "connected"
}GET /api/units - List all light units
curl http://192.168.1.100/api/units{
"units": [
{"id": 1, "name": "Kitchen Ceiling", "address": "...", "online": true},
{"id": 2, "name": "Living Room", "address": "...", "online": true}
]
}GET /api/groups - List all groups
curl http://192.168.1.100/api/groupsGET /api/scenes - List all scenes
curl http://192.168.1.100/api/scenesPOST /api/scenes/:id/on - Activate scene
curl -X POST http://192.168.1.100/api/scenes/1/onPOST /api/scenes/:id/off - Deactivate scene
curl -X POST http://192.168.1.100/api/scenes/1/offPOST /api/scenes/:id/level - Set scene intensity (0-255)
curl -X POST http://192.168.1.100/api/scenes/1/level \
-H "Content-Type: application/json" \
-d '{"level": 128}'POST /api/units/:id/on - Turn unit on
curl -X POST http://192.168.1.100/api/units/2/onPOST /api/units/:id/off - Turn unit off
curl -X POST http://192.168.1.100/api/units/2/offPOST /api/units/:id/level - Set brightness (0-255)
curl -X POST http://192.168.1.100/api/units/2/level \
-H "Content-Type: application/json" \
-d '{"level": 200}'POST /api/units/:id/color - Set RGB color (0-255 each)
curl -X POST http://192.168.1.100/api/units/2/color \
-H "Content-Type: application/json" \
-d '{"r": 255, "g": 100, "b": 0}'POST /api/units/:id/temperature - Set color temperature (Kelvin)
curl -X POST http://192.168.1.100/api/units/2/temperature \
-H "Content-Type: application/json" \
-d '{"kelvin": 2700}'POST /api/units/:id/vertical - Set light balance (0-255)
curl -X POST http://192.168.1.100/api/units/2/vertical \
-H "Content-Type: application/json" \
-d '{"value": 127}'POST /api/units/:id/slider - Set motor position (0-255)
curl -X POST http://192.168.1.100/api/units/2/slider \
-H "Content-Type: application/json" \
-d '{"value": 200}'POST /api/groups/:id/level - Set group brightness (0-255)
curl -X POST http://192.168.1.100/api/groups/1/level \
-H "Content-Type: application/json" \
-d '{"level": 128}'POST /api/groups/:id/vertical - Set group light balance (0-255)
curl -X POST http://192.168.1.100/api/groups/1/vertical \
-H "Content-Type: application/json" \
-d '{"value": 127}'POST /api/groups/:id/slider - Set group motor position (0-255)
curl -X POST http://192.168.1.100/api/groups/1/slider \
-H "Content-Type: application/json" \
-d '{"value": 200}'Success:
{"success": true}Error:
{
"success": false,
"error": "Unit not found"
}Use Virtual HTTP Output commands:
Scene ON: http://192.168.1.100/api/scenes/1/on (POST)
Unit Dimmer: http://192.168.1.100/api/units/2/level (POST, body: {"level":<v>})
rest_command:
casambi_scene_on:
url: "http://192.168.1.100/api/scenes/{{ scene_id }}/on"
method: POST
casambi_unit_level:
url: "http://192.168.1.100/api/units/{{ unit_id }}/level"
method: POST
content_type: "application/json"
payload: '{"level": {{ level }}}'Use HTTP Request nodes with method POST and appropriate payloads.
Authentication Flow:
- BLE connection to Casambi gateway
- ECDH key exchange (SECP256R1)
- Derive transport key (SHA256 + XOR fold)
- Authenticate with session key
- Encrypted communication (AES-CTR + CMAC)
Encryption Details:
- Key Exchange: ECDH with SECP256R1 elliptic curve
- Encryption: AES-128-CTR mode
- Authentication: Manual CMAC-AES (RFC 4493)
- Packet Format: Big-endian operation packets
Cloud API:
- Initial setup downloads network configuration
- Stored locally in LittleFS flash filesystem
- Includes keys, units, groups, scenes
- No cloud dependency after setup
esp32-casambi/
├── src/
│ ├── main.cpp # Main application
│ ├── config.h # Configuration constants
│ ├── ble/ # BLE protocol implementation
│ ├── cloud/ # Casambi Cloud API client
│ ├── crypto/ # AES-CTR + CMAC + ECDH
│ └── storage/ # LittleFS configuration
├── platformio.ini
└── README.md
WiFi won't connect:
- Ensure 2.4 GHz network (ESP32 doesn't support 5 GHz)
- Check SSID and password
- Try moving closer to access point
Network not found during scan:
- Ensure Casambi device is powered on and in range
- Only gateway devices advertise via BLE
Authentication fails:
- Run
clearconfigand redo setup - Ensure correct Casambi network password
Auto-connect doesn't work:
- Check
autoconnect status - Try manual
connectfirst to save MAC address
Commands don't work:
- Check connection:
status - Verify device IDs:
list units,list scenes - Try reconnecting
The project includes optimized PlatformIO configurations:
Production Environments:
devkit-v4- ESP32 Dev Kit V4 (default)esp32-c3- ESP32-C3 Super Mini
Development Environments:
debug- Verbose logging with full debug symbolsrelease- Size-optimized production build
Build Features:
- Automatic exception decoding in serial monitor
- Fast uploads (921600 baud vs default 115200)
- Pinned library versions for reproducible builds
- AsyncTCP optimizations for better WiFi/BLE coexistence
- PSRAM support for Dev Kit V4
Usage:
pio run # Build default environment
pio run -e esp32-c3 # Build for ESP32-C3
pio run -e debug # Build with debug symbols
pio run -e release # Build optimized releaseBased on reverse-engineering the Casambi Bluetooth library.
Key Opcodes:
0x01- SetLevel (brightness, scenes)0x03- SetTemperature (color temperature)0x04- SetVertical (position)0x07- SetColor (RGB/HSV)0x0C- SetSlider0x30- SetState
Target Encoding:
- Unit:
(deviceId << 8) | 0x01 - Group:
(groupId << 8) | 0x02 - Scene:
(sceneId << 8) | 0x04
MIT License - see LICENSE file for details.
- Casambi Protocol: Reverse-engineered from casambi-bt Python library
- ESP32 Community: For excellent BLE and crypto libraries
- Screaming GPUs in a datacenter somewhere
This project is not affiliated with or endorsed by Casambi. It is an independent implementation for educational and personal use.
Security Note: This controller stores Casambi network keys locally. Protect your ESP32 device physically to maintain security.
Status: Complete and hardware-tested
Tested Hardware:
- AZDelivery ESP32 Dev Kit C V4
- ESP32-C3 Super Mini
- Casambi network (protocol v43)
- Issues: GitHub Issues