TrueNAS AUDIO Alerts Through USB Speaker

Example video

TrueNAS SCALE: USB Speaker Pool-Alert Guide

Hardware noted: ASUS Pro WS WRX80 motherboard, USB speaker: AmazonBasics USB Plug-n-Play Computer Speakers

This guide produces an audible alert through a USB speaker whenever any ZFS pool is not healthy. It avoids installing packages on the TrueNAS host by using a tiny Docker image that contains ALSA’s aplay..


0) Prereqs (one-time)

  • TrueNAS SCALE with Apps/Docker enabled.
  • USB speaker is plugged in and powered.
  • Access to the TrueNAS web UI Shell (root).

Create a folder to hold the alert sound:

sudo mkdir -p /mnt/APPS/alerts

Build a tiny image that has aplay:

cat >/root/alsa-aplay.Dockerfile <<'EOF'
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends alsa-utils  && rm -rf /var/lib/apt/lists/*
ENTRYPOINT ["aplay"]
EOF

sudo /bin/docker build -t local/alsa-aplay -f /root/alsa-aplay.Dockerfile /root

Tip: If /bin/docker isn’t present on your box, use /usr/bin/docker in the commands below.


1) Make a WAV file and put it in a directory

Option A — Generate a simple 1‑second beep (uses a throwaway container)

sudo /bin/docker run --rm -v /mnt/APPS/alerts:/out debian:bookworm-slim bash -lc '
  set -e
  apt-get update >/dev/null
  apt-get -y install sox >/dev/null
  sox -n -r 44100 -b 16 -c 2 /out/pool_degraded.wav synth 1 sine 880
'

Option B — Use your own WAV

Copy any WAV (e.g., a TTS you recorded elsewhere) to:

/mnt/APPS/alerts/pool_degraded.wav

2) Test WAV playback over the USB audio device

List ALSA devices to find your USB speaker (look for “USB” in the card name):

sudo /bin/docker run --rm --device /dev/snd --group-add audio local/alsa-aplay -l

You’ll see entries like:

card 1: USB..., device 0: ...

Use that card,device pair with plughw:<card>,<device>. Test playback (replace 1,0 if your numbers differ):

sudo /bin/docker run --rm --device /dev/snd --group-add audio   -v /mnt/APPS/alerts:/audio   local/alsa-aplay -D plughw:1,0 /audio/pool_degraded.wav

If you don’t hear anything:

  • Try -D default instead of plughw:1,0.
  • Verify the speaker volume and that it’s not muted.
  • Re-check the card/device numbers with -l.

3) Set up a script to play whenever a pool is degraded

Create the alert script:

sudo tee /root/pool_alert.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

CONFIG — adjust these if needed

WAV=“/mnt/APPS/alerts/pool_degraded.wav”
ALSA_DEV=“plughw:1,0” # change if your USB device is a different card,device
DOCKER_IMG=“local/alsa-aplay”
LOG=“/var/log/pool_alert.log” # optional log

Sanity checks

[[ -f “$WAV” ]] || { echo “Missing WAV: $WAV” | tee -a “$LOG”; exit 0; }

If any pool is NOT healthy, zpool status -x will NOT say “all pools are healthy”

if ! /sbin/zpool status -x | grep -q “all pools are healthy”; then
echo “$(date) : Pool not healthy -> playing alert” >> “$LOG”
/bin/docker run --rm --device /dev/snd --group-add audio -v “$(dirname “$WAV”)”:/audio “$DOCKER_IMG” -D “$ALSA_DEV” “/audio/$(basename “$WAV”)” || true
else
echo “$(date) : Pools healthy” >> “$LOG”
fi
EOF

sudo chmod +x /root/pool_alert.sh

Quick manual test (should play once if a pool is not healthy; otherwise it will just log):

sudo /root/pool_alert.sh && sudo tail -n 3 /var/log/pool_alert.log

Notes

  • The script plays once per run. Pair it with a 5‑minute cron to be “annoying” until fixed.
  • Edit ALSA_DEV if your USB device isn’t plughw:1,0.
  • The check uses zpool status -x so it works across multi‑pool setups.

4) Make a cron job in the GUI (every 5 minutes)

  1. Go to System Settings → Advanced → Cron Jobs (in some versions: Tasks → Cron Jobs).
  2. Click Add.
  3. User: root
    Schedule: Every 5 minutes (preset or */5 * * * *)
    Command: /root/pool_alert.sh
    Description: Play USB speaker alert if any pool is degraded
    Enabled: Yes
  4. Click Save.

You should now hear an audible alert every 5 minutes whenever any pool goes non‑healthy.


Troubleshooting

  • aplay: device busy / cannot open — Another process may be using the device. Try -D default or confirm the correct card,device via -l.
  • Cron doesn’t seem to run — In the job details, temporarily disable “Hide Stdout/Stderr” and check for updates in /var/log/pool_alert.log, or test with /root/pool_alert.sh >> /root/cron_debug.log 2>&1.
  • New USB device index after reboot — Sometimes the card index changes (e.g., from 1,0 to 2,0). Re‑check with the -l command and update ALSA_DEV in /root/pool_alert.sh.

This was tested on TrueNAS SCALE with an ASUS Pro WS WRX80 board and the USB speaker linked above. If you later want text‑to‑speech instead of a fixed WAV, you can swap the WAV generation step for a small TTS container; the rest (script + cron + aplay) remains the same.

1 Like

Example script, again

/root/pool_alert.sh
sudo tee /root/pool_alert.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -euo pipefail

# CONFIG — adjust these if needed
WAV=“/mnt/APPS/alerts/pool_degraded.wav”
ALSA_DEV=“plughw:1,0” # change if your USB device is a different card,device
DOCKER_IMG=“local/alsa-aplay”
LOG=“/var/log/pool_alert.log” # optional log

# Sanity checks
[[ -f “$WAV” ]] || { echo “Missing WAV: $WAV” | tee -a “$LOG”; exit 0; }

# If any pool is NOT healthy, zpool status -x will NOT say “all pools are healthy”
if ! /sbin/zpool status -x | grep -q “all pools are healthy”; then
echo “$(date) : Pool not healthy -> playing alert” >> “$LOG”
/bin/docker run --rm --device /dev/snd --group-add audio
-v “$(dirname “$WAV”)”:/audio
“$DOCKER_IMG” -D “$ALSA_DEV” “/audio/$(basename “$WAV”)” || true
else
echo “$(date) : Pools healthy” >> “$LOG”
fi
EOF

sudo chmod +x /root/pool_alert.sh

1 Like

@scarbrtj
Very nice work. While I have not tested this, it does look like something I would want to try out. Very nice.

Possible suggestion is to force the motherboard speaker to beep. I have not looked into it to see how that might be done but the USB speaker is a good solution.

I can easily see that this script could be expanded to include much more than just the ZFS health of your pools, just add a few lines to test for some other situation and play a different .wav file for that situation. Maybe for any drive failure indications? In my mind it is the voice of Roz from Monsters Inc. “Joe, your hard drive is failing!”

Thank you for the posting. I really need to try it out, once I get a USB speaker.

AFAIK, the motherboard’s beep is just an ASCII character.

OMG, the bell character reminds me of when I was in high school when the bell character actually rang a bell on a TTY. Brings back some fond memories.
This is probably not the exact model but it is close. The one I used didn’t have a paper tape reader/punch.

1 Like

I’m kinda surprised that beep doesn’t work anymore. It worked about ten(-ish) years ago on a 4th gen core workstation with Win7. Proof.

Define “doesn’t work”?

The VT100 and other Terminal Standards have not changed.

It STILL works if the Terminal Emulator was coded properly.
Of course it must be ENABLED in both, the terminal emulator and the terminal itself (stty enable bell).

It should work in the Console as well, just another terminal.

Doesn’t make that beautiful sound.

Of course, I was talking about the out-of-the-box experience (in windows… and truenas). There are claims that the ubuntu terninal has the same behaviour as well.

I have set up a system for disk temp alerts… for me, the TrueNAS GUI refuses to show my disk temps, but the OS “knows” and can see the temps. So I have made a script to alert me if HDD disk temps get too high.

===========

TrueNAS SCALE — USB Speaker Audio Alerts for High Disk Temperatures

TrueNAS SCALE — USB Speaker Audio Alerts for High Disk Temperatures

Goal: Play a WAV alert through a USB speaker whenever any drive is ≥ 53 °C. This guide shows how to (1) place the WAV file, (2) build a tiny Docker audio container, (3) find the correct ALSA device, (4) install a temp-check script, and (5) schedule it in the GUI.


0) Prerequisites

  • TrueNAS SCALE with Apps/containers enabled.
  • USB speaker plugged into the TrueNAS host.
  • A 44.1 kHz, 16-bit, stereo .wav file (example: hotdiskalert.wav).

1) Put the alert WAV on your NAS

sudo mkdir -p /mnt/APPS/APPS2
: # Copy your WAV (hotdiskalert.wav) into /mnt/APPS/APPS2 via SMB/SFTP or shell
ls /mnt/APPS/APPS2/*.wav

2) Build a minimal audio container (aplay + optional TTS)

This provides aplay for WAV playback (and flite for optional TTS):

mkdir -p ~/audio-alert && cd ~/audio-alert

cat > Dockerfile <<‘EOF’
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends
alsa-utils flite ca-certificates &&
rm -rf /var/lib/apt/lists/*
ENTRYPOINT [“/bin/bash”,“-lc”]
EOF

sudo /bin/docker build -t local/alert-container .


3) Identify the ALSA device for your USB speaker

List devices inside the container with the host sound device passed through:

sudo /bin/docker run --rm \
  --device /dev/snd \
  --group-add audio \
  local/alert-container \
  aplay -l

Note your USB device (e.g., card 1, device 0 → use plughw:1,0).


4) Quick playback test (manual)

Verifies container + ALSA device + WAV binding:

sudo /bin/docker run --rm \
  --device /dev/snd \
  --group-add audio \
  -v /mnt/APPS/APPS2:/audio \
  local/alert-container \
  aplay -D plughw:1,0 /audio/hotdiskalert.wav

If it fails with “unable to open slave”, try the other detected device (e.g., plughw:2,0). Card numbers can change after a reboot; re-run step 3 if needed.


5) Install the temperature-check script

This script enumerates all disks (SATA/SAS/NVMe) and plays the alert if any disk is ≥ 53 °C.

sudo nano /root/check_disk_temps.sh
Paste the full script below :
#!/bin/bash
: # Check all disk temps and play an alert if any >= threshold

THRESHOLD=53
DOCKER="/bin/docker"
ALSA_DEVICE="plughw:1,0"
AUDIO_HOST_DIR="/mnt/APPS/APPS2"
AUDIO_IN_CONTAINER="/audio/hotdiskalert.wav"
SMARTCTL="/usr/sbin/smartctl"

: # Enumerate real disks (covers sda..sdaa, nvme*, etc.)
for name in $(lsblk -dn -o NAME,TYPE | awk '$2=="disk"{print $1}'); do
  : # Normalize NVMe: use controller device (nvme0) instead of namespace (nvme0n1)
  case "$name" in
    nvme*) dev="/dev/${name%%n*}";;
    *)     dev="/dev/$name";;
  esac

  : # Extract temperature in °C from various smartctl formats (ATA/SAS/NVMe)
  TEMP=$("$SMARTCTL" -A "$dev" 2>/dev/null | awk '
    /^Temperature:/ {
      if (match($0, /([0-9]+)[[:space:]]*C/, a)) { print a[1]; exit }
    }
    /^Current[[:space:]]+Drive[[:space:]]+Temperature/ {
      if (match($0, /([0-9]+)/, a)) { print a[1]; exit }
    }
    /^[[:space:]]*194[[:space:]]/ || /^[[:space:]]*190[[:space:]]/ {
      line=$0
      sub(/\(.*/,"", line)
      n=split(line, f, /[[:space:]]+/)
      print f[n]; exit
    }')

  : # If we got a valid integer temp, compare to threshold
  if echo "$TEMP" | grep -Eq '^[0-9]+$'; then
    if [ "$TEMP" -ge "$THRESHOLD" ]; then
      echo "Disk $dev is hot (${TEMP}°C) – playing alert"
      "$DOCKER" run --rm \
        --device /dev/snd \
        --group-add audio \
        -v "$AUDIO_HOST_DIR":/audio \
        local/alert-container \
        aplay -D "$ALSA_DEVICE" "$AUDIO_IN_CONTAINER"
      exit 0
    fi
  fi
done

Then:

sudo chmod +x /root/check_disk_temps.sh
sudo /root/check_disk_temps.sh

Then:



6) Add the cron job in the GUI

  1. Open System Settings → Advanced → Cron Jobs → Add.
  2. Description: Disk temperature audio alert (>=53C)
  3. User: root
  4. Schedule: Every 5 minutes (Preset “Every 5 minutes” or custom */5 * * * *)
  5. Command:
/bin/bash -lc '/root/check_disk_temps.sh; echo "$(date) : cron ran"' >> /var/log/disktemp_alert.log 2>&1

Verify heartbeat:

sudo tail -n 5 /var/log/disktemp_alert.log

7) Handy one-liners

Manual replay (bypass checks):

sudo /bin/docker run --rm \
  --device /dev/snd --group-add audio \
  -v /mnt/APPS/APPS2:/audio \
  local/alert-container \
  aplay -D plughw:1,0 /audio/hotdiskalert.wav

Quick view of current temps:

for d in $(lsblk -dn -o NAME,TYPE | awk '$2=="disk"{print $1}'); do
  [[ $d == nvme* ]] && dev="/dev/${d%%n*}" || dev="/dev/$d"
  echo -n "$dev : "
  sudo /usr/sbin/smartctl -A "$dev" | awk '/Airflow_Temperature_Cel|Temperature_Celsius|Temperature:/ {
    if (match($0, /([0-9]+)[[:space:]]*C/, a)) {print a[1]; exit}
    if (match($0, /([0-9]+)/, a)) {print a[1]; exit}
  }'
done

Troubleshooting

  • “unable to open slave”: Re-run aplay -l and update ALSA_DEVICE (card/device may change after reboot). Use plughw:<card>,<device>.
  • No sound at all: Check speaker volume, confirm the container sees /dev/snd, and prefer plughw: over hw:.
  • Script never alerts: Verify temps with the one-liner; ensure /usr/sbin/smartctl exists; confirm cron heartbeat in /var/log/disktemp_alert.log.
  • Too chatty / not chatty enough: Change the cron schedule to every minute (*/1 * * * *) or adjust the threshold.

Interesting work, i appreciate more the

because Is something not covered at all by TN (afaik).

Good Job :100: