Appearance
Raspberry Pi Satellite
Deploy a Raspberry Pi as a BirdNET-NG satellite node for continuous bird audio capture.
Hardware
- 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
bash
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo bash -
sudo apt install -y nodejs2. Install audio tools
bash
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 works3. Register the satellite
Use the web UI to register, or via API:
bash
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
bash
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.js5. Run as a systemd service
bash
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-satelliteGPS Setup
For live GPS positioning instead of static coordinates:
bash
sudo apt install -y gpsd gpsd-clientsEdit /etc/default/gpsd:
DEVICES="/dev/ttyUSB0" # or /dev/serial0 for GPIO UART
GPSD_OPTIONS="-n"
START_DAEMON="true"bash
sudo systemctl enable --now gpsd
cgps # Verify GPS fixAdd to .env:
bash
GPS_MODE=gpsd
GPSD_HOST=localhost
GPSD_PORT=2947When 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_offin the heartbeat - Re-checks the schedule every 5 minutes
Heartbeat
The satellite sends a lightweight heartbeat every 30 seconds 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), visible on the Satellites page.
On-Device Audio Filtering
Before sending a chunk, the satellite checks:
- RMS energy > 0.005 (reject silence)
- Bird-band frequency ratio > 0.1 (reject audio outside 1–10kHz)
This typically filters 70–90% of chunks, reducing bandwidth and hub processing load. Disable with AUDIO_FILTER=false.
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 |