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) |
Metadata
Release files for casambi-web-controller 0.9.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| casambi_web_controller-0.9.0.tar.gz | 9.1 kB | With provenance | Details for casambi_web_controller-0.9.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| casambi_web_controller-0.9.0-py3-none-any.whl | Python 3 | none | any | Details for casambi_web_controller-0.9.0-py3-none-any.whl |
Total release size: 18.9 kB
Release files / casambi_web_controller-0.9.0.tar.gz
| Download URL | casambi_web_controller-0.9.0.tar.gz |
|---|---|
| Size | 9.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b2dbb7cfe0bdd4cfe7c1cff89d355f5778b04209fe205271eb202abaca3c5150
|
|
BLAKE2b-256 checksum How to use checksums |
e2812b66f62b895651191440759888270008b797d13973221f2e0e3a64d52e1c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 4, 2026.
Transparency logRelease files / casambi_web_controller-0.9.0-py3-none-any.whl
| Download URL | casambi_web_controller-0.9.0-py3-none-any.whl |
|---|---|
| Size | 9.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
6ac96e948a8bd21f953b9d27bd713766fbb9051008a8a7e7fee973d9a4f42b34
|
|
BLAKE2b-256 checksum How to use checksums |
2f4df55ef1277d0b4f27d8c83292db1b687e62388c4f0285bd57fe138e29d63c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 4, 2026.
Transparency logSecurity for casambi-web-controller 0.9.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for casambi_web_controller-0.9.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on May 4, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.