Metadata-Version: 2.4
Name: govee-toolkit
Version: 0.1.0
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Rust
Classifier: Topic :: Home Automation
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Dist: pytest ; extra == 'dev'
Requires-Dist: pytest-asyncio ; extra == 'dev'
Provides-Extra: dev
Summary: Control Govee devices from your own network: undocumented LAN features, with BLE and Cloud modes when you need them.
Keywords: govee,led,smart-home,iot,sdk
Home-Page: https://gvetk.com
Author: damient
License-Expression: MIT
Requires-Python: >=3.11
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Changelog, https://github.com/damient/govee-toolkit/blob/main/packages/python/CHANGELOG.md
Project-URL: Documentation, https://gvetk.com/docs/start/
Project-URL: Homepage, https://gvetk.com
Project-URL: Issues, https://github.com/damient/govee-toolkit/issues
Project-URL: Repository, https://github.com/damient/govee-toolkit

# govee-toolkit (Python)

Control Govee devices over the LAN from Python, with the undocumented commands
observed on the wire.

**Documentation: [gvetk.com](https://gvetk.com)**

[![govee-toolkit on PyPI](https://img.shields.io/pypi/v/govee-toolkit?logo=python&logoColor=white&label=PyPI)](https://pypi.org/project/govee-toolkit/)
[![license](https://img.shields.io/badge/license-MIT-blue)](https://github.com/damient/govee-toolkit/blob/main/LICENSE)
[![ci](https://github.com/damient/govee-toolkit/actions/workflows/ci.yml/badge.svg)](https://github.com/damient/govee-toolkit/actions/workflows/ci.yml)

> Community project. Not affiliated with, sponsored by or endorsed by Govee.

The package is a [PyO3][pyo3] binding over the Rust core in
[`packages/rust`][rust], not a second implementation of the protocol. It builds
no frame of its own: the core builds every byte, and the conformance vectors in
the repository check the core. Arguments in, exact bytes out.

## Install

```console
pip install govee-toolkit
```

Python 3.11 and up. The wheel is `abi3`, so one wheel serves every version from
3.11. The release builds wheels for Linux and Windows on `x86_64` and
`aarch64`, for macOS on `aarch64`, for Linux on `armv7`, and for musl on
`x86_64`, `aarch64` and `armv7`.

The release publishes no source distribution. On a platform with no wheel, build
the wheel from a checkout of the repository with a Rust toolchain. The core
embeds the device files at build time, so a build needs the `devices/`
directory.

The wheel carries the device catalog, so there is no data file to install.
`govee_toolkit.CORE_VERSION` reports the version of the core that the wheel was
built from.

## A first command

The API is `asyncio` only.

```python
import asyncio
from govee_toolkit import Govee

async def main():
    # Reads $XDG_CONFIG_HOME/govee-toolkit/config.yaml.
    govee = await Govee.start()

    devices = await govee.scan()
    for device in devices:
        print(device.id, device.sku, device.modes)

    handle = govee.device(devices[0].id)
    served = await handle.send("power", on=True)
    print("served over", served.mode)

    await govee.close()

asyncio.run(main())
```

`handle.send()` takes any command the device file declares. Each value is read
under the type that entry declares for the argument, so `[0, 1, 2]` is zone
indices, byte values or one color as the file says. The common ones also
have a method: `power()`, `brightness()`, `color()`, `color_temp()`, `music()`,
`segment()`, `gradient()` and `provision_wifi()`. `handle.read()` and
`handle.status()` ask the device instead. `handle.open_stream()` opens a segment
stream and paints frame by frame.

## Modes

A command travels over your Wi-Fi (`lan`), over Bluetooth (`ble`) or through
Govee's servers (`cloud`). You enable the modes per device, in the configuration
file. One enabled mode means one mode: an unreachable device fails with an error
and says so. The package never substitutes a mode.

`handle.serving_mode()` names the mode a command goes over now, from the state
the SDK recorded. `await handle.ensure_known()` scans first if no mode knows the
device yet, then answers the same question.
[gvetk.com/docs/modes](https://gvetk.com/docs/modes/) has the rules.

## Where command names come from

`power`, `brightness` and `color` are entries in the device's YAML file in
[`devices/`][devices], not identifiers in this package. `handle.spec()` returns
what that file declares for your device. A name the device does not define, or
an argument outside the declared range, is an error before anything reaches the
network.

## Errors

`GoveeError` is the base class; `CodecError`, `TransportError` and `ConfigError`
are its subclasses. The subclass says where the failure happened: `CodecError`
if the command never reached the wire, `TransportError` if the link failed, and
`ConfigError` if a setting cannot work. Every one of them carries `.code`, the
stable identifier that the core gives the failure. Match on the code, not on
the message: the message is written for a person and can change.

A value the package cannot read at all, such as a color that is not three whole
numbers, is a `ValueError`. It carries no code, because the core never saw it.

```python
from govee_toolkit import GoveeError

try:
    await handle.brightness(50)
except GoveeError as err:
    print(err.code)  # for example "unknown_command" or "no_mode_available"
```

## Next

| You want to | Go to |
| ----------- | ----- |
| Install it and send a first command | [gvetk.com/docs/start](https://gvetk.com/docs/start/) |
| Know whether your model works | [gvetk.com/devices](https://gvetk.com/devices/) |
| Pick and configure the modes | [gvetk.com/docs/modes](https://gvetk.com/docs/modes/) |
| Read every command and method | [gvetk.com/reference](https://gvetk.com/reference/) |
| Report a device, or add one | [`devices/README.md`][devices-readme] |

## License

[MIT](https://github.com/damient/govee-toolkit/blob/main/LICENSE)

<!-- Absolute: this file is the package description on PyPI, where a relative
     link out of the package directory is dead. -->
[pyo3]: https://pyo3.rs
[rust]: https://github.com/damient/govee-toolkit/tree/main/packages/rust
[devices]: https://github.com/damient/govee-toolkit/tree/main/devices
[devices-readme]: https://github.com/damient/govee-toolkit/blob/main/devices/README.md

