Skip to content

Releases: zach7036/BirdNET-Pi-Enhanced-Version

v2.4.5 — Clean Sweep

Choose a tag to compare

@zach7036 zach7036 released this 07 Aug 17:11

This release clears the entire August audit backlog — every remaining finding from the full-codebase review, plus everything three follow-up review rounds caught. Fourteen fixes spanning security, data safety, and long-standing paper cuts.

🛡️ Security & privacy

  • Third-party image metadata is now escaped everywhere. Flickr photo titles and author/license URLs are uploader-controlled text; the Species Stats and Overview photo modals rendered them raw into the page. All pages now share one canonical escaping helper, so future hardening lands everywhere at once.
  • Image Provider "None" now really means none. The image API and the Species page contacted Wikipedia even with images disabled, contradicting the Settings privacy text ("nothing leaves your network..."). Every image path now respects the setting.
  • The spectrogram page no longer rewrites your config. A stale livestream stream selection used to trigger a config rewrite and root-level service restart from an unauthenticated page view — with a truncate-and-write that could corrupt birdnet.conf under concurrent access. The page now shows an honest "Live audio is stopped" warning and repairs the setting through the authenticated save when you pick a stream.

🐛 Fixed

  • Recordings can no longer be silently lost. If reporting fails mid-detection (full disk, database contention), the audio now moves to a Failed folder beside your recordings (capped at the newest 50) instead of being stranded in RAM or deleted. Move a file back to StreamData and restart to retry — retries are safe and won't duplicate detections or notifications. Database write failures are surfaced instead of silently dropping detections.
  • "Open in new tab" links work. Every detection's open-in-new-tab icon — and the link in Apprise notifications — landed on the generic dashboard instead of that recording. They now open the recording page.
  • The Kiosk view works again. A JavaScript error killed the detection timeline and auto-refresh the moment the page loaded.
  • Insights accuracy: the PEAK NOW badge compares week numbers in one convention and in local time (it could light the wrong species for stretches of the year); "Expected Today" no longer goes blank from Dec 29 to Jan 3; and early-January no longer counts last week's birds as prior-year history.
  • Species list management: species with apostrophes (Anna's Hummingbird, Cooper's Hawk...) no longer get duplicate entries on every submission, and a missing labels file renders an empty list instead of raw PHP warnings.
  • Image caching heals itself: one failed Flickr license lookup used to permanently disable caching for that species, re-running every API call on every page load.
  • Overview polish: the dashboard keeps refreshing when new detections are waiting on spectrograms mid-list, and the KPI strip no longer renders blank on a fresh browser session.
  • Installer: aborted installs (root user, old OS, sudo problems) now exit with a failure code so scripts can detect them, and a dangling weekly_report.php link is no longer planted in the web root.

⚡ Performance

  • Insights forecasting is dramatically lighter: historical peak weeks are computed in a single query instead of one query per species ever detected — hundreds of queries per page load on a mature station — and the health subview no longer runs that same workload just to discard the results.
  • Backlog-mode dashboard refreshes are throttled to every 30 seconds instead of up to every 1–3 seconds for hours on an already-busy Pi.

Updating

cd ~/BirdNET-Pi
git fetch origin
git pull --ff-only origin main
sudo bash scripts/update_birdnet_snippets.sh

Then refresh your browser.

🤖 Generated with Claude Code

v2.4.4 — Audit Hardening

Choose a tag to compare

@zach7036 zach7036 released this 07 Aug 04:32

Ten fixes from a full-codebase security and stability audit: two security holes closed, three crash classes eliminated, and the Overview dashboard is dramatically lighter on your Pi.

🛡️ Security

  • Cross-site scripting fixed on the Insights page. The subview name from the URL was echoed back into the page unescaped; it's now validated against the list of real subviews.
  • Service buttons work again — safely. The Stop/Restart/Enable/Disable buttons for the Live Audio Stream and the RAM drive in Settings silently did nothing (their commands never matched the security allowlist after input sanitizing). The comparison now happens on the decoded value, so the buttons work and the allowlist still guards every command.

🐛 Fixed

  • Insights → Environmental no longer crashes on fresh installs. With weather synced but no detections yet in the last 30 days, the page died with a fatal error. Thanks to @FrostSaint for the report and fix (#18)!
  • Notifications and weather sync no longer die silently on missing settings. Any config key absent from birdnet.conf (typical after restoring a backup made on an older version) crashed the Python side invisibly — weather updates stopped and every Apprise notification was dropped. Missing keys now fall back cleanly, and a missing notification title uses the default.
  • The weather table is created at install time, not after the first successful fetch — so offline stations and fresh installs get a working database schema immediately instead of error states on the weather pages.
  • Weather sync survives non-standard home directories. The hourly cron entry was written with a hardcoded /home/<user> path in one place and the real home in another; an update could silently kill weather sync on systems where those differ. Both now derive the real home directory.

⚡ Performance

  • The Overview dashboard now refreshes only when a new detection actually arrives. Previously a broken guard made it re-run every chart, KPI, and recent-detections query every ~3 seconds for as long as the tab was open — a constant CPU and database load on the Pi. It still refreshes live during audio-backlog processing and when you return to the tab.
  • Checking for a new detection is now nearly free. Each poll used to render a full detection card server-side — including Flickr/Wikipedia image lookups — just to be thrown away. The check now returns a one-line answer.
  • Chart loads no longer stall on offline stations. When the weather API is unreachable, the on-demand sync retries at most every 10 minutes instead of blocking page requests for up to 20 seconds each.

Updating

cd ~/BirdNET-Pi
git fetch origin
git pull --ff-only origin main
sudo bash scripts/update_birdnet_snippets.sh

Then refresh your browser.

🤖 Generated with Claude Code

v2.4.3 — Midnight Cleanup

Choose a tag to compare

@zach7036 zach7036 released this 26 Jul 16:16

Bug fix: the Today page now fully resets when the day rolls over while it's open.

🌙 No more ghost birds after midnight

  • If you left the Today page open past midnight, the Last heard card could show "No detections yet today" with yesterday's bird still underneath — photo, scientific name, badges, audio player, and the About/Review links all lingered until you refreshed the page. The live refresh now restores the clean listening state the moment the new day starts with no detections.
  • The "Review N uncertain visits" link now disappears when the count drops back to zero, instead of keeping yesterday's number on screen.

Updating

cd ~/BirdNET-Pi
git fetch origin
git pull --ff-only origin main
sudo bash scripts/update_birdnet_snippets.sh

Then refresh your browser.

🤖 Generated with Claude Code

v2.4.2 — Instant Filters

Choose a tag to compare

@zach7036 zach7036 released this 16 Jul 17:17

UX polish: filters that respond instantly, and honest empty states.

⚡ Filters apply as you use them

  • Birds page: searching now filters the species grid as you type — no reload, no lost focus, and the Total Species / Avg. Confidence cards update live with the filter. The URL tracks your filters, so a bookmark or refresh reproduces the view. Changing Time Period or Sort By refreshes in place too.
  • Insights → Charts: changing the Time Period re-draws the charts immediately — no more hunting for the Apply button. (The species-picker keeps its Apply button on purpose: check several boxes, then apply once.)
  • Enter, Apply Filters, Export CSV, and Reset all keep their old behavior, so everything still works with JavaScript disabled.

🪧 Honest empty states

  • The Weather Insights page no longer tells new users to activate a "Weather Plugin" that doesn't exist (the copy that confused early adopters). It now explains that weather syncs automatically every hour once your coordinates are set, with links to Settings and Station Doctor.
  • Weather brackets with no detections show 0 instead of the ambiguous "N/A", and the vaguest "Not enough data yet" rows now explain that those sections fill in as your station listens.

Updating

cd ~/BirdNET-Pi
git fetch origin
git pull --ff-only origin main
sudo bash scripts/update_birdnet_snippets.sh

Then refresh your browser.

🤖 Generated with Claude Code

v2.4.1 — Audit Fixes

Choose a tag to compare

@zach7036 zach7036 released this 16 Jul 06:19

Fixes from a full codebase audit — one data-integrity bug, one review-quality fix, and security hardening.

🐛 Fixed: reassigning a visit left its history behind

Renaming a detection's species updated the detections table and moved the files — but your review history and any crown purge-protection entries kept pointing at the old file name. A reassigned visit could reappear in the Review queue as never-reviewed, its clips vanished from comparison strips, and worst of all, a crowned (protected) clip could silently lose its protection from the disk cleaner. Reassignments now carry both along automatically.

Note: reassignments made before this version left orphaned records behind (harmless clutter, but if you crowned a clip and then reassigned it, re-crown it from the bird's page to restore protection).

🔍 Fixed: the comparison strip could verify a visit against itself

Every detection in a visit shares one acoustic event — the same individual bird, the same background, the same distant mimic — so its errors are correlated. A mockingbird doing a ten-minute Nighthawk impression should never be "verified" against its own visit-mates. The Review page's comparison clips now come strictly from other visits, giving you independent evidence, with the candidate search built so that even a marathon 100-detection visit can't leave the strip empty.

🔒 Security: cross-site request protection for file actions

The delete / rename / shift / protect actions responded to plain GET requests, meaning a malicious webpage could theoretically trigger them (e.g., delete recordings) while you were signed in to your station in the same browser. They now require the same request header the newer API already demands — something a cross-site page cannot send. If a delete or rename button ever shows "missing X-Requested-With header", please open an issue; it means a call site was missed.

🧪 Developer tooling

The smoke test suite can now reseed its demo database on demand (RESEED=1), ending a long-standing source of false test failures. No effect on stations.

Updating

cd ~/BirdNET-Pi
git fetch origin
git pull --ff-only origin main
sudo bash scripts/update_birdnet_snippets.sh

Then refresh your browser.

🤖 Generated with Claude Code

v2.4.0 — Your Own Thermometer

Choose a tag to compare

@zach7036 zach7036 released this 15 Jul 22:55

A new integration for the smart-home crowd, plus Species page polish.

🌡️ Local temperature from your own Home Assistant sensor

From issue #17 (@talkingdragon)

If you run Home Assistant with an outdoor temperature sensor, your station can now use your actual yard's temperature instead of the online weather model. Set three fields in Settings → Location & Weather:

  • Home Assistant URL (e.g. http://homeassistant.local:8123)
  • Access token (create a long-lived token in HA under your profile → Security)
  • Temperature entity (e.g. sensor.backyard_temperature)

The hourly weather sync still fetches conditions, wind, and history from Open-Meteo — but when your sensor is healthy, its reading wins the current hour. The fallback is automatic and stateless: if the sensor is unreachable, unavailable, or its value hasn't changed in over an hour (a frozen or disconnected sensor), that hour simply keeps the online value, with the reason logged. °C/°F/K readings convert automatically, and your display-unit setting keeps working as before.

Station Doctor gains a live "Local temperature sensor" check showing whether the current hour is using your sensor or the online fallback.

Leave the fields blank and nothing changes — the feature is fully dormant until configured. Every code path is tested against a simulated HA server; if you run a real HA install, feedback on #17 is very welcome.

🎨 Species page polish

The filter buttons never actually had styles — "Apply Filters" was a raw browser button, "Reset" floated above its neighbors, and "Export CSV" hid its label on a dark background. All three are now proper themed buttons on one baseline, and the Total Species / Avg. Confidence cards are wider and shorter so the header uses its space.

Updating

cd ~/BirdNET-Pi
git fetch origin
git pull --ff-only origin main
sudo bash scripts/update_birdnet_snippets.sh

Then refresh your browser.

🤖 Generated with Claude Code

v2.3.1 — Issue Fixes & Smarter Comparisons

Choose a tag to compare

@zach7036 zach7036 released this 11 Jul 17:19

Fixes for the first three issues filed against the fork — thank you @talkingdragon for the sharp reports — plus a smarter Review page.

🐛 Fixed: Reassign reported failure for successful renames (#16)

The rename script ends with a debug-only echo, and in the web UI's quiet mode that made every successful rename exit with an error status — the Review modal then showed "0 renamed, N failed" even though the files were moved and the database updated. If you ever saw that message: your reassignments almost certainly worked; check the bird's page.

Also in this fix: a real 401 now stops the reassign loop with a link that opens Settings so your browser can actually show its sign-in prompt (a background request never can), any genuine script error is shown verbatim instead of the old "check sign-in" guess, and the station now uses a single basic-auth realm, so signing in anywhere signs you in everywhere.

🖨️ New: reports print as clean A4 documents (#15)

Print Report now produces a proper document: no sidebar, tab bar, or buttons; ink-friendly flat cards; species lists that flow down the page without splitting rows; and — since the point of a printed monthly report is the complete record — every species prints, regardless of the on-screen "Show all" state. A typical monthly report fits on two A4 pages.

🐛 Fixed: "Show all species" on Reports did nothing (#14)

Two stacked bugs: the button's handler was silently overwritten by the Insights page's function of the same name, and the hidden rows were pinned by a CSS !important rule that inline styles can't override. Both fixed — the button now expands and collapses the full species list.

🔍 Better: the Review page's comparison strip

The "Compare with…" clips are now filled by priority: your confirmed clips at ≥80% confidence first, then the station's strongest recent matches, then weaker confirmed clips as a last resort. A new species starts with the model's best references; as you confirm good visits, the strip gradually becomes entirely your own verified audio. Mixed strips are labeled with a ✓ marking which clips you confirmed.

The strongest-match hunt also now searches recent detections rather than all-time bests — on a long-running station the all-time top clips have usually been purged from disk, which could leave the strip showing only faint clips despite fresh 90%+ recordings being available.

Updating

cd ~/BirdNET-Pi
git fetch origin
git pull --ff-only origin main
sudo bash scripts/update_birdnet_snippets.sh

Then refresh your browser.

🤖 Generated with Claude Code

v2.3.0 — Number Formats & the Midnight Fix

Choose a tag to compare

@zach7036 zach7036 released this 10 Jul 07:01

One new display setting and a set of real bug fixes — including one that had been hiding since the v2 heatmap shipped.

🔢 Number format setting

From Discussion #10 (@Svardsten53)

Settings → Display & Units has a new Number format dropdown: 1,234.5 (default), 1.234,5, or 1 234,5. It applies to every count, total, and percentage across the UI — Insights, Year in Birds, Reports, the Species gallery, and the live pages. Like the unit settings, it's display-only: nothing stored changes, switching is instant and reversible, and CSV exports and the API always keep machine format so nothing downstream breaks.

🌙 Fixed: "Heatmap unavailable" on days with no detections yet

Right after midnight — before the first bird of the day — the Today page's heatmap could show "Heatmap unavailable / Heatmap data could not be parsed." The error message blamed the data, but the data was fine: the heatmap's empty-state code was destroying its own canvas element, every subsequent refresh crashed on the missing canvas, and the crash was misreported as a parse failure. The empty day now simply says "No species yet today." (matching the Grid view), and the heatmap redraws cleanly when the first bird arrives.

Along the way, two genuine latent bugs got fixed too:

  • A busy database (e.g. the analyzer writing) made the chart endpoints answer with an HTML notice instead of JSON. They now wait out brief locks, and fail as proper JSON if they must fail.
  • The endpoint is hardened against stray output and invalid UTF-8, and the client now logs the raw response whenever something truly unparseable arrives.

📦 Fixed: updates not reaching your browser

Static JavaScript was version-stamped by date, so two updates on the same day produced identical URLs — and the PWA's cache served the old file, even past a hard refresh. Assets are now stamped by exact modification time, and this release's service worker automatically discards every browser's old cache. If an update ever seemed to "not take" before, this was why; from now on a plain refresh after updating is enough.

Updating

cd ~/BirdNET-Pi
git fetch origin
git pull --ff-only origin main
sudo bash scripts/update_birdnet_snippets.sh

Then refresh your browser.

🤖 Generated with Claude Code

v2.2.1 — Wikipedia in Your Language

Choose a tag to compare

@zach7036 zach7036 released this 10 Jul 05:45

A small follow-up to v2.2.0.

🌍 Wikipedia links in your language

Every Wikipedia link in the app (Species gallery, bird detail pages, Today's Detections, and the API) now follows your species-name language — the same Settings → Language & Species Info setting that localizes bird common names and eBird links. A station set to Swedish links to sv.wikipedia.org, German to de.wikipedia.org, and so on; the scientific-name URL redirects to the local article automatically.

There's nothing new to configure: if you've already set your language, the links just follow it after updating. English installs (or no language set) see no change.

From Discussion #10 (@Svardsten53).

Updating

cd ~/BirdNET-Pi
git fetch origin
git pull --ff-only origin main
sudo bash scripts/update_birdnet_snippets.sh

Then hard-refresh your browser (Ctrl+F5).

🤖 Generated with Claude Code

v2.2.0 — The Community Update

Choose a tag to compare

@zach7036 zach7036 released this 10 Jul 04:51

This release is built from your pull requests and discussions — thank you to @Kcalin, @E-Wold, @Svardsten53, and @Venceslas84. Every idea below started as a community contribution.

🌡️ Display & Units — Celsius, km/h, m/s, and 24-hour time

From PR #12 (@Kcalin) and Discussions #7, #10, #13

A new Settings → Display & Units section:

  • Temperature: Fahrenheit or Celsius — applied everywhere temperatures appear: sidebar weather, the Today hero, heatmap tooltips, the Timeline weather strip, System Health, and Weather Insights. In Celsius mode the insight brackets become true 5°C bins (0–4°, 5–9°, …), not relabeled Fahrenheit ranges.
  • Wind speed: mph, km/h, or m/s — wind analysis labels convert to your unit.
  • Time format: 12-hour or 24-hour — hour labels and clock times across Insights charts, Year in Birds, Reports, the Timeline, and the Today page axes.

Weather is always stored in one fixed unit — switching display units is instant, lossless, and fully reversible, and never mixes units in your historical statistics.

📝 Front-page info box + sidebar station name

From Discussion #13 (@Svardsten53)

  • Add your own text or HTML to a box at the top of the Today page — local notes, a welcome message for visitors, anything. Leave it empty and no box appears.
  • Optionally show your Site Name under the sidebar logo, handy when you run more than one station.

Both are in Settings → Display & Units.

🔁 Self-healing weather sync

From PR #9 (@E-Wold)

Open-Meteo hiccups no longer leave permanent holes in your weather charts: fetches retry automatically, and every successful sync backfills up to a week of history — recovering from Pi downtime, cron failures, or API outages on its own.

🖱️ Clickable species on the heatmap

From PR #8 (@E-Wold)

On the Today's Species heatmap, the bird's thumbnail and name now link to its detail page, just like the Timeline lanes.

🐛 Also in this release

  • Review queue: comparison strips ("Compare with this station's strongest matches") only offer clips that still exist on disk — previously, purged clips produced an empty strip with a flash of vanishing spectrograms. If nothing high-confidence survived cleanup, the best recent clips are offered instead.
  • "Now" is now "Today" — clearer next to "Live", and honest about what the page shows. All bookmarks and links keep working.

Updating

cd ~/BirdNET-Pi
git fetch origin
git pull --ff-only origin main
sudo bash scripts/update_birdnet_snippets.sh

Then hard-refresh your browser (Ctrl+F5). The updater seeds the new settings keys; everything defaults to current behavior (°F, mph, 12-hour) until you change it.

🤖 Generated with Claude Code