Govee lights in Home Assistant usually mean either the cloud path (0.3-0.7 s
per command) or BLE integrations that connect per command (multi-second, and
flaky because Govee firmware drops idle clients after about 10 seconds).
I spent some time on the BLE path and got warm-command latency down to
17-23 ms. Numbers and code below in case they’re useful to anyone.
Measured latencies (H605C at -50 RSSI, H601C via proxy):
| Path | Latency |
|---|---|
| Govee Platform API (cloud) | ~700 ms |
| AWS IoT push (govee2mqtt) | 300-500 ms |
| BLE, cold connect | ~600 ms |
| BLE, held connection | 17-23 ms |
How: hold the GATT connection instead of reconnecting per command. The
firmware kills idle links after ~10 s, so a keep-alive frame every 4 s keeps
it open; the link is released after 10 min without commands. That’s the core
of a fork of the (inactive since 2025) govee_ble_lights integration:
Verified on H601C/H601D (Glide downlights) and H605C; basic power/brightness/
color uses the generic 0x33 frame protocol so most BLE-capable Govee lights
should work. Installable as a HACS custom repository. Maintained as-is for
the hardware I own; issues with model number and debug log are welcome.
Firmware quirks found along the way (apply to any implementation, not
just this fork):
- On 60:74:F4-prefixed devices the BLE MAC is the WiFi MAC + 1. Older
devices embed the BLE MAC directly in the govee2mqtt device ID. - H601x takes brightness as 0-100; other models take raw 0-255. Sending
0-255 to an H601x overshoots to full at 40%. - Some firmware exposes the control characteristic as write-without-response
only. A write-with-response gets ATT WRITE_NOT_PERMITTED on a perfectly
healthy link. If your stack treats that as a dead connection you get
reconnect churn; retry the same payload without response instead. - H601x has no status readback I could find (the 0xAA 0x01 poll that works
on strips gets no reply), so state is optimistic. If you also run
govee2mqtt, its AWS IoT entities mirror BLE-initiated changes within
~1-2 s and can serve as readback. - The lights must be powered to be reachable: a wall switch that’s off
means no BLE, no matter what software you run.
Radio side: my fixtures are out of range of the HA host, so the
connection runs through a Bluetooth proxy on a Linux server that speaks the
ESPHome native API. HA treats it exactly like an ESP32 proxy, but it’s the
server’s BlueZ radio. I hardened a small existing project for this (the
original repo is now archived): write-without-response fallback, forced
active scanning, and a shutdown path that actually exits under systemd:
Caveat for held connections on any proxy: each held link occupies a
connection slot and connects pause scanning on a single radio, so size
max-connections to your fixture count and expect contention if one radio
serves many rooms.