Automatic bird identification with Home Assistant
My wife and I love birding. Our interest in the hobby intensified during COVID, spending many mornings at our favorite birdwatching spot.
When Merlin Bird ID added Sound ID in 2021, we were hooked immediately! It felt like something out of Harry Potter to be able to have our phones tell us what bird we were hearing, even if we couldn’t see it. About a year later, the BirdNET-Pi project made it easy to run the Sound ID model locally. One of the audio sources supported was the RTSP output, which I used with two of our Ubiquiti cameras.
While it worked well at identifying birds accurately, the app crashed randomly. First, I tried installing BirdNET-Pi as a Home Assistant Addon, as my HA hardware was vastly overprovisioned compared to the Raspberry Pi. This reduced the crashes, but did not eliminate them. A few months later, a fellow birding and Home Assistant enthusiast recommended I try BirdNET-Go, which is a rewrite of BirdNET-Pi with improved stability and performance. This fixed the reliability issues once and for all and I haven’t had any crashes since then.
Sifting through the data
With the stability issue resolved, I had a bigger problem: what to do with all of this data? While BirdNET-Go provided a nice dashboard for viewing detections, I wanted to find a way to surface insights about the data that were interesting to me without having to comb through the feed. Around the same time, I was developing the latest version of Timeframe, my e-paper dashboard system. Caitlin suggested we highlight the most interesting detection of the past day.
After trying a few different algorithms, I ended up with a simple REST sensor. The sensor fetches the summary data from BirdNET-Go, filters it to only include detections from the past day, then sorts them by the bird most recently heard for the first time:
# configuration.yaml
sensor:
- platform: rest
resource: http://homeassistant.local:8080/api/v2/analytics/species/summary
scan_interval: 300
name: "Most Interesting Bird"
unique_id: birdnet_most_interesting
value_template: >
{% set cutoff = (now() - timedelta(hours=24)).strftime('%Y-%m-%d %H:%M:%S') %}
{% set birds = value_json
| rejectattr('common_name', 'eq', 'Engine')
| selectattr('last_heard', 'ge', cutoff)
| sort(attribute='first_heard', reverse=true)
| list %}
{{ birds[0].common_name if birds | length > 0 else 'Unknown' }}
It’s been fun to see new species appear for the first time as an early spring arrives here in Colorado: