Skip to main content

Overview

Moorcheh voice can play TTS through a Bluetooth speaker on Linux (e.g. Arduino UNO Q) by setting "playback": "bluetooth" in ~/.moorcheh-edge/voice/audio.json. Pairing is done manually with bluetoothctl on the board. There is no fully automated CLI wizard today - headless boards often need the pairing agent registered in the same interactive session.
Keep the USB mic on ALSA (plughw:…) for capture. Only playback switches to Bluetooth.

Prerequisites

sudo apt-get update
sudo apt-get install -y bluez pulseaudio-utils
sudo systemctl enable --now bluetooth
sudo usermod -aG bluetooth $USER
Log out of SSH and back in (or reboot) after adding yourself to the bluetooth group. Verify the adapter:
bluetoothctl show
Expect Powered: yes.

Pair the speaker (interactive)

Put the speaker in pairing mode, then:
bluetoothctl
Inside the bluetoothctl prompt:
power on
pairable on
agent NoInputNoOutput
default-agent
scan on
Leave scan on running. With the speaker in pairing mode, wait 10-15 seconds so it appears in the scan results.

Pick your speaker and note its MAC

Still inside bluetoothctl, list discovered devices:
devices
Example output (yours will differ):
Device AA:BB:CC:DD:EE:FF JBL Flip 5
Device 11:22:33:44:55:66 Some-Other-Phone
  1. Find the line for your Bluetooth speaker - read the name at the end of the line (e.g. JBL Flip 5).
  2. Copy the MAC address from the start of that same line - six pairs of hex digits like AA:BB:CC:DD:EE:FF.
If your speaker does not appear, keep it in pairing mode, wait a few more seconds, and run devices again. Optional: stop scanning once you have the MAC:
scan off

Pair, trust, and connect

Replace AA:BB:CC:DD:EE:FF with the MAC you copied from devices:
pair AA:BB:CC:DD:EE:FF
trust AA:BB:CC:DD:EE:FF
connect AA:BB:CC:DD:EE:FF
quit
Expect Pairing successful and Connection successful before you run quit.
Run agent NoInputNoOutput and default-agent in the same bluetoothctl session before pair. If you see “No agent is registered”, exit and start over in one session.

Point Moorcheh at Bluetooth playback

Edit ~/.moorcheh-edge/voice/audio.json:
{
  "capture": "plughw:0,0",
  "playback": "bluetooth",
  "bt_device": "AA:BB:CC:DD:EE:FF"
}
  • capture - USB mic (from voice setup or voice check)
  • playback - must be "bluetooth" for PipeWire/BlueZ output
  • bt_device - optional MAC hint when multiple bluez_output sinks exist
Test:
moorcheh-edge voice speak --text "Bluetooth speaker test."
moorcheh-edge voice check
Restart the voice server after changing audio config:
moorcheh-edge voice serve --port 8766

Switch back to wired USB speaker

moorcheh-edge voice setup
Or edit audio.json manually:
{
  "capture": "plughw:0,0",
  "playback": "plughw:0,0"
}
Remove bt_device when using wired playback.

PipeWire session on UNO Q

On some UNO Q images the Bluetooth sink appears under the lightdm session while you SSH as arduino. Moorcheh tries the current user first, then lightdm, when "playback": "bluetooth". If playback fails but pactl list sinks short shows a sink under another user:
export MOORCHEH_PULSE_RUNTIME_USER=lightdm
moorcheh-edge voice speak --text "Test"
Optional env vars:
VariablePurpose
MOORCHEH_BT_DEVICEMAC filter (same as bt_device in audio.json)
MOORCHEH_PULSE_RUNTIME_USERForce PipeWire session user
MOORCHEH_AUDIO_PLAYBACKOverride playback (bluetooth or plughw:…)