Skip to content

fix Respeaker USB Mic Array v2 LEDs#357

Open
litinoveweedle wants to merge 6 commits into
OHF-Voice:mainfrom
litinoveweedle:fix_respeaker_mic_array_v2_leds
Open

fix Respeaker USB Mic Array v2 LEDs#357
litinoveweedle wants to merge 6 commits into
OHF-Voice:mainfrom
litinoveweedle:fix_respeaker_mic_array_v2_leds

Conversation

@litinoveweedle

@litinoveweedle litinoveweedle commented Jul 19, 2026

Copy link
Copy Markdown

What does this implement/fix?

Fix ReSpeaker Mic Array v2 USB LED control and suppress stale peripheral disconnect replay as reported in the #354

With help of AI ;-)

Related issue (if applicable):

Types of changes

  • Bugfix (non-breaking change which fixes an issue) — bugfix
  • New feature (non-breaking change which adds functionality) — new-feature
  • Enhancement to an existing feature — enhancement
  • Breaking change (fix or feature that would cause existing functionality to not work as expected) — breaking-change
  • Refactor (no behaviour change) — refactor
  • Documentation only — documentation
  • Maintenance / chore — maintenance
  • CI / workflow change — ci
  • Dependencies bump — dependencies

Checklist

  • The code change is tested and works locally.
  • ./script/lint passes.
  • ./script/tests passes, and tests have been added/updated under tests/ where applicable.

Summary

This pull request fixes two related issues affecting the ReSpeaker Mic Array v2.0 USB peripheral integration:

  1. The USB LED ring was being driven with the wrong protocol, which could leave the LEDs stuck in incorrect states such as full white and could interfere with the device.
  2. Peripheral clients could receive a stale disconnected event immediately after connecting, even when Home Assistant was already connected, which forced the LED controller back into the red "not ready" animation.

Together, these fixes make the ReSpeaker USB LED behavior consistent with the reference pixel_ring implementation and prevent false disconnect state from overriding valid Home Assistant state.

Changes

1. Fix ReSpeaker USB LED transport and device handling

Updated examples/ReSpeaker Mic Array v2.0 (USB)/respeaker_usb_mic_array.py to use the same USB vendor-command protocol as the copied reference implementation under the local pixel_ring directory.

What changed

  • Replaced the previous raw APA102-style frame transfer approach with the ReSpeaker USB firmware command protocol.
  • Added explicit USB commands:
    • 0x06 for LED frame updates
    • 0x20 for brightness updates
  • Kept the USB control endpoint at wIndex = 0x1C, matching the reference implementation.
  • Removed kernel-driver detachment from device discovery logic.

Why this was necessary

The local ReSpeaker USB example was treating the device like a raw APA102 transport target, but the USB firmware actually expects higher-level vendor commands. Sending the wrong payload format can cause the firmware to misinterpret LED data, which explains symptoms like the ring going fully white or otherwise behaving incorrectly.

The previous version also detached the kernel driver during USB initialization. For this hardware, that is unnecessary for LED control and risks interfering with the audio side of the device.

Result

  • LED writes now follow the known-working reference transport.
  • The microphone/audio interface is no longer disturbed by unnecessary driver detachment.
  • Brightness and color updates are sent in the form the device firmware expects.

2. Fix peripheral state initialization and recovery in the ReSpeaker USB example

Updated event handling in examples/ReSpeaker Mic Array v2.0 (USB)/respeaker_usb_mic_array.py so the LED controller correctly transitions out of NOT_READY.

What changed

  • snapshot handling now derives the initial assist state from:
    • muted
    • ha_connected
  • muted handling now supports both mute and unmute transitions.
  • zeroconf handling now restores the LED state to IDLE or MUTED when Home Assistant reconnects.

Why this was necessary

The peripheral could receive valid light_command updates, but still remain in the red twinkle animation because its local assist_state never left NOT_READY. In that situation, color and brightness changes were being stored, but the active animation selection kept choosing the disconnected/not-ready path.

Result

  • When Home Assistant is connected, the ring can enter IDLE and render the configured light color.
  • When muted, the controller correctly shows muted state.
  • Reconnection events restore a valid visual state instead of leaving the peripheral stuck in startup/disconnected mode.

3. Prevent stale disconnected replay to newly connected peripherals

Updated peripheral_api.py in the snapshot replay path.

What changed

  • Added a guard so the server does not replay a cached disconnected event to a newly connected peripheral when state.connected is already True.

Why this was necessary

The peripheral API sends a snapshot immediately on connect, then replays the current cached event state so peripherals can restore the correct animation. The bug was that the cached event could still be DISCONNECTED from an earlier Home Assistant outage, even though the current connection state had already recovered.

This produced a misleading sequence:

  1. Peripheral receives snapshot with ha_connected: true
  2. Peripheral immediately receives replayed disconnected
  3. Peripheral switches back to red twinkle

That made the LED controller appear disconnected even when Home Assistant was actually available.

Result

  • Newly connected peripherals now trust the current connection state from the snapshot.
  • A stale cached disconnect no longer overrides a valid active connection.
  • ReSpeaker USB peripherals remain in IDLE or other valid states instead of being forced back to twinkle.

Root Cause

There were two separate but compounding issues:

  1. The ReSpeaker USB LED implementation used the wrong low-level protocol for this hardware.
  2. The peripheral API could replay an outdated disconnect event after sending an up-to-date connected snapshot.

Because of that combination, the LED ring could both misrender LED commands and also remain visually stuck in a disconnected state even after the backend had recovered.

Validation

The chnages were validated on the user deployment.

Files Changed

  • peripheral_api.py
  • examples/ReSpeaker Mic Array v2.0 (USB)/respeaker_usb_mic_array.py

User Impact

After deploying this PR:

  • The ReSpeaker USB LED ring should no longer get stuck due to incorrect USB LED payload handling.
  • Home Assistant light color and brightness commands should apply when the peripheral is connected and idle.
  • The peripheral should no longer falsely fall back to the red disconnected animation right after connecting.

Fix ReSpeaker USB LED control and suppress stale peripheral disconnect replay
@omaramin-2000 omaramin-2000 linked an issue Jul 19, 2026 that may be closed by this pull request
@litinoveweedle

Copy link
Copy Markdown
Author

I discovered another issue testing this fix. There is a race between the LVA registering to HA and peripheral registering to the LVA. @omaramin-2000 shall I add fix here, or shall I create independent fix? The patch will goes as well into peripheral_api.py

@omaramin-2000

Copy link
Copy Markdown
Collaborator

I discovered another issue testing this fix. There is a race between the LVA registering to HA and peripheral registering to the LVA. @omaramin-2000 shall I add fix here, or shall I create independent fix? The patch will goes as well into peripheral_api.py

Yes, do it in a separate PR, better.

@florian-asche

Copy link
Copy Markdown
Collaborator

What device is respeaker usb mic v2?

@litinoveweedle

litinoveweedle commented Jul 20, 2026

Copy link
Copy Markdown
Author

This one: https://www.seeedstudio.com/ReSpeaker-Mic-Array-v3-0.html

Actually predecesor, as I see there is already V3 on the market. It is exactly the device described in the DOCS of this peripheral integration.

@litinoveweedle

Copy link
Copy Markdown
Author

@florian-asche I see PR checks failing on missing PR Labels. Is there anything I shall do? There is now also additional testing result available now from @tobuh reported in #354 .

@litinoveweedle

Copy link
Copy Markdown
Author

Yes, do it in a separate PR, better.

@omaramin-2000 I just open the PR #373 as discussed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

LEDs ReSpeaker Mic Array v2.0

3 participants