Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ jobs:
run: pip install -r requirements-dev.txt

- name: Run tests
env:
ASSISTANT_NUMBER: "5550000"
run: python -m pytest -m "not integration" -v

test-angular:
Expand Down
5 changes: 2 additions & 3 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ main.py
| `MEDIA_BACKEND` | `os.environ.get("MEDIA_BACKEND", "mpd")` — `"mpd"` or `"mopidy"` |
| `MPD_HOST` | `os.environ.get("MPD_HOST", "localhost")` |
| `MPD_PORT` | `int(os.environ.get("MPD_PORT", "6600"))` |
| `ASSISTANT_NUMBER` | `os.environ["ASSISTANT_NUMBER"]` (always required; raises `RuntimeError` if absent) |
| `ASSISTANT_NUMBER` | `os.environ["ASSISTANT_NUMBER", "5550000"]` |
| `HOOK_SWITCH_PIN` | `int(os.environ.get("HOOK_SWITCH_PIN", "17"))` — BCM pin; non-integer value raises `ValueError` at import |
| `PULSE_SWITCH_PIN` | `int(os.environ.get("PULSE_SWITCH_PIN", "27"))` — BCM pin; non-integer value raises `ValueError` at import |
| `PIPER_BINARY` | `os.environ.get("PIPER_BINARY", "/usr/local/bin/piper")` |
Expand All @@ -175,9 +175,8 @@ main.py

### Secrets and environment variables

- **No hardcoded secrets** — `ASSISTANT_NUMBER` is always required; the app raises `RuntimeError` if absent
- **No hardcoded secrets**
- **`config.env.example`** at the repo root documents all environment variables accepted by `constants.py` with placeholder or default values; copy it to `/etc/hello-operator/config.env` for deployment; never commit a real `.env` file
- **Tests that import `src.constants`** must set `ASSISTANT_NUMBER` in the environment; the CI/test runner command should include: `ASSISTANT_NUMBER=5550000 python -m pytest`

## Development Process

Expand Down
8 changes: 1 addition & 7 deletions INSTALL.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,12 +69,6 @@ cd web/angular && npm install && npm run build

Edit `/etc/hello-operator/config.env`. The file is pre-populated from `config.env.example` with comments explaining each variable.

### Always required

| Variable | Description |
|---|---|
| `ASSISTANT_NUMBER` | 7-digit reserved number for the diagnostic assistant (must not conflict with any media entry) |

### MPD and Mopidy backends

Set `MEDIA_BACKEND=mpd` to connect to a Music Player Daemon instance, or `MEDIA_BACKEND=mopidy` to connect to a Mopidy server. Both use the same `MPD_HOST` and `MPD_PORT` variables — Mopidy implements the MPD wire protocol via its `mopidy-mpd` extension.
Expand Down Expand Up @@ -104,6 +98,7 @@ These have sensible defaults matching the install script's paths and the hardwar

| Variable | Default | Description |
|---|---|---|
| `ASSISTANT_NUMBER` | '5550000' | 7-digit reserved number for the diagnostic assistant |
| `MEDIA_BACKEND` | `mpd` | Media player backend: `mpd` or `mopidy` |
| `MPD_HOST` | `localhost` | MPD/Mopidy server hostname or IP |
| `MPD_PORT` | `6600` | MPD/Mopidy TCP port (MPD and Mopidy backends) |
Expand Down Expand Up @@ -220,7 +215,6 @@ sudo systemctl restart hello-operator-web
| Handset lift not detected | `docs/HOOK_SWITCH_SETUP.md` |
| Service fails to start | `sudo journalctl -u hello-operator -n 50` |
| Web interface unreachable | Check `sudo systemctl status hello-operator-web`; confirm port 8080 is not blocked |
| Error about `ASSISTANT_NUMBER` at startup | Set `ASSISTANT_NUMBER` in `/etc/hello-operator/config.env` |
| Radio plays no audio | Confirm RTL-SDR dongle is plugged in; run `rtl_test` to verify it is detected |
| MPD connection refused | Confirm MPD is running (`systemctl status mpd`) and `MPD_HOST`/`MPD_PORT` match |
| Mopidy connection refused | Confirm Mopidy is running (`systemctl status mopidy`) and the MPD extension is enabled (`mopidy-mpd`); check `MPD_HOST`/`MPD_PORT` match Mopidy's MPD frontend (default port 6600) |
13 changes: 13 additions & 0 deletions config.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,19 @@ ASSISTANT_NUMBER=5550000
HOOK_SWITCH_PIN=17
PULSE_SWITCH_PIN=27

# ---------------------------------------------------------------------------
# Audio output device (optional; defaults to MAX98357A I2S amp)
# ---------------------------------------------------------------------------

# ALSA device name passed to aplay -D. Use "plughw:MAX98357A" for the
# I2S amplifier or "default" to route through PipeWire/PulseAudio.
ALSA_DEVICE=plughw:MAX98357A

# Software volume multiplier (0.0–1.0). Lower if the amp clips or buzzes.
# The MAX98357A with floating GAIN pin has 15 dB hardware gain, so 0.4 is
# a reasonable starting point. Tune up or down to taste.
AUDIO_VOLUME=0.05

# ---------------------------------------------------------------------------
# Piper TTS (optional; defaults match paths used by install.sh)
# ---------------------------------------------------------------------------
Expand Down
19 changes: 12 additions & 7 deletions docs/AMP_SETUP.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,16 +165,21 @@ Power-cycle the board after changing the gain wiring.

## Channel selection (SD pin)

The breakout board's SD pin has a 1MΩ pull-up to Vin, which selects **stereo average** output `(L+R)/2` by default — appropriate for mono use with a stereo audio source.

For reference, the SD pin voltage ranges are:

| SD pin voltage | Output |
1. Wire MAX98357A **SD** to **GPIO 22** (physical pin 15) instead of Vin.
2. Set `AMP_SD_PIN=22` in `/etc/hello-operator/config.env`.

hello-operator handles the rest automatically at startup.

### SD pin voltage reference

| SD pin voltage | Outage |
|---|---|
| < 0.16V | Amplifier shutdown |
| 0.16V – 0.77V | Stereo average (L+R)/2 |
| 0.77V – 1.4V | Right channel only |
| > 1.4V | Left channel only |
| < 0.16 V | Shutdown |
| 0.16 V – 0.77 V | Stereo average (L+R)/2 |
| 0.77 V – 1.4 V | Right channel only |
| > 1.4 V | Left channel only |

The SD pin is also used for instant audio cutoff — see Step 5 below.

Expand Down
45 changes: 19 additions & 26 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,11 @@ mkdir -p "$CONFIG_DIR"
chmod 755 "$CONFIG_DIR"
chown "$INSTALL_USER:$INSTALL_USER" "$CONFIG_DIR"

if [ ! -f "$CONFIG_DIR/config.env" ]; then
echo "==> Copying config.env.example to $CONFIG_DIR/config.env..."
cp "$INSTALL_DIR/config.env.example" "$CONFIG_DIR/config.env"
else
echo "==> $CONFIG_DIR/config.env already exists — skipping (not overwritten)."
fi
echo "==> Copying config.env.example to $CONFIG_DIR/config.env..."
cp "$INSTALL_DIR/config.env.example" "$CONFIG_DIR/config.env"

if [ ! -f "$CONFIG_DIR/radio_stations.json" ]; then
echo "==> Copying radio_stations.json.example to $CONFIG_DIR/radio_stations.json..."
cp "$INSTALL_DIR/radio_stations.json.example" "$CONFIG_DIR/radio_stations.json"
else
echo "==> $CONFIG_DIR/radio_stations.json already exists — skipping (not overwritten)."
fi
echo "==> Copying radio_stations.json.example to $CONFIG_DIR/radio_stations.json..."
cp "$INSTALL_DIR/radio_stations.json.example" "$CONFIG_DIR/radio_stations.json"

# ---------------------------------------------------------------------------
# Database directory
Expand Down Expand Up @@ -134,9 +126,9 @@ echo "==> Piper available at $PIPER_BIN_DIR/piper."
# Angular frontend
# ---------------------------------------------------------------------------

if command -v npm >/dev/null 2>&1; then
if command -v nvm >/dev/null 2>&1; then
echo "==> Building Angular frontend..."
(cd "$INSTALL_DIR/web/angular" && npm ci --quiet && npx ng build)
(cd "$INSTALL_DIR/web/angular" && nvm use && npm ci --quiet && npx ng build)
echo "==> Angular frontend built."
else
echo "==> Node.js/npm not found — skipping Angular build."
Expand Down Expand Up @@ -174,6 +166,12 @@ echo "==> Configuring MPD music directory..."
MUSIC_DIR="/home/$INSTALL_USER/Music"
sed -i "s|^music_directory.*|music_directory \"$MUSIC_DIR\"|" /etc/mpd.conf

# Grant mpd read access to the user's home directory.
# mpd runs as the system 'mpd' user; without group execute on ~ it cannot
# traverse into ~/Music even if the Music dir itself is world-readable.
usermod -aG "$INSTALL_USER" mpd
chmod g+x "/home/$INSTALL_USER"

echo "==> Enabling and starting MPD..."
systemctl enable mpd
systemctl start mpd
Expand All @@ -195,18 +193,14 @@ else
fi

if [ -n "$CONFIG_TXT" ]; then
if grep -q "dtoverlay=max98357a" "$CONFIG_TXT"; then
echo "==> MAX98357 overlay already present in $CONFIG_TXT — skipping."
else
# Replace dtparam=audio=on with off, or append audio=off if absent
if grep -q "^dtparam=audio=on" "$CONFIG_TXT"; then
sed -i 's/^dtparam=audio=on/dtparam=audio=off/' "$CONFIG_TXT"
elif ! grep -q "^dtparam=audio=off" "$CONFIG_TXT"; then
echo "dtparam=audio=off" >> "$CONFIG_TXT"
fi
echo "dtoverlay=max98357a" >> "$CONFIG_TXT"
echo "==> MAX98357 overlay added to $CONFIG_TXT."
# Replace dtparam=audio=on with off, or append audio=off if absent
if grep -q "^dtparam=audio=on" "$CONFIG_TXT"; then
sed -i 's/^dtparam=audio=on/dtparam=audio=off/' "$CONFIG_TXT"
elif ! grep -q "^dtparam=audio=off" "$CONFIG_TXT"; then
echo "dtparam=audio=off" >> "$CONFIG_TXT"
fi
echo "dtoverlay=max98357a" >> "$CONFIG_TXT"
echo "==> MAX98357 overlay added to $CONFIG_TXT."
fi

cat > /etc/asound.conf << 'ASOUND'
Expand Down Expand Up @@ -257,7 +251,6 @@ echo " After rebooting, verify with: aplay -l"
echo " Adjust volume with: alsamixer"
echo ""
echo " 2. Edit /etc/hello-operator/config.env and set:"
echo " ASSISTANT_NUMBER — required for all backends"
echo ""
echo " If using MPD (default, MEDIA_BACKEND=mpd):"
echo " MPD is already enabled and running. If the audio output device"
Expand Down
Loading