From 00188fa5da5109a28ce7f2ab497c1f8f1283b223 Mon Sep 17 00:00:00 2001 From: Luis Andrade Date: Thu, 8 Feb 2024 01:05:42 -0500 Subject: [PATCH 01/10] led brightness argument --- docs/tutorial_2mic.md | 3 +++ examples/2mic_service.py | 7 ++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/docs/tutorial_2mic.md b/docs/tutorial_2mic.md index dd2b805..7231044 100644 --- a/docs/tutorial_2mic.md +++ b/docs/tutorial_2mic.md @@ -385,4 +385,7 @@ Try a voice command and see if the LEDs change. Use `journalctl` to check the lo journalctl -u 2mic_leds.service -f ``` +If you encounter any issues, you can add the `--debug` argument to the command line to increase the log level. +To control the brightness of the LEDS, use the `--led-brightness ` argument, which accepts integer numbers from 1 to 31. + Make sure to run `sudo systemctl daemon-reload` every time you make changes to the service. diff --git a/examples/2mic_service.py b/examples/2mic_service.py index ac58c4a..929e4d8 100644 --- a/examples/2mic_service.py +++ b/examples/2mic_service.py @@ -41,8 +41,8 @@ async def main() -> None: """Main entry point.""" parser = argparse.ArgumentParser() parser.add_argument("--uri", required=True, help="unix:// or tcp://") - # parser.add_argument("--debug", action="store_true", help="Log DEBUG messages") + parser.add_argument("--led-brightness", type=int, default=31, help="LED brightness (integer from 1 to 31)") args = parser.parse_args() logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO) @@ -54,7 +54,7 @@ async def main() -> None: led_power = gpiozero.LED(LEDS_GPIO, active_high=False) led_power.on() - leds = APA102(num_led=NUM_LEDS) + leds = APA102(num_led=NUM_LEDS, global_brightness=args.led_brightness) # Start server server = AsyncServer.from_uri(args.uri) @@ -148,7 +148,7 @@ class APA102: def __init__( self, num_led, - global_brightness=MAX_BRIGHTNESS, + global_brightness, order="rgb", bus=0, device=1, @@ -162,6 +162,7 @@ def __init__( self.global_brightness = self.MAX_BRIGHTNESS else: self.global_brightness = global_brightness + _LOGGER.debug("LED brightness: %d", self.global_brightness) self.leds = [self.LED_START, 0, 0, 0] * self.num_led # Pixel buffer self.spi = spidev.SpiDev() # Init the SPI device From 61ae4ce68c2a066a6852bc17eb4a7804ce24e119 Mon Sep 17 00:00:00 2001 From: Luis Andrade Date: Mon, 12 Feb 2024 12:49:34 -0500 Subject: [PATCH 02/10] remove double volume --- wyoming_satellite/satellite.py | 1 - 1 file changed, 1 deletion(-) diff --git a/wyoming_satellite/satellite.py b/wyoming_satellite/satellite.py index 31aba25..81d9307 100644 --- a/wyoming_satellite/satellite.py +++ b/wyoming_satellite/satellite.py @@ -594,7 +594,6 @@ async def _play_wav( for event in wav_to_events( wav_path, samples_per_chunk=self.settings.snd.samples_per_chunk, - volume_multiplier=self.settings.snd.volume_multiplier, ): await self.event_to_snd(event) except Exception: From 69ceeef566ad64dce5941778477cdf71e11f0732 Mon Sep 17 00:00:00 2001 From: Tobias Buhlinger Date: Tue, 27 Feb 2024 22:14:12 +0100 Subject: [PATCH 03/10] Add example for ReSpeaker USB 4mic array v2.0 --- docs/tutorial_2mic.md | 7 +++ examples/usbmic_service.py | 103 +++++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 examples/usbmic_service.py diff --git a/docs/tutorial_2mic.md b/docs/tutorial_2mic.md index dd2b805..b5fe8b3 100644 --- a/docs/tutorial_2mic.md +++ b/docs/tutorial_2mic.md @@ -305,6 +305,13 @@ python3 -m venv --system-site-packages .venv .venv/bin/pip3 install 'wyoming==1.5.2' ``` +In case you use a ReSpeaker USB 4mic array v2.0, additionally install pixel-ring: + +```sh +.venv/bin/pip3 install 'pixel-ring' +``` + + The `--system-site-packages` argument is used to access the pre-installed `gpiozero` and `spidev` Python packages. If these are **not already installed** in your system, run: ```sh diff --git a/examples/usbmic_service.py b/examples/usbmic_service.py new file mode 100644 index 0000000..2898913 --- /dev/null +++ b/examples/usbmic_service.py @@ -0,0 +1,103 @@ +#!/usr/bin/env python3 +"""Controls the LEDs on the ReSpeaker Mic Array v2.0 (USB) .""" +import argparse +import asyncio +import logging +import time +from functools import partial + +from wyoming.event import Event +from wyoming.satellite import ( + SatelliteConnected, + SatelliteDisconnected, + StreamingStarted, + StreamingStopped, +) +from wyoming.snd import Played +from wyoming.server import AsyncEventHandler, AsyncServer +from wyoming.vad import VoiceStarted, VoiceStopped +from wyoming.wake import Detection + +from pixel_ring import pixel_ring + +_LOGGER = logging.getLogger() + +async def main() -> None: + """Main entry point.""" + parser = argparse.ArgumentParser() + parser.add_argument("--uri", required=True, help="unix:// or tcp://") + parser.add_argument("--debug", action="store_true", help="Log DEBUG messages") + args = parser.parse_args() + + logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO) + _LOGGER.debug(args) + + _LOGGER.info("Ready") + + # Turn on power to LEDs + pixel_ring.set_color_palette(0x0080ff, 0x007a37) + pixel_ring.think() + await asyncio.sleep(3) + pixel_ring.off() + + # Start server + server = AsyncServer.from_uri(args.uri) + + try: + await server.run(partial(LEDsEventHandler, args)) + except KeyboardInterrupt: + pass + finally: + pixel_ring.off() + + +class LEDsEventHandler(AsyncEventHandler): + """Event handler for clients.""" + + def __init__( + self, + cli_args: argparse.Namespace, + *args, + **kwargs, + ) -> None: + super().__init__(*args, **kwargs) + + self.cli_args = cli_args + self.client_id = str(time.monotonic_ns()) + + _LOGGER.debug("Client connected: %s", self.client_id) + + async def handle_event(self, event: Event) -> bool: + _LOGGER.debug(event) + + if Detection.is_type(event.type): + _LOGGER.debug("Detection") + pixel_ring.wakeup() + elif VoiceStarted.is_type(event.type): + _LOGGER.debug("VoiceStarted") + pixel_ring.speak() + elif VoiceStopped.is_type(event.type): + _LOGGER.debug("VoiceStopped") + pixel_ring.spin() + elif StreamingStopped.is_type(event.type): + _LOGGER.debug("StreamingStopped") + pixel_ring.off() + elif SatelliteConnected.is_type(event.type): + _LOGGER.debug("SatelliteConnected") + pixel_ring.think() + await asyncio.sleep(2) + pixel_ring.off() + elif Played.is_type(event.type): + _LOGGER.debug("Played") + pixel_ring.off() + elif SatelliteDisconnected.is_type(event.type): + _LOGGER.debug("SatelliteDisconnected") + pixel_ring.mono(0xff0000) + + return True + +if __name__ == "__main__": + try: + asyncio.run(main()) + except KeyboardInterrupt: + pass From f0297415ed4b9ddcc7de96f7c8b237db2f314aa0 Mon Sep 17 00:00:00 2001 From: tannisroot <10602045+tannisroot@users.noreply.github.com> Date: Wed, 22 May 2024 09:09:16 +0300 Subject: [PATCH 04/10] Change docs to suggest bookworm based Pi OS --- docs/tutorial_2mic.md | 2 +- docs/tutorial_installer.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorial_2mic.md b/docs/tutorial_2mic.md index dd2b805..1850340 100644 --- a/docs/tutorial_2mic.md +++ b/docs/tutorial_2mic.md @@ -6,7 +6,7 @@ This tutorial should work for almost any Raspberry Pi and USB microphone. Audio ## Install OS -Follow instructions to [install Raspberry Pi OS](https://www.raspberrypi.com/software/). Under "Choose OS", pick "Raspberry Pi OS (other)" and "Raspberry Pi OS (Legacy, **64-bit**) Lite". +Follow instructions to [install Raspberry Pi OS](https://www.raspberrypi.com/software/). Under "Choose OS", pick "Raspberry Pi OS (other)" and "Raspberry Pi OS (**64-bit**) Lite". When asking if you'd like to apply customization settings, choose "Edit Settings" and: diff --git a/docs/tutorial_installer.md b/docs/tutorial_installer.md index 11d8e58..c6b16af 100644 --- a/docs/tutorial_installer.md +++ b/docs/tutorial_installer.md @@ -4,7 +4,7 @@ Create a voice satellite using a Raspberry Pi 3+ and USB microphone and speakers ## Install OS -Follow instructions to [install Raspberry Pi OS](https://www.raspberrypi.com/software/). Under "Choose OS", pick "Raspberry Pi OS (other)" and "Raspberry Pi OS (Legacy, **64-bit**) Lite". +Follow instructions to [install Raspberry Pi OS](https://www.raspberrypi.com/software/). Under "Choose OS", pick "Raspberry Pi OS (other)" and "Raspberry Pi OS (**64-bit**) Lite". When asking if you'd like to apply customization settings, choose "Edit Settings" and: From 2f6ec1d3b05bcc7cfd89cc08167e723f51b4c516 Mon Sep 17 00:00:00 2001 From: Chad Condon Date: Sun, 16 Jun 2024 12:24:43 -0700 Subject: [PATCH 05/10] Include trace in import failure errors --- wyoming_satellite/__main__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wyoming_satellite/__main__.py b/wyoming_satellite/__main__.py index f878081..087f6f2 100644 --- a/wyoming_satellite/__main__.py +++ b/wyoming_satellite/__main__.py @@ -308,14 +308,14 @@ async def main() -> None: try: import webrtc_noise_gain # noqa: F401 except ImportError: - _LOGGER.fatal("Install extras for webrtc") + _LOGGER.exception("Install extras for webrtc") sys.exit(1) if needs_silero(args): try: import pysilero_vad # noqa: F401 except ImportError: - _LOGGER.fatal("Install extras for silerovad") + _LOGGER.exception("Install extras for silerovad") sys.exit(1) if args.awake_wav and (not Path(args.awake_wav).is_file()): From c6d1dec91801fc2056c5df979cd7e662fd4cb185 Mon Sep 17 00:00:00 2001 From: Chad Condon Date: Sun, 16 Jun 2024 12:26:27 -0700 Subject: [PATCH 06/10] Clarify import error message --- wyoming_satellite/__main__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wyoming_satellite/__main__.py b/wyoming_satellite/__main__.py index 087f6f2..4cff57b 100644 --- a/wyoming_satellite/__main__.py +++ b/wyoming_satellite/__main__.py @@ -308,14 +308,14 @@ async def main() -> None: try: import webrtc_noise_gain # noqa: F401 except ImportError: - _LOGGER.exception("Install extras for webrtc") + _LOGGER.exception("Extras for webrtc are not installed") sys.exit(1) if needs_silero(args): try: import pysilero_vad # noqa: F401 except ImportError: - _LOGGER.exception("Install extras for silerovad") + _LOGGER.exception("Extras for silerovad are not installed") sys.exit(1) if args.awake_wav and (not Path(args.awake_wav).is_file()): From 2b394504a0db9259620db65e536fbf6ca87d2546 Mon Sep 17 00:00:00 2001 From: tannisroot <10602045+tannisroot@users.noreply.github.com> Date: Sat, 8 Jun 2024 18:36:32 +0300 Subject: [PATCH 07/10] Adjust compile threads for low memory boards --- etc/install-respeaker-drivers.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/etc/install-respeaker-drivers.sh b/etc/install-respeaker-drivers.sh index 520447d..8a0169f 100755 --- a/etc/install-respeaker-drivers.sh +++ b/etc/install-respeaker-drivers.sh @@ -43,12 +43,18 @@ mod='seeed-voicecard' src='./' kernel="$(uname -r)" marker='0.0.0' +threads="$(getconf _NPROCESSORS_ONLN)" +memory="$(LANG=C free -m|awk '/^Mem:/{print $2}')" + +if [ "$memory" -le 512 ] && [ "$threads" -gt 2 ]; then +threads=2 +fi mkdir -p "/usr/src/${mod}-${ver}" cp -a "${src}"/* "/usr/src/${mod}-${ver}/" dkms add -m "${mod}" -v "${ver}" -dkms build -k "${kernel}" -m "${mod}" -v "${ver}" && { +dkms build -k "${kernel}" -m "${mod}" -v "${ver}" -j "${threads}" && { dkms install --force -k "${kernel}" -m "${mod}" -v "${ver}" } From a80c7724a6097a25981a39cf37a66bfaa7371f44 Mon Sep 17 00:00:00 2001 From: Aleksandr Oleinikov <10602045+tannisroot@users.noreply.github.com> Date: Wed, 26 Jun 2024 21:42:33 +0300 Subject: [PATCH 08/10] suggestions by Mike Co-authored-by: Michael Hansen --- etc/install-respeaker-drivers.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/etc/install-respeaker-drivers.sh b/etc/install-respeaker-drivers.sh index 8a0169f..4e7ff22 100755 --- a/etc/install-respeaker-drivers.sh +++ b/etc/install-respeaker-drivers.sh @@ -46,7 +46,7 @@ marker='0.0.0' threads="$(getconf _NPROCESSORS_ONLN)" memory="$(LANG=C free -m|awk '/^Mem:/{print $2}')" -if [ "$memory" -le 512 ] && [ "$threads" -gt 2 ]; then +if [ "${memory}" -le 512 ] && [ "${threads}" -gt 2 ]; then threads=2 fi From 6d11883dcb6a1aada874a61c664f3dc50b7c9dcf Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Mon, 1 Jul 2024 11:21:52 -0500 Subject: [PATCH 09/10] Restrict range --- examples/2mic_service.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/examples/2mic_service.py b/examples/2mic_service.py index 929e4d8..0b44e62 100644 --- a/examples/2mic_service.py +++ b/examples/2mic_service.py @@ -42,7 +42,13 @@ async def main() -> None: parser = argparse.ArgumentParser() parser.add_argument("--uri", required=True, help="unix:// or tcp://") parser.add_argument("--debug", action="store_true", help="Log DEBUG messages") - parser.add_argument("--led-brightness", type=int, default=31, help="LED brightness (integer from 1 to 31)") + parser.add_argument( + "--led-brightness", + type=int, + choices=range(1, 32), + default=31, + help="LED brightness (integer from 1 to 31)", + ) args = parser.parse_args() logging.basicConfig(level=logging.DEBUG if args.debug else logging.INFO) From a2bb7c8f57162a2ea5a10b56eb67334f92ff5b8e Mon Sep 17 00:00:00 2001 From: Michael Hansen Date: Mon, 1 Jul 2024 11:33:06 -0500 Subject: [PATCH 10/10] Add run_usbmic script --- script/run_usbmic | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100755 script/run_usbmic diff --git a/script/run_usbmic b/script/run_usbmic new file mode 100755 index 0000000..665cdbe --- /dev/null +++ b/script/run_usbmic @@ -0,0 +1,15 @@ +#!/usr/bin/env python3 +import sys +import subprocess +import venv +from pathlib import Path + +_DIR = Path(__file__).parent +_PROGRAM_DIR = _DIR.parent +_VENV_DIR = _PROGRAM_DIR / ".venv" + +context = venv.EnvBuilder().ensure_directories(_VENV_DIR) +subprocess.check_call( + [context.env_exe, str(_PROGRAM_DIR / "examples" / "usbmic_service.py")] + + sys.argv[1:] +)