Skip to content

Commit

Permalink
Merge branch 'master' into docker
Browse files Browse the repository at this point in the history
  • Loading branch information
preimmortal authored Jan 21, 2024
2 parents 79dee35 + 20bbd3c commit 865b407
Show file tree
Hide file tree
Showing 36 changed files with 2,436 additions and 83 deletions.
1 change: 1 addition & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@
!script/run
!wyoming_satellite/*.py
!wyoming_satellite/utils
!wyoming_satellite/VERSION
!docker/run
!sounds/*.wav
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## 1.1.1

- Bump to wyoming 1.5.2 (package fix)

## 1.1.0

- Bump to wyoming 1.5.1
- Send wyoming-satellite version in `info` message
- Ping server if supported (faster awareness of disconnection)
- Support `pause-satellite` message
- Stop streaming/wake word detection as soon as `pause-satellite` is received or server disconnects
- Mute microphone when awake WAV is playing

## 1.0.0

- Initial release
Expand Down
1 change: 1 addition & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
include requirements.txt
include VERSION
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ Requires:

## Installation

Install the necessary system dependencies:

``` sh
sudo apt-get install python3-venv python3-pip
```

Then run the install script:

``` sh
script/setup
```
Expand Down Expand Up @@ -168,5 +176,7 @@ Satellites can respond to events from the server by running commands:
* `--tts-start-command` - text-to-speech response started (no stdin)
* `--tts-stop-command` - text-to-speech response stopped (no stdin)
* `--error-command` - an error was sent from the server (text on stdin)
* `--connected-command` - satellite connected to server
* `--disconnected-command` - satellite disconnected from server

For more advanced scenarios, use an event service (`--event-uri`). See `wyoming_satellite/example_event_client.py` for a basic client that just logs events.
5 changes: 3 additions & 2 deletions docs/tutorial_2mic.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ python3 -m venv .venv
.venv/bin/pip3 install \
-f 'https://synesthesiam.github.io/prebuilt-apps/' \
-r requirements.txt \
-r requirements_extra.txt
-r requirements_audio_enhancement.txt \
-r requirements_vad.txt
```

If the installation was successful, you should be able to run:
Expand Down Expand Up @@ -301,7 +302,7 @@ cd wyoming-satellite/examples
python3 -m venv --system-site-packages .venv
.venv/bin/pip3 install --upgrade pip
.venv/bin/pip3 install --upgrade wheel setuptools
.venv/bin/pip3 install 'wyoming==1.4.1'
.venv/bin/pip3 install 'wyoming==1.5.2'
```

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:
Expand Down
75 changes: 75 additions & 0 deletions docs/tutorial_installer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Tutorial with Installer

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".

When asking if you'd like to apply customization settings, choose "Edit Settings" and:

* Set a username/password
* Configure the wireless LAN
* Under the Services tab, enable SSH and use password authentication

## Install Dependencies

After flashing and booting the satellite, connect to it over SSH using the username/password you configured during flashing.

**On the satellite**, make sure system dependencies are installed:

```sh
sudo apt-get update
sudo apt-get install --no-install-recommends \
git \
python3-venv
```

Clone the `wyoming-satellite` repository:

```sh
git clone https://github.com/rhasspy/wyoming-satellite.git
```

Now you can run the installer:

```sh
cd wyoming-satellite/
python3 -m installer
```

## Satellite

Under the "Satellite" menu, select "Satellite Type" and choose "Local wake word detection" (with the space bar).

## Microphone

Make sure you USB microphone is plugged in.

Under the "Microphone" menu, select "Autodetect", and speak loudly into the microphone for a few seconds.

In "Audio Settings", set "Noise Suppression" to "Medium" and "Auto Gain" to 15.

## Speakers

Make sure your USB speakers are plugged in.

Under the "Speakers" menu, choose "Test All Speakers". For each device, choose "Play Sound" and listen. If you hear the sound, select "Choose This Device"; otherwise, select "Next Device".

In "Toggle Feedback Sounds", enable "On wake-up" and "After voice command" (with the space bar).

## Wake Word

Under the "Wake Word" menu, select "Wake Word System" and choose "openWakeWord" (with the space bar). When prompted, install openWakeWord.

In the "openWakeWord" menu, choose "Download Community Wake Words". Back in the "Wake Word" menu, select "Choose Wake Word" and select one (with the space bar).

## Apply Settings

From the main menu, select "Apply Settings" and enter your password.

Check logs with:

```sh
sudo journalctl -f -u wyoming-satellite.service
```
17 changes: 16 additions & 1 deletion examples/2mic_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@
import spidev
from wyoming.asr import Transcript
from wyoming.event import Event
from wyoming.satellite import RunSatellite, StreamingStarted, StreamingStopped
from wyoming.satellite import (
RunSatellite,
SatelliteConnected,
SatelliteDisconnected,
StreamingStarted,
StreamingStopped,
)
from wyoming.server import AsyncEventHandler, AsyncServer
from wyoming.vad import VoiceStarted
from wyoming.wake import Detection
Expand Down Expand Up @@ -107,6 +113,15 @@ async def handle_event(self, event: Event) -> bool:
self.color(_BLACK)
elif RunSatellite.is_type(event.type):
self.color(_BLACK)
elif SatelliteConnected.is_type(event.type):
# Flash
for _ in range(3):
self.color(_GREEN)
await asyncio.sleep(0.3)
self.color(_BLACK)
await asyncio.sleep(0.3)
elif SatelliteDisconnected.is_type(event.type):
self.color(_RED)

return True

Expand Down
17 changes: 16 additions & 1 deletion examples/4mic_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@
import spidev
from wyoming.asr import Transcript
from wyoming.event import Event
from wyoming.satellite import RunSatellite, StreamingStarted, StreamingStopped
from wyoming.satellite import (
RunSatellite,
SatelliteConnected,
SatelliteDisconnected,
StreamingStarted,
StreamingStopped,
)
from wyoming.server import AsyncEventHandler, AsyncServer
from wyoming.vad import VoiceStarted
from wyoming.wake import Detection
Expand Down Expand Up @@ -107,6 +113,15 @@ async def handle_event(self, event: Event) -> bool:
self.color(_BLACK)
elif RunSatellite.is_type(event.type):
self.color(_BLACK)
elif SatelliteConnected.is_type(event.type):
# Flash
for _ in range(3):
self.color(_GREEN)
await asyncio.sleep(0.3)
self.color(_BLACK)
await asyncio.sleep(0.3)
elif SatelliteDisconnected.is_type(event.type):
self.color(_RED)

return True

Expand Down
1 change: 1 addition & 0 deletions installer/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Command-line installer."""
178 changes: 178 additions & 0 deletions installer/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
"""Command-line installer."""
import logging
from typing import List, Optional

from .const import LOCAL_DIR, PROGRAM_DIR, SatelliteType, Settings
from .drivers import install_drivers
from .microphone import configure_microphone
from .packages import (
can_import,
install_packages,
install_packages_nogui,
packages_installed,
)
from .satellite import configure_satellite
from .services import generate_services, install_services, stop_services
from .speakers import configure_speakers
from .wake_word import configure_wake_word
from .whiptail import ItemType, error, menu, msgbox, passwordbox, run_with_gauge

_LOGGER = logging.getLogger()


def main() -> None:
LOCAL_DIR.mkdir(parents=True, exist_ok=True)
logging.basicConfig(
filename=LOCAL_DIR / "installer.log", filemode="w", level=logging.DEBUG
)

settings = Settings.load()

if not packages_installed("whiptail"):
install_packages_nogui("whiptail")

choice: Optional[str] = None
while True:
choice = main_menu(choice)

if choice == "satellite":
configure_satellite(settings)
elif choice == "microphone":
configure_microphone(settings)
elif choice == "speakers":
configure_speakers(settings)
elif choice == "wake":
configure_wake_word(settings)
elif choice == "drivers":
install_drivers(settings)
elif choice == "apply":
apply_settings(settings)
else:
break


def main_menu(last_choice: Optional[str]) -> Optional[str]:
items: List[ItemType] = [
("satellite", "Satellite"),
("microphone", "Microphone"),
("speakers", "Speakers"),
("wake", "Wake Word"),
("drivers", "Drivers"),
("apply", "Apply Settings"),
]

return menu(
"Main",
items,
selected_item=last_choice,
menu_args=["--ok-button", "Select", "--cancel-button", "Exit"],
)


# -----------------------------------------------------------------------------


def pip_install(*args) -> List[str]:
return [
str(PROGRAM_DIR / ".venv" / "bin" / "pip3"),
"install",
"--extra-index-url",
"https://www.piwheels.org/simple",
"-f",
"https://synesthesiam.github.io/prebuilt-apps/",
] + list(args)


def apply_settings(settings: Settings) -> None:
if settings.mic.device is None:
msgbox("Please configure microphone")
return

if (settings.satellite.type == SatelliteType.WAKE) and (
settings.wake.system is None
):
msgbox("Please set wake word system")
return

password: Optional[str] = None
if not packages_installed("python3-pip", "python3-venv"):
password = passwordbox("sudo password:")
if not password:
return

success = install_packages(
"Installing Python packages...", password, "python3-pip", "python3-venv"
)
if not success:
error("installing pip/venv for Python")
return

# Satellite venv
venv_dir = PROGRAM_DIR / ".venv"
if not venv_dir.exists():
result = run_with_gauge(
"Creating virtual environment...", [str(PROGRAM_DIR / "script" / "setup")]
)
if not result:
error("creating virtual environment")
return

# silero (vad)
if (settings.satellite.type == SatelliteType.VAD) and (
not can_import("pysilero_vad")
):
result = run_with_gauge(
"Installing vad...",
[pip_install("-r", str(PROGRAM_DIR / "requirements_vad.txt"))],
)
if not result:
error("installing vad")
return

# webrtc (audio enhancements)
if ((settings.mic.noise_suppression > 0) or (settings.mic.auto_gain > 0)) and (
not can_import("webrtc_noise_gain")
):
result = run_with_gauge(
"Installing audio enhancements...",
[
pip_install(
"-r", str(PROGRAM_DIR / "requirements_audio_enhancement.txt")
)
],
)
if not result:
error("installing audio enhancements")
return

if (
settings.satellite.event_service_command
and (
("2mic" in settings.satellite.event_service_command)
or ("4mic" in settings.satellite.event_service_command)
)
) and (not can_import("gpiozero", "spidev")):
result = run_with_gauge(
"Installing event requirements...",
[pip_install("-r", str(PROGRAM_DIR / "requirements_respeaker.txt"))],
)
if not result:
error("installing event requirements")
return

generate_services(settings)

if password is None:
password = passwordbox("sudo password:")
if not password:
return

stop_services(password)
install_services(settings, password)


# -----------------------------------------------------------------------------


if __name__ == "__main__":
main()
Loading

0 comments on commit 865b407

Please sign in to comment.