Skip to main content

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-Key comparison is constant-time (hmac.compare_digest) to resist timing attacks.
  • The Casambi network password is held on app.state and not written into os.environ (no leak via /proc/PID/environ on Linux).
  • Default bind is 127.0.0.1. Binding to 0.0.0.0 without --api-key logs a warning.
  • /api/metadata no longer emits executable Python; the previous events.{name}.script shape 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

casambi_web_controller-0.9.0.tar.gz (9.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

casambi_web_controller-0.9.0-py3-none-any.whl (9.8 kB view details)

Uploaded Python 3

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

Hashes for casambi_web_controller-0.9.0.tar.gz
Algorithm Hash digest
SHA256 b2dbb7cfe0bdd4cfe7c1cff89d355f5778b04209fe205271eb202abaca3c5150
MD5 0818e1d93dc5cd77fa32c7f7b8162e9b
BLAKE2b-256 e2812b66f62b895651191440759888270008b797d13973221f2e0e3a64d52e1c

See more details on using hashes here.

Provenance

The following attestation bundles were made for casambi_web_controller-0.9.0.tar.gz:

Publisher: python-publish.yml on dongnh/casambi_webcontrol

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file casambi_web_controller-0.9.0-py3-none-any.whl.

File metadata

File hashes

Hashes for casambi_web_controller-0.9.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6ac96e948a8bd21f953b9d27bd713766fbb9051008a8a7e7fee973d9a4f42b34
MD5 5daf7e21c3c17c2e5e598800eaa19976
BLAKE2b-256 2f4df55ef1277d0b4f27d8c83292db1b687e62388c4f0285bd57fe138e29d63c

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page