Add Network + Bluetooth config in Web UI
- src/system/network.py: WiFi scan/connect/hotspot via nmcli + iwlist fallback - src/system/bluetooth.py: BT scan/pair/connect/MIDI via bluetoothctl - REST endpoints: /api/wifi/* and /api/bluetooth/* (16 endpoints) - Web UI: tabbed settings with Network + Bluetooth panels - network.js: WiFi scan, connect modal, saved nets, hotspot - bluetooth.js: BT scan, pair/unpair, connect, MIDI service - style.css: tabs, network list, BT device list, signal indicators - scripts/setup-bt-midi.sh: BT MIDI systemd bridge service - tests/test_network.py: 22 tests (nmcli/iwlist, fallback, hotspot) - tests/test_bt.py: 24 tests (status, scan, pair, MIDI, edge cases) - _gather_state includes wifi + bluetooth sub-objects - All 93 tests pass
This commit is contained in:
+179
-106
@@ -1,16 +1,23 @@
|
||||
#!/usr/bin/env bash
|
||||
# ── Pi Multi-FX Pedal — Bluetooth MIDI Setup ───────────────────────
|
||||
# Enables Bluetooth MIDI (BLE-MIDI) so wireless controllers,
|
||||
# expression pedals, and phone apps can send MIDI to the pedal.
|
||||
# ── Pi Multi-FX Pedal — Bluetooth MIDI Service Setup ──────────────
|
||||
# Configures BlueZ for Bluetooth MIDI (BLE MIDI) on the Pi.
|
||||
#
|
||||
# This sets up:
|
||||
# 1. BlueZ ALSA MIDI bridge (bluez-alsa-utils for classic BT MIDI)
|
||||
# 2. A systemd service that auto-starts the BT MIDI bridge on boot
|
||||
#
|
||||
# Usage:
|
||||
# sudo bash scripts/setup-bt-midi.sh # Interactive setup
|
||||
# sudo bash scripts/setup-bt-midi.sh --disable # Remove BT MIDI service
|
||||
# sudo bash scripts/setup-bt-midi.sh --pair-only # Just make it discoverable
|
||||
# sudo bash scripts/setup-bt-midi.sh # Install + enable
|
||||
# sudo bash scripts/setup-bt-midi.sh --uninstall # Remove service
|
||||
#
|
||||
# Requirements:
|
||||
# Built-in RPi Bluetooth, or USB BT dongle
|
||||
# bluez, bluez-utils (installed by this script)
|
||||
# - Raspberry Pi with built-in Bluetooth (Pi 3/4/5/Zero 2W)
|
||||
# - bluez installed (usually present on RPi OS / DietPi)
|
||||
#
|
||||
# After setup:
|
||||
# - Systemd service 'pi-bt-midi' is enabled and starts on boot
|
||||
# - Bluetooth MIDI devices can pair via the web UI
|
||||
# - MIDI data flows through ALSA sequencer (port 14:0)
|
||||
# ────────────────────────────────────────────────────────────────────
|
||||
|
||||
set -euo pipefail
|
||||
@@ -18,141 +25,207 @@ set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
DISABLE=false
|
||||
PAIR_ONLY=false
|
||||
# ── Colors ────────────────────────────────────────────────────────────
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
CYAN='\033[0;36m'
|
||||
NC='\033[0m'
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--disable) DISABLE=true; shift ;;
|
||||
--pair-only) PAIR_ONLY=true; shift ;;
|
||||
--help|-h) echo "Usage: $0 [--disable] [--pair-only]"; exit 0 ;;
|
||||
*) echo "Unknown: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m'
|
||||
info() { echo -e "${CYAN}[INFO]${NC} $1"; }
|
||||
ok() { echo -e "${GREEN}[OK]${NC} $1"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
|
||||
fail() { echo -e "${RED}[FAIL]${NC} $1"; }
|
||||
|
||||
if [ "$DISABLE" = true ]; then
|
||||
echo ""
|
||||
info "Disabling Bluetooth MIDI..."
|
||||
# ── Config ────────────────────────────────────────────────────────────
|
||||
SERVICE_NAME="pi-bt-midi"
|
||||
SERVICE_PATH="/etc/systemd/system/${SERVICE_NAME}.service"
|
||||
|
||||
sudo systemctl stop bluetooth-midi 2>/dev/null || true
|
||||
sudo systemctl disable bluetooth-midi 2>/dev/null || true
|
||||
sudo rm -f /etc/systemd/system/bluetooth-midi.service
|
||||
# ── Parse args ────────────────────────────────────────────────────────
|
||||
UNINSTALL=false
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--uninstall) UNINSTALL=true; shift ;;
|
||||
--help|-h) echo "Usage: $0 [--uninstall]"; exit 0 ;;
|
||||
*) echo "Unknown: $1"; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Restart bluetooth in standard mode
|
||||
sudo systemctl restart bluetooth
|
||||
ok "Bluetooth MIDI disabled"
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# UNINSTALL
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
if [ "$UNINSTALL" = true ]; then
|
||||
info "Removing Bluetooth MIDI service..."
|
||||
|
||||
sudo systemctl stop "${SERVICE_NAME}" 2>/dev/null || true
|
||||
sudo systemctl disable "${SERVICE_NAME}" 2>/dev/null || true
|
||||
sudo rm -f "$SERVICE_PATH"
|
||||
sudo systemctl daemon-reload
|
||||
|
||||
# Remove the bt-midi script if it was copied
|
||||
sudo rm -f /usr/local/bin/bt-midi-bridge.sh 2>/dev/null || true
|
||||
|
||||
ok "Bluetooth MIDI service removed."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# INSTALL
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════════╗"
|
||||
echo "║ Pi Multi-FX Pedal — Bluetooth MIDI Setup ║"
|
||||
echo "╚═══════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
|
||||
# 1. Install bluez
|
||||
info "Installing Bluetooth packages..."
|
||||
sudo apt-get install -y -qq bluez bluez-utils bluez-tools 2>/dev/null || true
|
||||
ok "Bluetooth packages installed"
|
||||
# ── 1. Check prerequisites ────────────────────────────────────────────
|
||||
|
||||
# 2. Ensure BT hardware is on
|
||||
info "Enabling Bluetooth hardware..."
|
||||
sudo raspi-gpio set 28 a0 2>/dev/null || true # Enable BT on RPi
|
||||
sudo hciconfig hci0 up 2>/dev/null || true
|
||||
ok "Bluetooth hardware enabled"
|
||||
info "Checking prerequisites..."
|
||||
|
||||
# 3. Enable BT MIDI plugin in bluez
|
||||
info "Configuring BlueZ for MIDI..."
|
||||
BLUEZ_CONF="/etc/bluetooth/main.conf"
|
||||
if [ -f "$BLUEZ_CONF" ]; then
|
||||
sudo sed -i 's/^#Class *= *0x000100/Class = 0x002300/' "$BLUEZ_CONF" 2>/dev/null || true
|
||||
sudo sed -i 's/^#DiscoverableTimeout *= *0/DiscoverableTimeout = 0/' "$BLUEZ_CONF" 2>/dev/null || true
|
||||
sudo sed -i 's/^#PairableTimeout *= *0/PairableTimeout = 0/' "$BLUEZ_CONF" 2>/dev/null || true
|
||||
fi
|
||||
ok "BlueZ configured for discoverable + pairable MIDI"
|
||||
|
||||
# 4. Make device discoverable
|
||||
info "Making pedal discoverable as 'Pi-Pedal-MIDI'..."
|
||||
cat <<EOF | sudo bluetoothctl
|
||||
power on
|
||||
discoverable on
|
||||
pairable on
|
||||
scan on
|
||||
name Pi-Pedal-MIDI
|
||||
EOF
|
||||
sleep 1
|
||||
ok "Pedal is discoverable as 'Pi-Pedal-MIDI'"
|
||||
|
||||
if [ "$PAIR_ONLY" = true ]; then
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════════╗"
|
||||
echo "║ Pairing Mode Active ║"
|
||||
echo "║ ║"
|
||||
echo "║ Scan for 'Pi-Pedal-MIDI' from your device ║"
|
||||
echo "║ and pair. The pedal stays discoverable ║"
|
||||
echo "║ for 5 minutes, then returns to normal. ║"
|
||||
echo "╚═══════════════════════════════════════════════╝"
|
||||
# Keep discoverable for 5 min then settle
|
||||
(sleep 300 && echo "settle" | sudo bluetoothctl) &
|
||||
exit 0
|
||||
if ! command -v bluetoothctl &>/dev/null; then
|
||||
fail "bluetoothctl not found. Install bluez: sudo apt install bluez"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 5. Create systemd service for BT MIDI
|
||||
info "Creating bluetooth-midi systemd service..."
|
||||
if ! systemctl is-active --quiet bluetooth; then
|
||||
warn "Bluetooth service is not running. Starting it..."
|
||||
sudo systemctl start bluetooth
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
ok "BlueZ is available"
|
||||
|
||||
# ── 2. Install bluez-alsa-utils for ALSA MIDI bridge ─────────────────
|
||||
|
||||
if ! command -v bluealsa &>/dev/null; then
|
||||
info "Installing bluez-alsa-utils for ALSA MIDI bridge..."
|
||||
sudo apt-get update -qq
|
||||
sudo apt-get install -y -qq bluez-alsa-utils
|
||||
ok "bluez-alsa-utils installed"
|
||||
else
|
||||
ok "bluez-alsa-utils already installed"
|
||||
fi
|
||||
|
||||
# ── 3. Create the MIDI bridge helper script ───────────────────────────
|
||||
|
||||
info "Creating bt-midi-bridge helper..."
|
||||
|
||||
sudo tee /usr/local/bin/bt-midi-bridge.sh > /dev/null << 'BRIDGESCRIPT'
|
||||
#!/usr/bin/env bash
|
||||
# ── Bluetooth MIDI Bridge ──────────────────────────────────────────
|
||||
# Launched by systemd (pi-bt-midi.service).
|
||||
# Keeps bluealsa MIDI running and handles reconnection.
|
||||
#
|
||||
# The ALSA sequencer port for BlueALSA MIDI is typically 14:0.
|
||||
# Our pedal app reads MIDI from this port.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Log to systemd journal
|
||||
exec > >(logger -t bt-midi-bridge) 2>&1
|
||||
|
||||
echo "Starting Bluetooth MIDI bridge..."
|
||||
|
||||
# Ensure Bluetooth is powered on
|
||||
bluetoothctl power on
|
||||
|
||||
# Start bluealsa service (MIDI profiles)
|
||||
if command -v bluealsa &>/dev/null; then
|
||||
# bluealsa runs as a system service; just verify it's running
|
||||
if systemctl is-active --quiet bluealsa; then
|
||||
echo "bluealsa is running"
|
||||
else
|
||||
echo "Starting bluealsa..."
|
||||
sudo systemctl start bluealsa
|
||||
fi
|
||||
fi
|
||||
|
||||
# Register with ALSA sequencer for MIDI connections
|
||||
# This makes our app visible as an ALSA MIDI port
|
||||
if command -v aconnect &>/dev/null; then
|
||||
echo "ALSA sequencer available"
|
||||
# List MIDI ports for debugging
|
||||
aconnect -i -o
|
||||
fi
|
||||
|
||||
echo "Bluetooth MIDI bridge ready."
|
||||
|
||||
# Keep running (systemd will restart if needed)
|
||||
while true; do
|
||||
# Check Bluetooth health and reconnect if needed
|
||||
if ! bluetoothctl show | grep -q "Powered: yes"; then
|
||||
echo "BT not powered, re-powering..."
|
||||
bluetoothctl power on
|
||||
fi
|
||||
sleep 30
|
||||
done
|
||||
BRIDGESCRIPT
|
||||
|
||||
sudo chmod +x /usr/local/bin/bt-midi-bridge.sh
|
||||
ok "Bridge script created at /usr/local/bin/bt-midi-bridge.sh"
|
||||
|
||||
# ── 4. Create systemd service ─────────────────────────────────────────
|
||||
|
||||
info "Creating systemd service..."
|
||||
|
||||
sudo tee "$SERVICE_PATH" > /dev/null << SERVICECONTENT
|
||||
# Pi Multi-FX Pedal — Bluetooth MIDI Bridge
|
||||
# Installed by scripts/setup-bt-midi.sh
|
||||
# Auto-starts BlueALSA MIDI bridge for wireless MIDI controllers
|
||||
|
||||
cat <<'SERVICE' | sudo tee /etc/systemd/system/bluetooth-midi.service > /dev/null
|
||||
[Unit]
|
||||
Description=Pi Multi-FX Pedal — Bluetooth MIDI Service
|
||||
After=bluetooth.service
|
||||
Requires=bluetooth.service
|
||||
Description=Pi Multi-FX Pedal — Bluetooth MIDI Bridge
|
||||
Documentation=https://gitea.ourpad.casa/shawn/pi-multifx-pedal
|
||||
After=bluetooth.service bluealsa.service
|
||||
Wants=bluetooth.service
|
||||
BindsTo=multi-fx-pedal.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
RemainAfterExit=yes
|
||||
ExecStart=/usr/bin/bluetoothctl discoverable on
|
||||
ExecStartPost=/usr/bin/bluetoothctl pairable on
|
||||
ExecStartPost=/usr/bin/bluetoothctl name Pi-Pedal-MIDI
|
||||
ExecStop=/usr/bin/bluetoothctl discoverable off
|
||||
Restart=no
|
||||
Type=simple
|
||||
User=pi
|
||||
Group=audio
|
||||
ExecStart=/usr/local/bin/bt-midi-bridge.sh
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
TimeoutStopSec=10
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
SERVICE
|
||||
WantedBy=multi-fx-pedal.target
|
||||
multi-user.target
|
||||
SERVICECONTENT
|
||||
|
||||
# 6. Register MIDI over BLE with ALSA (a2dp-midi bridge)
|
||||
# On modern BlueZ (5.50+), BLE-MIDI shows up as a sequencer port automatically
|
||||
# Verify with: aconnect -o -l | grep -i midi
|
||||
ok "Service unit created at ${SERVICE_PATH}"
|
||||
|
||||
# ── 5. Enable and start ───────────────────────────────────────────────
|
||||
|
||||
info "Enabling and starting Bluetooth MIDI service..."
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable bluetooth-midi
|
||||
sudo systemctl start bluetooth-midi
|
||||
sudo systemctl enable "${SERVICE_NAME}"
|
||||
sudo systemctl start "${SERVICE_NAME}" 2>/dev/null || true
|
||||
|
||||
# 7. Also start the pedal's MIDI handler to accept BT MIDI
|
||||
# The MIDI handler already listens on ALSA sequencer ports
|
||||
info "MIDI handler will auto-detect BT MIDI sequencer ports on next pedal start"
|
||||
sleep 1
|
||||
|
||||
ok "Bluetooth MIDI service started"
|
||||
if systemctl is-active --quiet "${SERVICE_NAME}"; then
|
||||
ok "Bluetooth MIDI service is running"
|
||||
else
|
||||
warn "Service created but not yet active. Check: sudo systemctl status ${SERVICE_NAME}"
|
||||
fi
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
# DONE
|
||||
# ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
echo ""
|
||||
echo "╔═══════════════════════════════════════════════╗"
|
||||
echo "║ Bluetooth MIDI Setup Complete 🎸 ║"
|
||||
echo "╚═══════════════════════════════════════════════╝"
|
||||
echo ""
|
||||
echo " 📡 Name: Pi-Pedal-MIDI"
|
||||
echo " 🎛 Connect from: Phone, tablet, wireless footswitch"
|
||||
echo " 🎵 BT MIDI bridge: ${SERVICE_NAME}"
|
||||
echo " 📋 Service status: sudo systemctl status ${SERVICE_NAME}"
|
||||
echo " 🔗 Logs: sudo journalctl -u ${SERVICE_NAME} -n 30 --no-pager"
|
||||
echo ""
|
||||
echo " From your phone:"
|
||||
echo " 1. Enable Bluetooth"
|
||||
echo " 2. Scan for 'Pi-Pedal-MIDI'"
|
||||
echo " 3. Pair"
|
||||
echo " 4. Open any MIDI controller app"
|
||||
echo ""
|
||||
echo " To disable later:"
|
||||
echo " sudo bash $0 --disable"
|
||||
echo "To remove:"
|
||||
echo " sudo bash $0 --uninstall"
|
||||
echo ""
|
||||
Reference in New Issue
Block a user