pycasperglow
Async Python library for controlling Casper Glow lights via BLE.
Built on bleak and designed for use as a backend for Home Assistant integrations.
Installation
pip install pycasperglow
Usage
Discover devices
import 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())
Control a light
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())
Home Assistant integration
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.
API
CasperGlow(ble_device, client=None)
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) |
GlowState
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 |
BatteryLevel
IntEnum with four members: PCT_25, PCT_50, PCT_75, PCT_100.
Each has a .percentage property returning 25, 50, 75, or 100.
discover_glows(timeout=10.0)
Scan for Casper Glow devices. Async generator that yields BLEDevice objects as they are found. For standalone use — Home Assistant uses its own discovery.
is_casper_glow(device, adv)
Returns True if a BLEDevice and AdvertisementData match a Casper Glow (by service UUID or name prefix).
Exceptions
| Exception | Description |
|---|---|
CasperGlowError |
Base exception |
ConnectionError |
Connection or handshake failure |
HandshakeTimeoutError |
Device did not become ready in time |
CommandError |
Failed to send a command |
Examples
See the examples/ directory for runnable scripts. To discover nearby Casper Glow lights and turn them on:
python examples/discover_and_turn_on.py
Development
python3 -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/
Protocol
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
License
MIT
Release files for pycasperglow 1.2.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 | |
|---|---|---|---|
| pycasperglow-1.2.0.tar.gz | 20.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pycasperglow-1.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 33.1 kB
Release files / pycasperglow-1.2.0.tar.gz
| Download URL | pycasperglow-1.2.0.tar.gz |
|---|---|
| Size | 20.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cd2f92f7a145ee12347fc1e6aed2a2a0075737eb8d613bdf878d96de6fa51232
|
|
BLAKE2b-256 checksum How to use checksums |
82e5a88e50549d4770d0e9feec772e8d88c64d35a56de850eaff9f4a70f1fff0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Mar 21, 2026.
Transparency logRelease files / pycasperglow-1.2.0-py3-none-any.whl
| Download URL | pycasperglow-1.2.0-py3-none-any.whl |
|---|---|
| Size | 13.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8aadfd85627d4606f536af88c0ee83125f01fdc9d54ceca460d910b4808559d7
|
|
BLAKE2b-256 checksum How to use checksums |
fa1520e05e6955f2140f10909e108a30e07f5274f90ac6b43b045f1927555b9d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.13.7
|
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 Mar 21, 2026.
Transparency log