Async Python library for controlling Casper Glow lights via BLE.
Built on bleak and designed for use as a backend for Home Assistant integrations.
pip install pycasperglowimport asyncio
from pycasperglow import discover_glows
async def main():
async for device in discover_glows(timeout=10.0):
print(f"{device.name} ({device.address})")
asyncio.run(main())import asyncio
from pycasperglow import CasperGlow, discover_glows
async def main():
glow = None
async for device in discover_glows():
glow = CasperGlow(device)
break
if glow is None:
print("No Casper Glow found")
return
await glow.turn_on()
await asyncio.sleep(5)
await glow.turn_off()
asyncio.run(main())When used within Home Assistant's Bluetooth stack, pass the managed BleakClient to avoid connection conflicts:
glow = CasperGlow(ble_device, client=bleak_client)
await glow.turn_on()When an external client is provided, pycasperglow will not disconnect it — the caller retains ownership.
Async client for a single Casper Glow light.
| Method / Property | Description |
|---|---|
turn_on() |
Turn the light on |
turn_off() |
Turn the light off |
pause() |
Pause the active dimming sequence |
resume() |
Resume a paused dimming sequence |
set_brightness_and_dimming_time(level, dimming_time_minutes) |
Set brightness (60–100 %) and dimming duration (15, 30, 45, 60, or 90 min). Both required. |
query_state() |
Query current device state; returns GlowState |
handshake() |
Test connectivity without sending a command |
register_callback(cb) |
Register a callback invoked on every state update |
state |
Current GlowState property (last known, or default) |
name |
Device name (property) |
address |
BLE address (property) |
Dataclass returned by query_state() and passed to registered callbacks.
| Field | Type | Description |
|---|---|---|
is_on |
bool | None |
True when on, False when off |
is_paused |
bool | None |
True when dimming is paused |
is_charging |
bool | None |
True when plugged in to charger |
battery_level |
BatteryLevel | None |
Discrete battery level |
brightness_level |
int | None |
Last-set brightness % (not reported by device) |
dimming_time_minutes |
int | None |
Remaining dimming time (from device) |
configured_dimming_time_minutes |
int | None |
Total configured duration |
IntEnum with four members: PCT_25, PCT_50, PCT_75, PCT_100.
Each has a .percentage property returning 25, 50, 75, or 100.
Scan for Casper Glow devices. Async generator that yields BLEDevice objects as they are found. For standalone use — Home Assistant uses its own discovery.
Returns True if a BLEDevice and AdvertisementData match a Casper Glow (by service UUID or name prefix).
| Exception | Description |
|---|---|
CasperGlowError |
Base exception |
ConnectionError |
Connection or handshake failure |
HandshakeTimeoutError |
Device did not become ready in time |
CommandError |
Failed to send a command |
See the examples/ directory for runnable scripts. To discover nearby Casper Glow lights and turn them on:
python examples/discover_and_turn_on.pypython3 -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"Run checks:
pytest tests/ -v --cov=pycasperglow
mypy src/ tests/ examples/ --strict
ruff check src/ tests/ examples/The BLE protocol was partially reverse-engineered from dengjeffrey/casper-glow-pro. The connection flow is:
- Connect and subscribe to notifications on the read characteristic
- Write the reconnect packet
- Wait for a notification containing the ready marker
- Extract the session token from the notification
- Build and write the action packet (header + token + action body)
- Disconnect
MIT