From 309ec2baf102c8c0b3921c89544b2563572ef287 Mon Sep 17 00:00:00 2001 From: Ken Sanislo Date: Sat, 18 Apr 2026 13:12:31 -0700 Subject: [PATCH] HeadsetRGBColor: FrameEnd byte 0 must be 0x01, not 0x00 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RE of lghub_agent.arm64 (see HEADSET_RGB_HOSTMODE_WIRE_PROTOCOL.md) corrected the canonical protocol doc: FrameEnd byte 0 is a frame_type tag where 0x01 = transient commit and 0x02 = persistent/final flush. The firmware silently discards frames sent with byte 0 = 0x00 — the HID++ ACK succeeds but the staged color writes are never committed. This is why SetRgbZonesSingleValue appeared to succeed but LEDs never changed color on the tester's G522. The canonical doc's "For basic usage, all parameter bytes can be set to 0x00" is wrong. Change FrameEnd payload from `\x00\x00\x00\x00` to `\x01\x00\x00\x00`. Also worth noting (not fixed here): firmware auto-releases the host-mode claim if no Set+FrameEnd traffic arrives within a few seconds. HeadsetRGBColor already re-issues SetHostModeState(1) on every color change (the LGHUB "on-demand" model), so that covers the common case. HeadsetRGBHostMode toggle alone will still appear to "not stick" in GetHostModeState after the firmware release window — that's the firmware's behavior, not a bug. --- lib/logitech_receiver/settings_templates.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/logitech_receiver/settings_templates.py b/lib/logitech_receiver/settings_templates.py index d02544f3..88c45ad4 100644 --- a/lib/logitech_receiver/settings_templates.py +++ b/lib/logitech_receiver/settings_templates.py @@ -2028,7 +2028,11 @@ class HeadsetRGBColor(settings.Setting): resp.hex() if resp else resp, ) # FrameEnd: commit the frame. - resp = device.feature_request(_F.HEADSET_RGB_HOSTMODE, 0x60, b"\x00\x00\x00\x00") + # Byte 0 is frame_type: 0x01 = transient commit, 0x02 = persistent/final + # flush. The firmware silently discards frames when byte 0 is 0x00 — + # canonical protocol doc was wrong on this point. See + # HEADSET_RGB_HOSTMODE_WIRE_PROTOCOL.md. + resp = device.feature_request(_F.HEADSET_RGB_HOSTMODE, 0x60, b"\x01\x00\x00\x00") logger.info("HeadsetRGBColor: FrameEnd resp=%s", resp.hex() if resp else resp) except Exception as e: logger.warning("HeadsetRGBColor write failed for %s: %s", name, e)