You are viewing archived documentation for v0.4. Go to latest →

Satellite: Raspberry Pi

Deploy a Raspberry Pi as a BirdNET-NG satellite node for continuous bird audio capture.

Platform: Raspberry Pi — a dedicated, always-on Node.js agent that captures audio via ALSA and uploads to the hub over MQTTS.

Hardware Requirements

  • Raspberry Pi 3B+ or newer (4 recommended)
  • USB microphone or I2S MEMS microphone (e.g., Adafruit SPH0645)
  • SD card (16GB+)
  • Power supply
  • Optional: GPS module (e.g., u-blox NEO-6M, Adafruit Ultimate GPS, BN-880)

Software Setup

1. Install Node.js

curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
sudo apt install -y nodejs

2. Install audio tools

sudo apt install -y alsa-utils
arecord -l                    # List audio devices
arecord -D plughw:1,0 -f S16_LE -r 48000 -c 1 -d 3 test.wav
aplay test.wav                # Verify recording works

3. Register the satellite

Use the web UI to register, or via API:

curl -X POST https://birdnet.example.com/api/satellites \
  -H "Authorization: Bearer <jwt-token>" \
  -H "Content-Type: application/json" \
  -d '{"tenantId":"<uuid>","name":"Garden Pi","latitude":43.56,"longitude":3.90}'

Save the returned id, mqtt.username, and mqtt.password.

4. Configure and run

git clone https://github.com/birdnet-ng/birdnet-ng.git
cd birdnet-ng
pnpm install && pnpm build

cd packages/satellite
cat > .env << 'EOF'
SATELLITE_ID=<from registration>
TENANT_ID=<your tenant>
MQTT_BROKER_URL=mqtts://mqtt.birdnet.example.com:8883
MQTT_USERNAME=<satellite id>
MQTT_PASSWORD=<from registration>
CAPTURE_MODE=alsa
AUDIO_DEVICE=plughw:1,0
LATITUDE=43.56
LONGITUDE=3.90
RECORDING_PROFILE=continuous
EOF

node dist/index.js

5. Run as a systemd service

sudo tee /etc/systemd/system/birdnet-satellite.service << 'EOF'
[Unit]
Description=BirdNET-NG Satellite
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=pi
WorkingDirectory=/home/pi/birdnet-ng/packages/satellite
EnvironmentFile=/home/pi/birdnet-ng/packages/satellite/.env
ExecStart=/usr/bin/node dist/index.js
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable --now birdnet-satellite

GPS Setup

For live GPS positioning instead of static coordinates:

sudo apt install -y gpsd gpsd-clients

Edit /etc/default/gpsd:

DEVICES="/dev/ttyUSB0"    # or /dev/serial0 for GPIO UART
GPSD_OPTIONS="-n"
START_DAEMON="true"
sudo systemctl enable --now gpsd
cgps                         # Verify GPS fix

Add to .env:

GPS_MODE=gpsd
GPSD_HOST=localhost
GPSD_PORT=2947

When GPS mode is gpsd, the satellite reads live coordinates from the GPS daemon and updates the hub via telemetry. Falls back to static coordinates if GPS has no fix.

Recording Profiles

Profiles control when the satellite captures audio. They are pushed from the hub via MQTT and can be changed on the Satellites page.

Profile Schedule Description
continuous 24/7 Always recording
dawn_chorus sunrise-30min to sunrise+2h Peak bird activity
night_migration sunset+30min to sunset+12h Nocturnal flight calls
low_power sunrise+/-30min, sunset+/-30min Dawn and dusk only

Sunrise and sunset times are calculated automatically from the satellite's GPS coordinates using the NOAA solar algorithm. Times update daily as day length changes with seasons.

When outside a recording window, the satellite:

  • Pauses the capture loop (no CPU/disk usage)
  • Continues sending heartbeats (stays "online" on the hub)
  • Reports state as scheduled_off in the heartbeat
  • Re-checks the schedule every 5 minutes

Heartbeat

The satellite sends a lightweight heartbeat at a configurable interval (default 30 seconds, set from hub tenant settings) via MQTT QoS 1. This keeps the satellite showing as "online" on the hub even when all audio chunks are filtered out (silence).

The heartbeat includes the satellite's current state (recording, scheduled_off, error) and noise_floor_rms for filter calibration, visible on the Satellites page.

On-Device Audio Filtering

The satellite uses adaptive noise floor + spectral peak SNR detection to filter audio before upload:

  1. Adaptive noise floor: tracks ambient noise level over time (smoothing alpha: 0.02)
  2. Minimum RMS energy: rejects silence below threshold (default 0.003)
  3. Spectral peak SNR: requires signal-to-noise ratio above threshold (default 1.5)
  4. Bird-band frequency check: confirms energy in the 1-10kHz bird frequency range

All filter settings are configurable from hub tenant settings (filter_enabled, filter_min_rms, filter_peak_snr, filter_bird_band_check, filter_noise_floor_alpha) and pushed to satellites via the MQTT config channel when changed. Satellites also apply the latest settings on reconnect.

The satellite reports noise_floor_rms in heartbeat telemetry for monitoring.

This typically filters 70-90% of chunks, reducing bandwidth and hub processing load. Disable with filter_enabled=false in tenant settings (or AUDIO_FILTER=false in the satellite .env as a local override).

Filtering is automatically disabled for simulate and replay capture modes.

Troubleshooting

Symptom Check
Satellite shows offline Verify MQTT credentials, check journalctl -u birdnet-satellite
No detections Check if all chunks are filtered (low audio activity), verify worker is running
GPS unavailable Check cgps for fix, verify /dev/ttyUSB0 permissions
High CPU temp Normal for Pi 4 under load; add heatsink or fan
Storage filling up Increase RETENTION_HOURS or check outbox drain