Leds and buttons events#266
Conversation
Add stop_media_player, and stop_speaking commands accepted from the peripheral container
Add the sound playing when pressing button to start listening
Add the sound playing when pressing button to start listening
handle_timer_event now builds a timer_data dict from the protobuf message fields before the if/elif chain and passes it into all three relevant emits.
|
I'm not sure if this is the right place to ask, but how would the external Python script work? How would it also work if you have to repull down the container, for updating and the like? |
| # When TTS is playing, keep _pipeline_active = True to block | ||
| # false wake word detections from speaker audio feedback. | ||
| # _tts_finished() callback will clear it when playback ends. | ||
|
|
There was a problem hiding this comment.
You say:
When TTS is playing, keep _pipeline_active = True to block false wake word detections from speaker audio feedback.
Would that block the stop word too?
Sorry, I was just looking and got confused by the wording.
It should communicate to any script/container using its api. |
|
Where would be the documentation for the API? Also, thank you for this great work! |
|
I see, does that need this pull request in order to work or does that work just with LVA on its own? |
I cloned this repo and build my own docker image Then (me using picomposer) modify /compose/.env and add: Then save the led script ( I used the respeaker 2MIC HAT) and run it. There is a readme here: https://github.com/omaramin-2000/linux-voice-assistant/blob/leds-and-buttons-events/docs/peripheral_api.md I added a systemd service to work on boot. I also had to uncomment gpio in the python script since I hadn’t enabled it elsewhere. |
|
How would you go about updating the container though? Do you have to rebuild it every time? Maybe that would be nice to have this also send a command to your script just to tell you that it has a update available. That way you could display an icon or something. |
…l peripheral container
When the hangup button is pressed it sends the `STOP_MEDIA_PLAYER` command (if the satellite is idle)
* Emit volume_muted so peripherals can track mute state LVA never broadcast the muted bool to peripheral_api clients. The ``muted`` event signalled "we just entered the muted display state" but no event ever signalled "we just left it" — only the generic ``idle`` did, and peripherals can't infer mute state from an idle event since idle fires in many other situations (post-TTS, post wake word, after errors). As a result the ReSpeaker 2-Mic peripheral script's cached ``muted`` flag flipped to True on the first mute and stayed True forever. Its button handler keyed off that flag (``muted → unmute_mic``, ``unmuted → mute_mic``), so after the very first mute the button could only ever emit ``unmute_mic``: the user could unmute but never re-mute. The ``volume_muted`` event was already declared in the protocol and already handled by the peripheral script — it just had no emitter. Hook one into ``_set_muted`` so every mute transition (both directions) ships the boolean. The peripheral's existing handler clears its cached ``muted`` and switches the animator state back to IDLE automatically. * Change event emitted for mute state * Track unmute by reading the boolean on the muted event c523617 switched LVA to emit `muted` carrying {"muted": bool} in place of the dedicated `volume_muted` event. The ReSpeaker `muted` handler still hardcoded `muted=True`, so it set the flag on mute but never cleared it on unmute. The cached state stuck on, the muted indicator stayed latched, and the button toggle fell out of sync after the first mute (every later press read as already muted). Read `data["muted"]` instead, mirroring the existing `volume_muted` handler, and default to True so a bare `muted` event still reads as muted. Update the peripheral_api docstring, the event and command tables, and the reference handler in peripheral_api.md to document the new payload. * Drop the duplicate muted event on the mute path --------- Co-authored-by: Omar Amin <65174210+omaramin-2000@users.noreply.github.com>
|
OK, let's merge this for now and see if it will have some further updates. Thanks to everyone who helps and shares their thoughts. |
|
Great job! |
florian-asche
left a comment
There was a problem hiding this comment.
@omaramin-2000 can you please have a look at this?
| parser.add_argument( | ||
| "--preferences-file", | ||
| default=_REPO_DIR / "preferences.json", | ||
| help="Directory and file name for the file where the preferences are stored in JSON format", |
There was a problem hiding this comment.
Why does this got reverted?
| ) | ||
| parser.add_argument( | ||
| "--host", | ||
| help="Optional host IP address to bind to (default: Autodetected by network interface)", # 0.0.0.0 is IPv4, None is all interfaces |
There was a problem hiding this comment.
Why does this got reverted?
| ) | ||
| parser.add_argument( | ||
| "--network-interface", | ||
| help="Network interface the application will be listening on (default: will be automatically detected by gateway)", |
There was a problem hiding this comment.
Why does this got reverted?
| parser.add_argument( | ||
| "--enable-thinking-sound", | ||
| action="store_true", | ||
| help="Enable thinking finish sound, when the assistant is done thinking and needed more time to process", |
There was a problem hiding this comment.
Why does this got reverted?
|
|
||
| while attempt <= max_attempts: | ||
| try: | ||
| server = await loop.create_server(lambda: VoiceSatelliteProtocol(state), host=host_ip_address, port=args.port) |
There was a problem hiding this comment.
Why does this got reverted?
| if err.errno == errno.EADDRINUSE: | ||
| message = "address already in use" | ||
| if attempt < max_attempts: | ||
| _LOGGER.warning("Attempt %d/%d failed to bind on address (%s, %s): %s. Retrying in 1 second...", attempt, max_attempts, host_ip_address, args.port, message) |
There was a problem hiding this comment.
Why does this got reverted?
| await asyncio.sleep(1) | ||
| attempt += 1 | ||
| else: | ||
| _LOGGER.exception("All %d attempts failed to bind on address (%s, %s): %s", max_attempts, host_ip_address, args.port, message) |
There was a problem hiding this comment.
Why does this got reverted?
| process_audio_thread.start() | ||
|
|
||
| # Auto discovery (zeroconf, mDNS) | ||
| discovery = HomeAssistantZeroconf(port=args.port, name=state.name, mac_address=state.mac_address, host_ip_address=host_ip_address) |
There was a problem hiding this comment.
Why does this got reverted?
|
Speaking of, is it possible that more features could be added on later other pull requests? By other features, I of course mean features that add on to this feature or pull request. |
Of course |
|
Great! There are some great features that might be nice to have but I'm glad this is getting released now so I can go ahead and start trying to script things. |
|
When do you think a new version of this will be released so I can use this? Or is this already in the new version? That's been released. |
It will be available starting from the next release. |
|
Hi @omaramin-2000 Unfortunately, I receive these errors: Same with root. Any idea? Debug flag did not show any useful information here. Using the demo project https://github.com/respeaker/pixel_ring.git mentioned in https://wiki.seeedstudio.com/ReSpeaker_Mic_Array_v2.0/ works. Happy to help. Please let me know how. |
Use events and commands to control custom onboard leds and buttons. Can be used to communicate with an external Python script via a WebSocket API running in a container alongside LVA.