Ground truth for Govee Flow Plus Light Bars (H6056): phantom segments, bar-to-segment mapping, API auth and rate limits. Language-agnostic facts; Kotlin/Ktor reference example.
93
92%
Does it follow best practices?
Impact
100%
3.84xAverage score across 3 eval scenarios
Passed
No known issues
Use this skill whenever you need to light up Govee Flow Plus light bars (H6056).
segmentedColorRgb, min=1, max=15).12, 13, 14 are phantom. The API returns 200 OK when you address them; no light turns on. If you don't slice your ranges correctly, your "all on" commands will look broken on stage.bar_a (call it Yankee): segments 0, 1, 2, 3, 4, 5bar_b (Golf): segments 6, 7, 8, 9, 10, 11segment[0] is at the TOP. Bottom-up fill on Yankee = lighting segments 5 → 0.GET /router/api/v1/user/devices with your API key to enumerate SKUs and device IDs.https://openapi.api.govee.comGovee-API-Key: <key> (NOT bearer, NOT query param)POST /router/api/v1/device/controltype = "devices.capabilities.segment_color_setting"instance = "segmentedColorRgb"value = {"segment": [<indices>], "rgb": <packed_int>} where rgb = (r shl 16) or (g shl 8) or biot-actuator-patterns-kotlin's debounce controller (min-interval 1.2 s).rgb=(0,0,0) packs to 0x000000. Some firmware paths treat that as a no-op and retain the prior segment state. To reliably clear a segment, send rgb=(1,1,1) — near-black but non-zero. The user can't perceive the 1/255 brightness.
On session shutdown, always issue an explicit all-segments command:
Runtime.getRuntime().addShutdownHook(Thread {
runBlocking { client.setSegments((0..11).toList(), Triple(1, 1, 1)) }
})import io.ktor.client.*
import io.ktor.client.engine.cio.*
import io.ktor.client.request.*
import io.ktor.client.statement.*
import kotlinx.coroutines.runBlocking
import java.util.UUID
class GoveeClient(
private val apiKey: String,
private val sku: String, // "H6056"
private val device: String // from GET /router/api/v1/user/devices
) {
private val client = HttpClient(CIO)
private val base = "https://openapi.api.govee.com"
suspend fun setSegments(segments: List<Int>, rgb: Triple<Int, Int, Int>): Int {
val (r, g, b) = rgb
val packed = (r shl 16) or (g shl 8) or b
val segArr = segments.joinToString(",", "[", "]")
val payload = """
{"requestId":"${UUID.randomUUID()}",
"payload":{"sku":"$sku","device":"$device",
"capability":{"type":"devices.capabilities.segment_color_setting",
"instance":"segmentedColorRgb",
"value":{"segment":$segArr,"rgb":$packed}}}}
""".trimIndent()
return client.post("$base/router/api/v1/device/control") {
header("Content-Type", "application/json")
header("Govee-API-Key", apiKey)
setBody(payload)
}.status.value
}
companion object {
// Use these constants, NOT raw indices, to stay phantom-safe and bar-aware
val YANKEE = (0..5).toList()
val GOLF = (6..11).toList()
val ALL_PHYSICAL = (0..11).toList()
}
}
fun main() = runBlocking {
val client = GoveeClient(
apiKey = System.getenv("GOVEE_API_KEY"),
sku = "H6056",
device = System.getenv("GOVEE_H6056_DEVICE")
)
// Light Yankee green, Golf red:
client.setSegments(GoveeClient.YANKEE, Triple(0, 200, 0))
client.setSegments(GoveeClient.GOLF, Triple(200, 0, 0))
}Because segment[0] is the TOP, a bottom-up "thermometer" fill means lighting from the high-index end:
fun yankeeBottomUp(lit: Int): IntRange = (6 - lit) until 6 // total=6
// lit=1 → segment 5 (just the bottom)
// lit=3 → segments 3, 4, 5
// lit=6 → segments 0..5 (full bar)See render-progress-bar-kotlin for the full gradient pattern.
suspend fun discoverDevices(client: HttpClient, apiKey: String): List<Map<String, Any?>> {
val resp = client.get("https://openapi.api.govee.com/router/api/v1/user/devices") {
header("Govee-API-Key", apiKey)
}
// resp.bodyAsText() → {"code":200, "data":[{sku, device, deviceName, ...}], ...}
// Parse with kotlinx.serialization or Jackson; extract entries where sku == "H6056"
TODO("parse JSON, return entries")
}15 as the segment count — sends 3 wasted commands to phantom segments.0..4, 5..9, 10..14 for a semaphore — middle band spans Yankee + Golf, top band addresses phantoms.rgb=(0,0,0) for "off" — silently no-ops on some firmware paths./devices endpoint.export GOVEE_API_KEY=<your-developer-api-key> # from developer.govee.com
export GOVEE_H6056_SKU=H6056
export GOVEE_H6056_DEVICE=<the device-id field from /devices response>