Using BLE to control a Casambi-based home lighting system via a web interface.
Project description
Casambi Web Controller
Local Casambi BLE lighting control exposed as an HTTP API. Compatible with matter_webcontrol v0.25.0+ federation, so a Casambi network can be merged into a Matter fabric as a logical bridge.
Architecture
FastAPI middleware over the casambi-bt library. The server discovers a Casambi network over BLE, authenticates with the network password, and exposes each unit through a REST API that matches matter_webcontrol's federation contract — so federation peers call /api/devices, /api/level, /api/mired, /api/set directly without embedded scripts (no RCE surface).
┌──────────────┐ HTTP+API key ┌──────────────────┐ BLE ┌──────────┐
│ matter-srv │ ─────────────────▶ │ casambi-srv │ ────────▶ │ Casambi │
│ (Matter │ │ (this project) │ │ network │
│ fabric) │ ◀─── /api/devices │ FastAPI + bleak │ ◀──notif─ │ │
└──────────────┘ └──────────────────┘ └──────────┘
Limitations
- Single Casambi network per server instance (uses
devices[0]from discovery). - Lighting units only — sensor / occupancy not exposed.
- BLE depends on host OS permissions (on macOS, grant Bluetooth to the parent process via System Settings → Privacy & Security → Bluetooth).
Install
pip install -e . # from source
# or
pip install casambi-web-controller # from PyPI
Run
casambi-srv --port 8000 --api-key <secret>
# or via env:
CASAMBI_NETWORK_PWD=<network-password> CASAMBI_SRV_KEY=<secret> casambi-srv --port 8000
CLI options:
| Flag | Default | Description |
|---|---|---|
--port |
8000 |
Web server port |
--host |
127.0.0.1 |
Bind address. Use 0.0.0.0 to expose on LAN (warns if no API key) |
--api-key |
$CASAMBI_SRV_KEY |
Require X-API-Key header on all requests |
--password |
— | Casambi network password (see below) |
Password resolution order: --password flag → $CASAMBI_NETWORK_PWD env var → interactive getpass prompt. The env var is preferred over --password because CLI args are visible to other users via ps. Whichever source supplies it, the value is held only on app.state and the env var is pop()'d so it does not leak via /proc/PID/environ.
Federation with matter_webcontrol
Once both servers are running, register this server as a logical bridge on the Matter side:
GET http://<matter-host>:8080/api/bridge?ip=<casambi-host>&port=8000&api_key=<secret>
After this, every Casambi device appears under matter's /api/devices with id cas_* and is controllable through any matter endpoint (/api/level, /api/set, /api/toggle, etc.). Matter routes calls back through this server's REST API.
API endpoints
All endpoints require X-API-Key: <secret> if --api-key was set.
GET /api/devices
Federation device list. Each entry: {id, names, states}.
[
{
"id": "cas_d8dccdc7a8bc4f079f4e76d49bf9c7bc",
"names": ["Sofa and Painting"],
"states": {"on_off": false, "brightness_raw": 0}
}
]
states keys (only emitted when the unit type supports the control):
on_off(bool)brightness_raw(int 0–254, Matter scale)color_temp_mireds(int 153–500)
GET /api/lights
Light-only view with normalized fields.
[{"id": "cas_…", "names": ["…"], "on_off": true, "brightness": 0.78}]
GET /api/status
Summary counts.
{"lights_on": 1, "lights_off": 7, "sensors_active": 0, "logical_bridges": 0, "total_devices": 8}
GET|POST /api/level
Read or write Matter-scale level (0–254).
| Param | Type | Required | Notes |
|---|---|---|---|
id |
str | yes | Canonical device id (cas_*) |
level |
int | no | If absent, returns current level. If present (0–254), sets it |
Body for POST: {"id": "cas_…", "level": 200}. Read-back response: {id, level}. Write response: {status, id, level, type}.
GET|POST /api/mired
Color temperature in mireds (153–500). Auto-clamped to per-unit Kelvin range. Returns 400 for units without temperature control.
Body for POST: {"id": "cas_…", "mireds": 250}.
GET|POST /api/set
Multi-attribute write. At least one of brightness / temperature is required (else 400).
| Param | Type | Range |
|---|---|---|
id |
str | required |
brightness |
float | 0.0–1.0 |
temperature |
int | Kelvin |
Body for POST: {"id": "cas_…", "brightness": 0.5, "temperature": 4000}.
GET /api/toggle?id=
Flip on/off. When turning on, restores the last non-zero level (cached in-memory) instead of jumping to 100%.
GET /api/refresh
If BLE is connected, no-op (state is push-driven via Casambi notifications). If disconnected, attempts a reconnect using the cached network password.
GET /api/metadata
Declarative bridge metadata for federation discovery. No embedded Python scripts — peers consume the device list via /api/devices and call control endpoints directly.
{
"bridge": {
"id": "casambi_bridge_http",
"type": "lighting_controller",
"network_host": "192.168.1.220",
"network_port": 8000,
"api_version": "2"
},
"devices": [
{
"id": "cas_d8dccdc7a8bc4f079f4e76d49bf9c7bc",
"name": "Sofa and Painting",
"names": ["Sofa and Painting"],
"hardware_type": "dimmable_light",
"capabilities": ["on_off", "brightness"],
"states": {"on_off": false, "brightness_raw": 0}
}
]
}
Security notes
X-API-Keycomparison is constant-time (hmac.compare_digest) to resist timing attacks.- The Casambi network password is held on
app.stateand not written intoos.environ(no leak via/proc/PID/environon Linux). - Default bind is
127.0.0.1. Binding to0.0.0.0without--api-keylogs a warning. /api/metadatano longer emits executable Python; the previousevents.{name}.scriptshape was removed in v0.9.0 to match matter_webcontrol v0.25.0 (closes a federation RCE risk).
Compatibility matrix
| casambi_webcontrol | matter_webcontrol |
|---|---|
| 0.9.x | 0.25.x + (federation v2: REST + auth) |
| ≤ 0.6.x | ≤ 0.22.x (legacy embedded scripts) |
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file casambi_web_controller-0.9.0.tar.gz.
File metadata
- Download URL: casambi_web_controller-0.9.0.tar.gz
- Upload date:
- Size: 9.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b2dbb7cfe0bdd4cfe7c1cff89d355f5778b04209fe205271eb202abaca3c5150
|
|
| MD5 |
0818e1d93dc5cd77fa32c7f7b8162e9b
|
|
| BLAKE2b-256 |
e2812b66f62b895651191440759888270008b797d13973221f2e0e3a64d52e1c
|
Provenance
The following attestation bundles were made for casambi_web_controller-0.9.0.tar.gz:
Publisher:
python-publish.yml on dongnh/casambi_webcontrol
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
casambi_web_controller-0.9.0.tar.gz -
Subject digest:
b2dbb7cfe0bdd4cfe7c1cff89d355f5778b04209fe205271eb202abaca3c5150 - Sigstore transparency entry: 1437034065
- Sigstore integration time:
-
Permalink:
dongnh/casambi_webcontrol@7d012fe8497831339cd2eea714344151e9cd4cb2 -
Branch / Tag:
refs/tags/v0.9.0 - Owner: https://github.com/dongnh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@7d012fe8497831339cd2eea714344151e9cd4cb2 -
Trigger Event:
release
-
Statement type:
File details
Details for the file casambi_web_controller-0.9.0-py3-none-any.whl.
File metadata
- Download URL: casambi_web_controller-0.9.0-py3-none-any.whl
- Upload date:
- Size: 9.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ac96e948a8bd21f953b9d27bd713766fbb9051008a8a7e7fee973d9a4f42b34
|
|
| MD5 |
5daf7e21c3c17c2e5e598800eaa19976
|
|
| BLAKE2b-256 |
2f4df55ef1277d0b4f27d8c83292db1b687e62388c4f0285bd57fe138e29d63c
|
Provenance
The following attestation bundles were made for casambi_web_controller-0.9.0-py3-none-any.whl:
Publisher:
python-publish.yml on dongnh/casambi_webcontrol
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
casambi_web_controller-0.9.0-py3-none-any.whl -
Subject digest:
6ac96e948a8bd21f953b9d27bd713766fbb9051008a8a7e7fee973d9a4f42b34 - Sigstore transparency entry: 1437034069
- Sigstore integration time:
-
Permalink:
dongnh/casambi_webcontrol@7d012fe8497831339cd2eea714344151e9cd4cb2 -
Branch / Tag:
refs/tags/v0.9.0 - Owner: https://github.com/dongnh
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@7d012fe8497831339cd2eea714344151e9cd4cb2 -
Trigger Event:
release
-
Statement type: