Metadata-Version: 2.4
Name: govee-ble-local
Version: 1.2.1
Summary: Local Bluetooth LE control of Govee devices — no cloud, no LAN API.
Author: Brady Woods
License-Expression: MIT
Project-URL: Homepage, https://github.com/Brady-Woods/govee-ble-local
Project-URL: Repository, https://github.com/Brady-Woods/govee-ble-local
Project-URL: Changelog, https://github.com/Brady-Woods/govee-ble-local/blob/master/CHANGELOG.md
Project-URL: Issues, https://github.com/Brady-Woods/govee-ble-local/issues
Keywords: govee,bluetooth,ble,home-assistant,led,light
Classifier: Development Status :: 5 - Production/Stable
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Home Automation
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Framework :: AsyncIO
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: bleak>=0.21
Requires-Dist: bleak-retry-connector>=3.0.0
Requires-Dist: cryptography>=41.0.0
Requires-Dist: kaitaistruct>=0.11
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-asyncio; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Requires-Dist: jsonschema>=4.0; extra == "test"
Requires-Dist: PyYAML>=6.0; extra == "test"
Requires-Dist: aiohttp>=3.9; extra == "test"
Requires-Dist: pycryptodome; extra == "test"
Provides-Extra: cloud
Requires-Dist: aiohttp>=3.9; extra == "cloud"
Provides-Extra: typing
Requires-Dist: mypy; extra == "typing"
Requires-Dist: types-PyYAML; extra == "typing"
Provides-Extra: lint
Requires-Dist: ruff; extra == "lint"
Requires-Dist: bandit; extra == "lint"
Requires-Dist: pip-audit; extra == "lint"
Provides-Extra: docs
Requires-Dist: pdoc; extra == "docs"
Provides-Extra: audit
Requires-Dist: vulture; extra == "audit"
Requires-Dist: radon; extra == "audit"
Provides-Extra: dev
Requires-Dist: govee-ble-local[audit,cloud,lint,test,typing]; extra == "dev"
Requires-Dist: uv; extra == "dev"
Dynamic: license-file

# govee-ble-local

**Local Bluetooth LE control of Govee devices — no cloud, no LAN API.**

A standalone Python library implementing Govee's BLE control protocol (AES-ECB+RC4
handshake, 20-byte command framing, multi-packet scene upload, and status read-back),
derived from the decompiled Govee Home app and verified against real hardware. It's the
protocol engine behind the
[`hass-govee-ble-local`](https://github.com/Brady-Woods/hass-govee-ble-local)
Home Assistant integration, but has no Home Assistant dependency and can be used on its own.

> ⚠️ **Unofficial.** Not affiliated with or endorsed by Govee. Reverse-engineered from the
> app + hardware; behavior may change with device firmware. Live-verified on the **H60A6**
> (Ceiling Light Pro); the other curated SKUs are modelled from the app and are not all
> hardware-verified (see the profile notes).

## Install

```bash
pip install govee-ble-local
# optional Govee cloud-account helpers (pulls in aiohttp):
pip install 'govee-ble-local[cloud]'
# or, from a clone (editable, for development):
git clone https://github.com/Brady-Woods/govee-ble-local.git
cd govee-ble-local && pip install -e '.[dev]'
```

Requires Python 3.11+. Runtime dependencies are deliberately minimal and Home-Assistant-friendly:
`bleak`, `bleak-retry-connector`, `cryptography` (all shipped with HA), plus `kaitaistruct` (a
pure-Python, stdlib-only wire-parser runtime). Dev extras: `.[dev]` (everything a contributor needs), or individually `.[test]`, `.[typing]`,
`.[lint]`, `.[audit]`, `.[docs]`.

## Quick start

```python
import asyncio
from govee_ble_local import create_device, discover

async def main():
    # Active-scan for supported Govee devices (strongest advertisement per address).
    devices = await discover(timeout=8.0)
    found = next(d for d in devices if d.sku == "H60A6")

    dev = create_device(found.ble_device, found.sku)

    await dev.turn_on()
    await dev.set_brightness(60)             # percent
    await dev.set_rgb((255, 0, 0))
    await dev.set_zone_power("background", False)

    state = await dev.update()               # read-back into dev.state
    print(state.is_on, state.brightness, state.rgb_color, state.segments)

    await dev.stop()

asyncio.run(main())
```

## API

The library follows Home-Assistant BLE-library conventions: identify a device from its
advertisement, build a capability-driven `Device`, then drive it.

- **`discover(timeout=10.0, *, supported_only=True)`** — active-scan → `list[DiscoveredDevice]`
  (`.ble_device`, `.advertisement`, `.sku`, `.rssi`, `.supported`). `supported(name, mfg)` and
  `match(ble_device, adv)` are the passive-matcher hooks for a HA-style scanner.
- **`create_device(ble_device, sku, advertisement_data=None, *, secret=None, frame_log=None)`**
  — construct a `Device` for the SKU (raises `GoveeBleNotSupported` if uncurated).
  `is_supported_sku(sku)` / `supported_skus()` / `device_profile_for(sku)` query the table.
- **`Device`** — one capability-gated class (behaviour comes from its `DeviceProfile`, not
  subclasses). Commands are ACK-confirmed on the wire:
  `turn_on` / `turn_off` / `set_power`, `set_brightness`, `set_rgb`, `set_color_temp`,
  `set_segment_rgb` / `set_segment_brightness` / `set_segment_color_temp`,
  `set_zone_power` / `set_zone_rgb` / `set_zone_color_temp`,
  `set_scene` / `set_scene_by_name`, and `update()` (read-back). Introspection:
  `capabilities`, `zones`, `min_kelvin` / `max_kelvin`, `scene_names`, `state`,
  `register_callback`. Methods for unsupported capabilities raise `GoveeBleNotSupported`.
- **`DeviceState`** — parsed state: `is_on`, `brightness` (0–100), `rgb_color`,
  `color_temp_kelvin`, `segments` (`list[Segment]`), `zone_power`, `scene_code`, plus
  device-info (`serial_number`, `wifi_mac`, `hardware_version`, `firmware_version`, `ble_mac`).
- **`Capability`** — `POWER`, `BRIGHTNESS`, `RGB`, `COLOR_TEMP`, `SEGMENTS`, `SCENES`.

Curated SKUs: **H60A6**, **H6047**, **H61A8**, **H6006/H6008**, **H6052**, **H6641**, and the
plug family (**H5080/H5082/H5083/H5085/H5089/H5160/H5161**). Segment-colour read-back and some
scene dialects on the non-H60A6 SKUs are source-modelled and not yet hardware-verified.

The full API reference is generated from the docstrings with [`pdoc`](https://pdoc.dev)
(`pip install '.[docs]' && bash tools/gen_docs.sh` → `docs/api/`); `govee_ble_local.__all__` is the
public contract.

## Security notes

The Govee BLE protocol itself has well-known limits that this library cannot fix:

- Its encryption uses a public pre-shared key, AES-ECB for the handshake and an RC4 stream for
  traffic, and integrity is only an XOR checksum. Anyone within radio range can drive an
  encrypted device.
- Captures made with `GOVEE_FRAME_LOG` contain wire frames from which the session key can be
  derived. Treat them as sensitive and do not post them publicly. Frame-log files are created
  with owner-only permissions.

## Diagnostics & session capture

The library logs under the `govee_ble_local.*` hierarchy and can capture a full protocol
session (over a local adapter or a Home Assistant Bluetooth proxy) for analysis. Enable the
flow trace, or the per-frame firehose, and decode a capture with the bundled
`govee-ble-analyze` CLI. See [`docs/DIAGNOSTICS.md`](docs/DIAGNOSTICS.md).

## Protocol

The wire protocol is specified as Kaitai Struct definitions — [`spec/govee_ble.ksy`](spec/govee_ble.ksy)
(command/reply frames) and [`spec/govee_adv.ksy`](spec/govee_adv.ksy) (advertisements) — with the
per-device table in [`spec/devices.yaml`](spec/devices.yaml). The runtime readers under
`govee_ble_local/_generated/` are generated from those (source of truth: the decompiled Govee app).

## Contributing & versioning

See [`CONTRIBUTING.md`](CONTRIBUTING.md) for development setup, branching, commit, and release
conventions. Changes are tracked in [`CHANGELOG.md`](CHANGELOG.md); the project follows
[Semantic Versioning](https://semver.org/). Live hardware tests run against the curated SKUs above.

## License

[MIT](LICENSE) © Brady Woods
