Skip to content

ernens/birdash

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

837 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

🐦 BirdStation

MIT License Node.js Vue 3 PRs Welcome

Modern bird detection dashboard and engine for Raspberry Pi 5. Standalone dual-model architecture with BirdNET V2.4 + Perch V2. Community network with live station map. Customizable station name and branding.

Francais | Nederlands | Deutsch | Contributing

Screenshots

Highlights — scroll horizontally to peek at the main pages. Full per-section galleries are folded below.

Overview Today Spectrogram modal Weather analytics Species page Recordings Detection review
Overview
KPIs & bird of the day
Today
live detections + filters
Spectrogram
full-screen + weather chip
Weather
leaderboards · heatmap · search
Species
history + weather profile
Recordings
library + best per species
Review
auto-flagged + bulk actions
Home — Overview · Today

Overview Today

Live — Dashboard · Spectrogram · Log · Live Board

Dashboard Spectrogram Live log Live Board

History — Calendar · Timeline · Detections · Review

Calendar Timeline Detections Review

Species — Species · Recordings · Rarities · Favorites

Species Recordings Rarities Favorites

Indicators — Weather · Statistics · Models · Analyses · Biodiversity · Phenology · Seasons · Compare

Weather Statistics Models Analyses Biodiversity Phenology Seasons Compare 2 species

Station — System health, settings & terminal

System health Model monitor System data External

Detection Audio Notifications Station

Services Species Backup Terminal

Architecture

Full architecture documentation → — deep technical reference covering audio pipeline, database schema, performance, and more.

Raspberry Pi 5 + SSD
├── USB Audio Interface
│     ↓
├── BirdEngine (Python)
│   ├── Recording service (arecord → WAV 45s)
│   ├── Audio pipeline: Adaptive Gain → Highpass → Lowpass
│   │   → Noise Profile Subtraction → RMS Normalize
│   ├── BirdNET V2.4    (~1.5s/file, primary)
│   ├── Perch V2         (~0.7s/file on Pi 5, secondary)
│   ├── MP3 extraction + spectrograms
│   └── BirdWeather upload
│
├── Birdash (Node.js)
│   ├── Dashboard API (port 7474)
│   ├── Live spectrogram (PCM + MP3 stream)
│   ├── Push notifications via Apprise (100+ services)
│   ├── Detection review + auto-flagging
│   ├── Telemetry (opt-in Supabase)
│   └── In-app bug reporting (GitHub Issues)
│
├── Caddy (reverse proxy :80)
├── ttyd (web terminal)
└── SQLite (1M+ detections)

Features

Detection Engine (BirdEngine)

  • Dual-model inference — BirdNET V2.4 (~1.5s/file) + Perch V2 (~0.7s/file on Pi 5) in parallel. Model variant auto-selected per Pi: FP32 on Pi 5, FP16 on Pi 4, INT8 on Pi 3
  • Dual-model cross-confirmation — Perch detections below a standalone threshold (default 0.85) must be echoed by BirdNET (raw score ≥ 0.15) on an overlapping chunk. Kills the bulk of Perch false positives on low-frequency noise (wind, vehicles → geese/herons/ravens) without losing Perch's edge on species BirdNET misses. All three thresholds adjustable in Settings → Detection with (i) tooltips
  • Noisy-species throttle — opt-in per-species cooldown (default 120 s) keeps dominant feeder species (sparrows, blackbirds…) from flooding the DB while letting high-confidence calls (≥ bypass threshold, default 0.95) always pass. State is in-memory on the engine, hot-reloaded from birdnet.conf. Companion script scripts/cleanup_throttle.py applies the same rule retroactively to historical rows with --dry-run / --apply, DB backup, and audio quarantine — 60-70 % typical purge on noisy stations
  • Local recording — any USB audio interface via ALSA with configurable gain
  • Adaptive noise normalization — automatic software gain based on ambient noise, with clip guard, activity hold, and observer mode
  • Audio filters — configurable highpass + lowpass (bandpass), spectral noise reduction (stationary gating), RMS normalization
  • BirdWeather — automatic upload of soundscapes + detections
  • Smart push notifications — via Apprise (ntfy, Telegram, Discord, Slack, email, 100+ services) with species photo attached, station name prefix ([Heinsch] Merle noir). 5 configurable rules: rare species, first-of-season, new species, first-of-day, favorites
  • MQTT publisher — opt-in, publishes each detection to any MQTT broker (Mosquitto, EMQX, HiveMQ…) on <prefix>/<station>/detection, with a retained last_species topic and LWT online/offline status. Optional Home Assistant auto-discovery creates Last species + Last confidence sensor entities automatically. Configurable QoS, retain, TLS, username/password, minimum confidence — one-click Test from Settings
  • Prometheus /metrics endpoint — scrape http://your-pi.local/birds/metrics from Prometheus / Grafana / VictoriaMetrics. Custom gauges (detections total/today/last-hour, distinct species, last-detection age, DB size), system gauges (CPU temp, usage, RAM, disk, fan RPM, uptime), feature toggles, and standard Node.js process metrics. Refreshed lazily on each scrape
  • Live sound-level monitor (Leq / peak) — RMS and peak in dBFS computed per recording, exposed on /metrics (birdash_sound_leq_dbfs, _peak_dbfs, _leq_1h_avg_dbfs) and displayed as a live card in Settings → Audio with a 60-point sparkline. Useful for spotting wind, traffic, a dead mic, or silent overnight hours. Uncalibrated (trend-tracking, not SPL). Optional Apprise alerts when the average Leq drops below -90 dBFS for 15 min (silent mic) or stays above -5 dBFS (clipping)
  • Auth & access control — opt-in cookie sessions (single user, bcrypt). Three modes: off (LAN-trust, default), protected (login for everything), and public-read (everyone can browse detections, species and stats — login required only to change settings or access sensitive data). HMAC-signed cookies, no DB sessions to manage. Bearer token (BIRDASH_API_TOKEN) still works in parallel for cron/automation. Login attempts rate-limited 5/min/IP. See Expose on the internet below
  • Range filter — geographic — BirdNET MData filter (already active, configurable via SF_THRESH) now shows the live list of species expected at your location for the current week (Settings → Detection). Plus opt-in eBird filter for Perch that drops Perch detections absent from the local eBird "recently observed" map — Perch has no built-in geographic model and otherwise reports tropical species in temperate zones
  • Pre-analysis filters (YAMNet) — opt-in privacy filter (drops detections + optionally deletes the WAV when human voice is detected, RGPD-friendly default) and dog bark filter (drops detections + cooldown window when bark / howl / growl is detected — stops the cascade of false positives dogs trigger). Powered by Google's YAMNet (AudioSet, 521 audio classes, 4 MB TFLite, bundled). One model, two filters, ~30 ms added latency per recording on Pi 5
  • Weekly editorial digest — Monday 8am, 5 curated lines via Apprise: numbers + delta vs N-1, highlight (rare > first-of-year > notable), best moment, phenology shift, top 3 species. Opt-in, optional tag routing
  • Async post-processing — MP3 extraction, spectrogram generation, DB sync don't block inference
  • Detection Refinement Module — heuristic bbox computed for every detection (time-frequency localization visualized as an amber dashed rectangle on every spectrogram in the dashboard) + optional stability-check worker (birdengine-stability.service, opt-in) that re-runs Perch on a 5 s window recentered on the energy peak; detections whose confidence collapses on recentering are tagged unstable and surface in the flagged list. See docs/refinement/SPEC-v2.md

Dashboard (20 pages)

Home

  • Overview (landing page) — 6 KPIs (incl. first-detection time), "What's New" alerts, weather context, hourly activity. Featured-detection card with two tabs: Last detection (station-alive signal) and Best of today (highest-confidence pick of the day)
  • Today — species list with sort (count / first heard / max conf / new first) and separated count/confidence pills. Per-species interpretive summary (single deterministic status: needs review / single weak / isolated burst / repeated high-confidence / mostly dawn active / present all day). Spectrogram with expected frequency band overlay (~95 species, toggleable). Audio player with gain/HP/LP filters. Direct deep-link to Review with species + date pre-filtered
  • Species name translation — bird names displayed in the user's chosen language across all pages

Live

  • Bird Flow — animated pipeline showing live audio levels (SSE), dual-model inference with per-model species + confidence, detection flow with animated connectors, today's KPIs, key events feed
  • Live spectrogram — real-time audio from mic with bird name overlay
  • Live log — real-time streaming dashboard (SSE) with color-coded categories, KPIs, pause/resume
  • Live Board — full-screen kiosk display for a dedicated screen: large species photo, KPIs, today's species list, weather, auto-refresh 30s, discreet back button

History

  • Calendar — monthly grid with per-day species count, detection count, activity heatmap, new species badges (★) and rare species badges (◆). Click a cell with badges to see a popover with species photos and names. Click any day to open the detail view
  • Timeline — full-page interactive timeline with drag-to-zoom, unified bird density slider (0-100%), SVG sunrise/sunset/moon icons, type filter badges with blink highlight, confidence-mapped vertical layout
  • Detections — full filterable table with favorites, new species filter, per-detection delete, CSV/eBird export
  • Review — auto-flagged detections with spectro modal, bulk confirm/reject/delete with preview, purge rejected

Species

  • Species cards with photos (iNaturalist + Wikipedia), IUCN status, favorites (SQLite-backed), personal notes (per-species and per-detection), phenology calendar (12-month dot map), year-over-year monthly comparison, chart PNG export, Web Share API
  • Favorites — dedicated page with KPIs, search, sort; heart toggle on all species lists
  • Rarities — full-width clickable KPI cards, filterable table (seen once / new this year), detailed species list with photos and confidence badges
  • Recordings — unified audio library with two tabs: "Library" (all recordings, sortable/filterable) and "Best" (top recordings grouped by species)

Indicators

  • Weather — Open-Meteo correlation analysis (Pearson r), tomorrow's forecast, plus full ornithological analytics: 4 leaderboards (cold tolerance · storm singers · heavy rain · strong wind), species × temperature heatmap (top 30, -15…+35 °C bins), and a live custom-search card with 6 filterable dimensions (temp, precip, wind, hour-of-day, date range, conditions) — answers "which species are still active when it's freezing?" in one click. URL-shareable filters and CSV export
  • Per-detection weather context — every detection is tagged with hourly weather snapshot (temp, humidity, wind, precip, cloud, pressure, WMO code) via background weather-watcher polling Open-Meteo. Compact weather chips appear on today, overview, recordings, rarities, review, favorites, and inside the spectrogram modal. Per-species "Weather profile" panel on species.html shows the species' typical conditions (avg temp, range, % during precip) plus distribution histograms. Backfilled to the oldest detection in the DB via Open-Meteo's free archive API (no key required)
  • Statistics — rankings, records, distributions, annual evolution; integrated Models tab for dual-model comparison (daily chart, exclusive species, overlap analysis)
  • Advanced analyses (polar charts, heatmaps, time series, narrative)
  • Biodiversity — Shannon index, adaptive richness chart, taxonomy heatmap
  • Phenology calendar — observed annual cycle per species (presence/abundance/hourly modes), inferred phases (active period, peak abundance, dawn chorus, migrant detection), 53-week ribbon visualization, species suggestions on empty state
  • Seasons — seasonal ornithological report (spring/summer/autumn/winter). Migratory arrivals with date comparison vs previous year (earlier/later), departures, season-exclusive species, multi-year evolution chart, best days, top species with year-over-year delta
  • Compare — side-by-side disambiguation of 2 species. Identity cards, deterministic verdict (not enough data / possible model confusion / strong seasonal separation / distinct profiles), 24h activity overlay, weekly phenology overlay, confidence histogram, reliability badge. Hardcoded "often confused" pairs (Chiffchaff/Willow Warbler, Marsh/Willow Tit…)

Navigation

  • 6 intent-based sections: Home, Live, History, Species, Indicators, Station
  • Mobile bottom nav (4 quick links + hamburger drawer with all 20 pages)
  • Global species+date search, notification bell, review badge counter
  • Keyboard shortcuts on 5 pages, swipe gestures on species photos
  • Skeleton loading states for data-heavy pages
  • Cross-navigation between settings and system pages

First-run setup wizard

  • 7-step hardware-aware modal — auto-triggered on fresh install (no setup flag, lat/lon=0). Detects Pi model, RAM, sound cards, disks, internet via /api/setup/hardware-profile and proposes adapted defaults. Steps: Welcome (with detected hardware preview) → Location → Audio source (USB-recommended badge) → Model (Single/Dual based on hardware) → Pre-filters (privacy + dog) → Integrations (BirdWeather, Apprise) → Recap. Applies config to disk without restarting any service — ongoing detections never interrupted, user restarts the engine when ready. Re-runnable any time from Settings → Station → "Launch wizard". Auto-skipped after first successful completion via config/setup-completed.json. Available in 4 languages.

Detection Review

  • Auto-flagging — nocturnal birds by day, out-of-season migrants, low confidence isolates, non-European species
  • Bulk actions — confirm/reject/delete by rule, per-selection, or purge all rejected
  • Full spectrogram modal with gain/highpass/lowpass filters and loop selection for manual verification
  • Permanent deletion — preview modal listing what will be deleted (DB + audio files), with result report

Audio Configuration

  • Auto-detection of USB audio devices with one-click selection
  • Adaptive gain — noise floor estimation, clip guard, activity hold, observer/apply modes
  • Bandpass + denoise — highpass (50-300 Hz), lowpass (4-15 kHz), spectral gating (noisereduce), all toggleable per profile
  • Ambient noise profile — record 5s of background noise (highway, HVAC), used for targeted spectral subtraction via noisereduce y_noise — more effective than auto-denoise for constant noise sources
  • Filter preview — before/after spectrograms from live mic to visualize the effect of each filter including the noise profile
  • Audio pipeline — Mic → Adaptive Gain → Highpass → Lowpass → Noise Profile (or auto denoise) → RMS Normalize → BirdNET + Perch — visual pipeline diagram in Settings
  • 6 environment profiles (garden, forest, roadside, urban, night, test)
  • Inter-channel calibration wizard for dual EM272 microphones
  • Real-time VU meters via SSE

Community Network

  • BirdStation Network — opt-in community of stations sharing daily detection summaries via Supabase
  • Live station map — all registered stations on an interactive dark-themed map
  • In-app bug reporting — submit issues directly to GitHub from the dashboard header, with optional log attachment (last hour of service logs included in the issue)

Settings & System

  • Full settings UI — models (one-click BirdNET download with license acceptance), analysis parameters, notifications, audio, backup
  • Interactive GPS map — Leaflet/OpenStreetMap widget in station settings with click-to-set, drag marker, and geolocation button
  • System health — CPU, RAM, disk, temperature, services
  • Web terminal — full bash in browser, supports Claude Code
  • Backup — NFS/SMB/SFTP/S3/GDrive/WebDAV with scheduling
  • 12 themes — 7 dark (Forest, Night, Ocean, Dusk, Solar Dark, Nord, High Contrast AAA), 4 light (Paper, Sepia, Solar Light, Colonial), plus an Auto mode that follows the OS prefers-color-scheme. Mini page previews in the picker, smooth cross-fade between themes, fully token-driven (design system documented in docs/THEMES.md)
  • Photo management — ban/replace photos, set preferred photo per species
  • Customizable branding — configurable station name and header brand via settings
  • 4 UI languages (FR/EN/NL/DE) + 36 languages for species names
  • Locale-aware units & formats — auto-detected from browser locale (°C/°F, km/h/mph, 12h/24h, DMY/MDY/ISO dates, Mon/Sun week start), overridable in Settings → Station

Optimized Perch V2 Models

We publish 3 optimized Perch V2 TFLite models for edge deployment, converted from the official Google SavedModel:

ernensbjorn/perch-v2-int8-tflite on HuggingFace

Model Size Latency (Pi 5) Top-1 Top-5 Best for
perch_v2_original.tflite 409 MB 435 ms baseline baseline Pi 5 (default)
perch_v2_fp16.tflite 205 MB 384 ms 100% 99% Pi 4 (default)
perch_v2_dynint8.tflite 105 MB 299 ms 93% 90% Pi 3 (default)

Benchmarked on Raspberry Pi 5 (8 GB, Cortex-A76 @ 2.4 GHz), 20 real bird recordings from 20 species, 5 runs each, 4 threads. The installer auto-selects the optimal variant for your Pi model.

Hardware

Component Recommended
SBC Raspberry Pi 5 (8GB) recommended — also works on Pi 4 (4GB+) and Pi 3 (1GB, INT8 models only)
Storage NVMe SSD (500GB+)
Audio Any USB audio interface (e.g., RODE AI-Micro, Focusrite Scarlett, Behringer UMC, UGreen 30724) + microphone
Network Ethernet or WiFi

Low-RAM Pis (≤ 4 GB): BirdNET + Perch + Node + arecord can pressure memory and trigger OOM kills under load. The installer auto-runs scripts/configure_zram.sh which tunes zstd-compressed zram swap (50 % of RAM on ≤2 GB hosts, 25 % on 3-4 GB hosts) via systemd-zram-generator (modern) or zram-tools (legacy). Re-run any time, or bash scripts/configure_zram.sh --status to inspect. Skipped silently on ≥6 GB hosts where modern RPi OS defaults already suffice.

Expose on the internet

By default birdash trusts the LAN — anyone on 192.168.x.x can change settings. To safely show your station to friends or embed it in a public site:

  1. Enable auth. In Settings → Station → Security, pick a mode:

    • Public read-only ⭐ — visitors can browse detections, species, stats, audio. Login required to change settings, edit detections, or see logs. Recommended for public sharing.
    • Protected — login required for everything.

    Set a username + password (8 chars min, bcrypt-hashed in birdnet.conf). Login attempts are rate-limited 5/min/IP.

  2. Reverse-tunnel with Cloudflare (no port-forwarding, free TLS, hides your home IP):

    # On your Pi
    curl -L https://github.com/cloudflare/cloudflared/releases/latest/download/cloudflared-linux-arm64.deb -o cloudflared.deb
    sudo dpkg -i cloudflared.deb
    
    # Login + create a tunnel
    cloudflared tunnel login
    cloudflared tunnel create birdash
    cloudflared tunnel route dns birdash birds.example.com
    
    # /etc/cloudflared/config.yml
    tunnel: <UUID-from-create>
    credentials-file: /root/.cloudflared/<UUID>.json
    ingress:
      - hostname: birds.example.com
        service: http://localhost:80
      - service: http_status:404
    
    sudo cloudflared service install
    sudo systemctl restart cloudflared

    Your station is now reachable at https://birds.example.com/birds/ with end-to-end TLS, no open ports on your router, and Cloudflare in front of any abuse.

  3. Don't forget the Bearer token. If you also use BIRDASH_API_TOKEN for cron/automation, that still works in parallel — set the Authorization: Bearer <token> header instead of logging in.

Alternatives: Tailscale Funnel, ngrok, plain port-forward + Caddy with Let's Encrypt — birdash doesn't care which transport you use as long as something terminates TLS in front of it.

Prerequisites

  • Raspberry Pi 3/4/5 with Raspberry Pi OS 64-bit (Bookworm/Trixie) — Pi 5 recommended for dual-model
  • Internet connection (for initial setup and model download)
  • USB audio interface + microphone(s)
    • Lavalier (clip-on) microphones with TRRS plug need a TRRS→TRS adapter for standard USB sound cards
    • The installer auto-configures ALSA with a software gain boost for low-sensitivity USB mics

All other dependencies are installed automatically by the installer.

Installation

One-line install (recommended)

curl -sSL https://raw.githubusercontent.com/ernens/birdash/main/bootstrap.sh | bash

That's it. The bootstrap installs git if needed, clones the repo into ~/birdash, runs install.sh non-interactively, downloads the BirdNET V2.4 model, enables dual-model detection (BirdNET + Perch), and starts all services. When it finishes, open the dashboard URL printed at the end and tweak GPS/audio from Settings.

BirdNET V2.4 is under CC-BY-NC-SA 4.0 (non-commercial use — see the BirdNET-Analyzer repo). To skip the BirdNET download and use Perch-only:

curl -sSL https://raw.githubusercontent.com/ernens/birdash/main/bootstrap.sh | BIRDASH_SKIP_BIRDNET=1 bash

Manual install

# 1. Clone and install
cd ~
git clone https://github.com/ernens/birdash.git
cd birdash
chmod +x install.sh
./install.sh                # interactive
# or: ./install.sh --yes    # non-interactive

# 2. Start all services
sudo systemctl enable --now birdengine-recording birdengine birdash caddy ttyd

# 3. Open the dashboard and configure
#    → Settings → Station: set GPS coordinates via interactive map
#    → Settings → Detection: download BirdNET V2.4 (one-click)
#    → Settings → Audio: select your USB audio device

The installer handles everything: system packages, Caddy, ttyd, databases, Perch V2 models (auto-downloaded from HuggingFace, variant adapted to your Pi model), services, and cron jobs. BirdNET V2.4 is installed via the dashboard (CC-NC-SA license acceptance required).

Your dashboard will be available at http://yourpi.local/birds/

Updating

In-app update (recommended)

When a new version is available, a red banner appears at the top of every page with the real semver version (e.g. v1.7.0 → v1.7.3). Click View to see categorized release notes, then:

  • Install now — applies the update, restarts services with health-check, auto-reloads the page
  • Later (24h) — snoozes the banner for 24 hours
  • Skip these updates — hides until a newer version is published

On failure:

  • Roll back — reverts to the previous version (appears when previousCommit is known)
  • Force update — forces the update even with diverged history or dirty files
  • Show log — expandable log viewer for debugging

On success: a confirmation message is shown, and the page auto-reloads after 2 seconds.

Remote update via SSH

ssh user@yourpi.local 'bash ~/birdash/scripts/update.sh'

Fan-out to multiple stations

for h in mickey donald papier; do
  ssh "$h.local" 'bash ~/birdash/scripts/update.sh'
done

Versioning (semver)

BirdStation follows Semantic Versioning: MAJOR.MINOR.PATCH

Bump When Example
PATCH Bug fix, polish, CSS tweak 1.7.0 → 1.7.1
MINOR New feature, screen refonte 1.7.3 → 1.8.0
MAJOR Breaking change, DB migration 1.8.0 → 2.0.0

Version source of truth: package.json. Bump before pushing:

bash scripts/bump.sh patch    # bug fix
bash scripts/bump.sh minor    # new feature
bash scripts/bump.sh major    # breaking change
bash scripts/bump.sh          # auto from last commit (feat:→minor, else→patch)

How it works

  • /api/update-status compares local git rev-parse HEAD against git ls-remote origin main (1-minute cache)
  • latestVersion is fetched from the remote package.json via GitHub Contents API (real version, no guessing)
  • update.sh runs: git fetch → merge → npm/pip install (fatal on failure) → migrations → health-check restart
  • rollback.sh reverts to a known commit: git reset --hard → npm install → health-check restart
  • All update output is logged to config/update.log
  • Stale "running" states auto-expire after 10 minutes
  • Snooze state stored server-side in config/update-state.json (persistent across browsers)
  • BIRDASH_SKIP_BIRDNET=1 skips BirdNET download during install if desired

What the Installer Does

Step Action
1 System packages (Node.js, Python, ffmpeg, alsa, sqlite3, Caddy, ttyd)
2 Node.js dependencies
3 Python venv + ML dependencies (ai-edge-litert, numpy, soundfile, resampy, scipy, noisereduce)
4 Directory structure (audio, models, BirdSongs)
5 Database bootstrap (birds.db + birdash.db with full schema)
6 GeoIP auto-detection (latitude, longitude, language from ipapi.co)
7 Configuration files (birdnet.conf with Pi-aware defaults, engine config, ALSA dsnoop for shared mic access)
8 Model download — Perch V2 from HuggingFace (auto: FP32 on Pi 5, FP16 on Pi 4, INT8 on Pi 3)
9 Systemd services with KillMode=process (engine, recording, dashboard, terminal)
10 Caddy reverse proxy
11 BirdNET V2.4 download via birdnetlib (CC-BY-NC-SA 4.0) + l18n species labels (38 languages)
12 Enable dual-model (BirdNET primary + Perch secondary), start all services

Note: BirdNET V2.4 download can be skipped with BIRDASH_SKIP_BIRDNET=1 and installed later from the dashboard: Settings → Detection → Download BirdNET V2.4.

Tests

# Node.js backend tests (160 tests including cross-page coherence)
npm test

# Python engine tests (13 tests)
cd engine && ../engine/venv/bin/python -m unittest test_engine -v

# Smoke test — loads every page in a headless browser, captures pageerror
# + console.error + 5xx, exits non-zero on any failure. Catches the
# silent regressions screenshot-only runs miss (broken JS, missing icons,
# pages that fail to mount).
npm run smoke                       # local
npm run smoke http://biloute.local  # against any Pi station

# Refresh README screenshots (Paper theme, EN, 1440x900)
npm run screenshots

Project Structure

birdash/
├── server/
│   ├── server.js                  # HTTP server, middleware, route delegations (271 lines)
│   ├── lib/
│   │   ├── adaptive-gain.js       # Adaptive software gain algorithm
│   │   ├── alerts.js              # System alert monitoring (temp, disk, RAM)
│   │   ├── alert-i18n.js          # Alert message translations (4 langs)
│   │   ├── config.js              # BirdNET config, settings validators, exec helper
│   │   ├── db.js                  # Database bootstrap, tables, taxonomy
│   │   ├── notification-watcher.js # Push notifications (polls DB, sends via Apprise)
│   │   ├── result-cache.js        # Proactive result cache for heavy queries
│   │   ├── safe-config.js         # Atomic JSON config read/write with mutex
│   │   ├── telemetry.js           # Telemetry: anonymous pings + community network
│   │   ├── weather-watcher.js     # Hourly Open-Meteo poll + archive backfill
│   │   └── whats-new-worker.js    # Worker thread for heavy computation
│   └── routes/
│       ├── audio.js               # Audio routes — thin dispatcher (45 lines)
│       ├── audio/                  # Audio sub-modules (split from audio.js)
│       │   ├── _helpers.js         # jsonConfigGet/Post, paths, whitelists
│       │   ├── streaming.js        # /api/audio-info, audio-stream, live-stream, live-pcm
│       │   ├── devices.js          # /api/audio/devices, test, config, boost
│       │   ├── profiles.js         # /api/audio/profiles CRUD + activate
│       │   ├── calibration.js      # Inter-channel gain wizard
│       │   ├── monitoring.js       # SSE VU meter + filter preview
│       │   ├── adaptive_gain.js    # Adaptive-gain endpoints + bg collector
│       │   └── noise_profile.js    # Ambient-noise capture
│       ├── backup.js              # Backup config, scheduling, export
│       ├── bug-report.js          # In-app bug reporting (GitHub Issues)
│       ├── comparison.js          # Seasonal report (spring/summer/autumn/winter)
│       ├── data.js                # Favorites, notes, photo-pref, query
│       ├── detections.js          # Detections, validations, flagging
│       ├── external.js            # BirdWeather, eBird, Open-Meteo, weather analytics
│       ├── photos.js              # Photo resolution/caching, species names
│       ├── settings.js            # Settings, apprise, alerts, logs SSE
│       ├── setup.js               # Setup wizard backend (status, hardware-profile, complete)
│       ├── system.js              # Services, health, hardware, models
│       ├── telemetry.js           # Telemetry routes (register, anonymous pings toggle)
│       ├── timeline.js            # Timeline with SunCalc astronomy
│       ├── updates.js             # Update system: status, apply, rollback, force, log
│       └── whats-new.js           # Daily overview cards
├── public/                        # Static frontend (Vue 3 (vendored))
│   ├── index.html                 # Redirect to overview.html
│   ├── overview.html               # Landing page — KPIs, bird of the day, weather
│   ├── dashboard.html              # Bird Flow — live pipeline visualization
│   ├── today.html                 # Today's detections with audio filters
│   ├── calendar.html              # Monthly calendar with new/rare species badges + popover
│   ├── timeline.html              # Full-page timeline with drag-to-zoom
│   ├── detections.html            # Filterable detection table
│   ├── review.html                # Detection review + bulk actions
│   ├── species.html               # Species cards + favorites + notes
│   ├── gallery.html               # Redirect → recordings.html
│   ├── favorites.html             # Favorites with stats + management
│   ├── weather.html               # Weather/activity correlation
│   ├── stats.html                 # Statistics + integrated Models tab
│   ├── analyses.html              # Per-species deep analysis
│   ├── biodiversity.html          # Shannon index, adaptive richness chart
│   ├── phenology.html             # Observed phenology calendar (per species)
│   ├── comparison.html            # Seasonal report (migratory arrivals, departures, evolution)
│   ├── compare.html               # Compare 2 species (disambiguation: identity, verdict, 24h, phenology, confidence)
│   ├── spectrogram.html           # Live spectrogram + clip playback
│   ├── settings.html              # Full settings (9 tabs)
│   ├── system.html                # System health + terminal
│   ├── liveboard.html              # Live Board — kiosk display mode
│   ├── log.html                   # Live log dashboard (SSE)
│   ├── recordings.html            # Audio library with photos
│   ├── rarities.html              # Rare species tracker
│   ├── recent.html                # Redirect to calendar.html
│   ├── models.html                # Redirect to stats.html?tab=models
│   ├── js/
│   │   ├── bird-config.js         # Navigation, API config
│   │   ├── bird-queries.js        # Shared SQL query library (38 queries)
│   │   ├── bird-icons.js          # Lucide icon set (98 SVG icons)
│   │   ├── bird-shared.js         # Utilities, DSP, favorites, notes API
│   │   ├── bird-vue-core.js       # Vue composables, i18n (4 langs), shell
│   │   ├── bird-spectro-modal.js # SpectroModal component (extracted)
│   │   ├── bird-weather-chip.js   # &lt;weather-chip&gt; component + global cache
│   │   ├── bird-setup-wizard.js   # &lt;setup-wizard&gt; 7-step onboarding modal
│   │   ├── bird-timeline.js       # Timeline rendering (sky, stars, markers)
│   │   ├── vue.global.prod.min.js # Vue 3 (vendored)
│   │   ├── chart.umd.min.js      # Chart.js (vendored)
│   │   └── echarts.min.js        # ECharts (vendored)
│   ├── i18n/                      # Translation files (fr/en/de/nl.json)
│   ├── css/                       # Styles + 12 themes (see docs/THEMES.md)
│   ├── settings/                  # Lazy-loaded settings tab fragments
│   └── sw.js                      # Service Worker (offline cache)
├── engine/                        # BirdEngine (Python detection engine)
│   ├── engine.py                  # BirdEngine orchestrator + main (~850 lines)
│   ├── audio.py                   # I/O · sound-level · adaptive gain · filters · split_signal
│   ├── models.py                  # TFLite wrappers (BirdNET v1/v2.4, Perch v2) + factory
│   ├── clips.py                   # MP3 extraction + plasma-colormap spectrogram PNG
│   ├── birdweather.py             # Soundscape + per-detection upload
│   ├── db.py                      # SQLite bootstrap + write_detection
│   ├── watcher.py                 # WavHandler (one-behind rotation trick)
│   ├── yamnet_filter.py           # Privacy + dog YAMNet pre-filter (opt-in)
│   ├── config.toml                # Engine configuration
│   ├── record.sh                  # Audio capture (arecord)
│   ├── purge_audio.sh             # Disk space management
│   ├── convert_from_saved_model.py # Perch V2 optimization script
│   ├── birdengine.service         # systemd: detection engine
│   ├── birdengine-recording.service # systemd: audio capture
│   ├── ttyd.service               # systemd: web terminal
│   └── models/                    # TFLite models (not in git)
├── config/
│   ├── birdash.service            # systemd: dashboard
│   ├── audio_config.json          # Audio device config
│   ├── audio_profiles.json        # 6 environment profiles
│   ├── detection_rules.json       # Auto-flagging rules
│   └── birdash-local.example.js   # Local config template
├── scripts/
│   ├── update.sh                  # Update: git pull, deps, migrations, health-check restart
│   ├── rollback.sh                # Rollback: git reset --hard, deps, restart
│   ├── bump.sh                    # Semver bump (patch/minor/major/auto)
│   ├── backup.sh                  # Incremental backup (rsync)
│   ├── bench-sqlite.mjs           # SQLite query bench (--baseline / --tuned, 9 representative queries)
│   ├── cleanup_throttle.py        # Retroactive noisy-species purge (DB + audio quarantine, --dry-run by default)
│   ├── configure_zram.sh          # Auto-tune zram swap (zstd, % of RAM); skips on ≥6 GB hosts
│   └── smoke.mjs                  # Headless smoke test of all pages
├── tests/
│   └── server.test.js             # Backend tests
├── README.md                      # English
├── README.fr.md                   # Francais
├── README.nl.md                   # Nederlands
└── README.de.md                   # Deutsch

Environment Variables

Variable Default Description
BIRDASH_PORT 7474 API server port
BIRDASH_DB ~/birdash/data/birds.db SQLite database path
EBIRD_API_KEY eBird API key (optional)
BW_STATION_ID BirdWeather station ID (optional)

Security

  • Rate limiting: 300 req/min per IP
  • Strict SQL validation (read-only, parameterized)
  • Centralized SQL query library (bird-queries.js) — 38 parameterized queries with automatic confidence filtering
  • Lucide icon system (bird-icons.js + <bird-icon> component) — 100+ modern SVG icons, theme-aware form controls (accent-color)
  • Security headers (CSP, X-Frame-Options, Referrer-Policy)
  • CORS restricted to localhost
  • Worker threads for heavy computation (event-loop non-blocking)
  • Auto-download of species translation labels when missing (BirdNET GitHub fallback)

Telemetry & Privacy

BirdStation has two independent telemetry layers:

Anonymous usage pings (opt-out) — enabled by default, disableable in Settings → Station:

  • Sends a monthly ping with: version, Pi model, OS, country
  • No GPS, UUID, station name, IP, or any personal data
  • Install and update events also recorded (same anonymous data)
  • Helps us track adoption and which platforms to prioritize
  • Disable anytime in Settings → Station → "Anonymous usage statistics"

Community network (opt-in) — disabled by default:

  • Registers your station on the live map with GPS + station name
  • Sends daily detection summaries (top species, rare species)
  • Enable in Settings → Station → "Join the network"

Both layers use Supabase with a public anon key (write-only RLS). No data is collected until the service starts, and anonymous pings can be fully disabled.

Community

  • Live Station Map — see all registered BirdStation installations worldwide
  • Report a bug — or use the in-app bug report button (red bug icon in header)
  • Discussions — questions, ideas, show your setup

Star History

Star History Chart

License

MIT

About

Real-time bird detection dashboard for Raspberry Pi with BirdNET + Perch V2. Dual-model inference, live spectrogram, interactive timeline, weather correlation, 15+ pages, 4 languages.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors