No fighting with other important issues at the moment (shitty iotawatt integration), but something has to be done. I replaced the microphone and now the birdnet list of detections is 100s of lines long each day.
Yes, me too - for now, I reverse sort them by time, and show the top 10…
That’s a good idea. Care to share your config for this?
Just a small addition to your markdown card:
- type: markdown
title: "BirdNET Events"
content: |-
Time|CommonName|Confidence
:---|:---|:---
{%- set t = now() %}
{%- set bird_list = [] %}
{%- for bird in (state_attr('sensor.birdnet_intake','bird_events')| sort(attribute='time', reverse=true))[0:10] or [] %}
{{bird.time}} | {{bird.name}} | {{bird.confidence }}
{%- endfor %}
My next attempt will be to show just the most recent ‘sighting’ of each bird…
I’ve also used the new webpage dashboard to put the full BirdNET dashboard in the side menu but it only works when I’m at home and using http access.
This code presents the most recent sighting of each unique bird in your events:
- type: markdown
title: "BirdNET Events"
content: |-
Time|Common Name|Day Count|Max Confidence
:---|:---|:---:|:---:
{%- set t = now() %}
{%- set bird_list = state_attr('sensor.birdnet_intake','bird_events') | sort(attribute='time', reverse=true) | map(attribute='name') | unique | list %}
{%- set bird_objects = state_attr('sensor.birdnet_intake','bird_events') | sort(attribute='time', reverse=true) %}
{%- for thisbird in bird_list or [] %}
{%- set ubird = ((bird_objects | selectattr("name", "equalto", thisbird)) | list)[0] %}
{%- set ubird_count = ((bird_objects | selectattr("name", "equalto", thisbird)) | list) | length %}
{%- set ubird_max_confidence = ((bird_objects | selectattr("name", "equalto", thisbird)) | map(attribute='confidence') | max) %}
{{ubird.time}} | {{ubird.name}} | {{ubird_count}} | {{ubird_max_confidence }}
{%- endfor %}
(edited to show most recent version)
That’s awesome. Thank you for sharing. The only addition I made was a couple of
spaces in front of the name and confidence for legibility:
Time| Common Name|Day Count| Max Confidence
:---|:---|:---:|:---:
{%- set t = now() %}
{%- set bird_list = state_attr('sensor.birdnet_go_events','bird_events') | sort(attribute='time', reverse=true) | map(attribute='name') | unique | list %}
{%- set bird_objects = state_attr('sensor.birdnet_go_events','bird_events') | sort(attribute='time', reverse=true) %}
{%- for thisbird in bird_list or [] %}
{%- set ubird = ((bird_objects | selectattr("name", "equalto", thisbird)) | list)[0] %}
{%- set ubird_count = ((bird_objects | selectattr("name", "equalto", thisbird)) | list) | length %}
{%- set ubird_max_confidence = ((bird_objects | selectattr("name", "equalto", thisbird)) | map(attribute='confidence') | max) %}
{{ubird.time}} | {{ubird.name}} | {{ubird_count}} | {{ubird_max_confidence }}
{%- endfor %}
So I got a new microphone. In the nighttime recordings (after traffic noise has died down) I can hear the waves crashing on the beach 1.3Km away and 100m below.
Lots more bird detections. Too many in-fact:
Logger: homeassistant.components.recorder.db_schema
Source: components/recorder/db_schema.py:598
integration: Recorder (documentation, issues)
First occurred: 15:26:57 (14 occurrences)
Last logged: 15:53:00State attributes for sensor.birdnet_go_events exceed maximum size of 16384 bytes. This can cause database performance issues; Attributes will not be stored
Create multiple sensors and filter based on time?
So 1 for the hours 00:00 - 06:00
the 2nd none for 06:00 - 12:00 etc
Hello, can you share configuration of mqtt sensor for birdnet-go? I’m trying to get the data from birdnet
mqtt:
sensor:
- name: "BirdNet"
state_topic: "birdnet"
unique_id: bird
I don’t use an mqtt sensor. I use a triggered template sensor as shown above Displaying Birdnet-go detections - #6 by tom_l
And this post: Displaying Birdnet-go detections - #7 by tom_l
thanks Tom, it’s works for me, maybe you can tell me how to add a link to the wiki about each bird like this https://community.home-assistant.io/t/birdnet-pi/444654/10
fixed
https://en.wikipedia.org/wiki/{{bird_name | replace(' ', '_')}}
Thanks a lot for sharing this! It is awesome, and works very well.
I fine-tuned a bit the card to provide a link to the BirdNet-Go UI, filter the results (confidence above 70), embed the Wikipedia links and add a nice icon.
Here is the full card snippet in case you are interested:
It is in German, but easy to translate. You would have to replace “IP_OF_YOUR_BIRDNETGO_UI” by the IP of your HA instance or wherever your BirdNET-Go is running.
- type: markdown
title: Vogelbeobachtungen
content: >-
Uhr| Vogelname|Anzahl Heute| Max
[Confidence](http://IP_OF_YOUR_BIRDNETGO_UI:8080/)
:---|:---|:---:|:---:
{%- set t = now() %}
{%- set bird_list = state_attr('sensor.birdnet_go_events','bird_events') |
sort(attribute='time', reverse=true) | map(attribute='name') | unique |
list %}
{%- set bird_objects =
state_attr('sensor.birdnet_go_events','bird_events') |
sort(attribute='time', reverse=true) %}
{%- for thisbird in bird_list or [] %}
{%- set ubird = ((bird_objects | selectattr("name", "equalto", thisbird))
| list)[0] %}
{%- set ubird_count = ((bird_objects | selectattr("name", "equalto",
thisbird)) | list) | length %}
{%- set ubird_max_confidence = ((bird_objects | selectattr("name",
"equalto", thisbird)) | map(attribute='confidence') | map('replace', '%',
'') | map('float') | max | round(0)) %}
{%- if ubird_max_confidence > 70 %}
{{ubird.time}}
| [{{ubird.name}}](https://de.wikipedia.org/wiki/{{ubird.name |
replace(' ', '_')}}) | {{ubird_count}} | {{ ubird_max_confidence }} %
{%- endif %}
{%- endfor %}
card_mod:
style:
$: |
.card-header {
display: flex !important;
align-items: center;
}
.card-header:before {
content: url("data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyMDYuODcgMTE2LjY2Ij48ZGVmcz48c3R5bGU+LmNscy0xe2ZpbGw6I2Y0ZTUwNTt9LmNscy0ye2ZpbGw6I2UzMWUyNjt9LmNscy0ze2ZpbGw6I2ZmZjt9PC9zdHlsZT48L2RlZnM+PHBhdGggZD0iTTIwNi4zNywxNi42OHMtMTYuNDQtNC4zNC0yMi43Ni00LjljMCwwLTI1LDEzLjUtMzIsMThhMTkuMTYsMTkuMTYsMCwwLDAtOC42NywxMy44OWwzNS43MS0yNi4zMmgyOEMyMDcuMzEsMTcuMzksMjA2LjM3LDE2LjY4LDIwNi4zNywxNi42OFoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgMC42MykiLz48cGF0aCBkPSJNMTQ4LjU1LDI3LjMzYzcuMzItNC45LDMyLjYyLTE4LjczLDMyLjYyLTE4LjczbDAsMEEzMC42OSwzMC42OSwwLDAsMCwxNTktLjYzYTQ0LjIzLDQ0LjIzLDAsMCwwLTIwLjcxLDVIMGMwLDMuNzEsNS42LDYuNTYsMTIuMTQsNi41Nkg1Mi4zNkw4Ni42MiwzNS4xMlY3MS4zN2MwLDE1LjczLDguMjYsMjkuNDQsMjEuNzgsMzcuMzVTMTI4LjY4LDExNiwxMzguNjMsMTE2VjQ2Ljg3QzEzOC42Myw0MC43OCwxNDAuNDcsMzIuNzMsMTQ4LjU1LDI3LjMzWk0xNjcuODcsOGEyLjUxLDIuNTEsMCwxLDEtMi41MSwyLjUxQTIuNTEsMi41MSwwLDAsMSwxNjcuODcsOFptLTI5LjEzLDEzLDE1LjY5LTguNjgsNi44OS41N0wxMzguNzQsMjUuMzZaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDAuNjMpIi8+PHBhdGggY2xhc3M9ImNscy0xIiBkPSJNNTIuMzYsMTAuOTFIMTEwYy0xMi44OSwwLTIzLjQsMTAuMzUtMjMuNCwyNC4yMVoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgMC42MykiLz48cGF0aCBjbGFzcz0iY2xzLTIiIGQ9Ik0xNzgsMTAuMzNBMzEuNzEsMzEuNzEsMCwwLDAsMTU3Ljc4LDIuOVYtLjYxbDEuMjUsMEEzMC42MywzMC42MywwLDAsMSwxODEuMTcsOC42WiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAwLjYzKSIvPjxwYXRoIGNsYXNzPSJjbHMtMiIgZD0iTTE3OC42MywxNy4zOWwtMjUsMTguNDNzLS4yOS0yLjcsMy40Ny01Ljc0LDI2LjUtMTguMywyNi41LTE4LjNaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDAuNjMpIi8+PHBhdGggY2xhc3M9ImNscy0zIiBkPSJNMTI4LjE0LDY0LjQ3VjUyLjE1YzAtNS4xOC0yLjExLTguNzctNi45My0xMi4xOEwxMDAuNzksMjUuNTRhMTQuMzIsMTQuMzIsMCwwLDAsMiwyMVoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgMC42MykiLz48cGF0aCBjbGFzcz0iY2xzLTMiIGQ9Ik0xMjguMTQsNjQuNDdWNTIuMTVjMC01LjE4LTIuMTEtOC43Ny02LjkzLTEyLjE4TDEwMC43OSwyNS41NGExNC4zMiwxNC4zMiwwLDAsMCwyLDIxWiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAwLjYzKSIvPjxwYXRoIGNsYXNzPSJjbHMtMyIgZD0iTTE1MS41OSwyOS44MmM3LTQuNTQsMzItMTgsMzItMThhMTYuMjQsMTYuMjQsMCwwLDAtMi40MS0zLjE1bDAsMHMtMjUuMywxMy44My0zMi42MiwxOC43My05LjU3LDEyLjE3LTkuODcsMThsLS4wNSwxLjUxLDQuMjktMy4xNkExOS4xNiwxOS4xNiwwLDAsMSwxNTEuNTksMjkuODJaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDAuNjMpIi8+PHBhdGggY2xhc3M9ImNscy0zIiBkPSJNMTY3Ljg3LDhhMi41MSwyLjUxLDAsMSwxLTIuNTEsMi41MUEyLjUxLDIuNTEsMCwwLDEsMTY3Ljg3LDhaIiB0cmFuc2Zvcm09InRyYW5zbGF0ZSgwIDAuNjMpIi8+PHBvbHlnb24gY2xhc3M9ImNscy0zIiBwb2ludHM9IjEzOC43NCAyMS41NyAxNTQuNDMgMTIuODkgMTYxLjMyIDEzLjQ1IDEzOC43NCAyNS45OCAxMzguNzQgMjEuNTciLz48L3N2Zz4=");
height: 20px;
width: 60px;
margin-top: -10px;
padding-left: 8px;
padding-right: 18px;
}
Great topic! I’ve added MQTT to the birdnet-pi addon too with the same MQTT handle so that those cards can mostly be used as such
Given it publishes the SpeciesCode you could also use : https://ebird.org/species/{{SpeciesCode}}
or https://ebird.org/species/{{SpeciesCode}}?siteLanguage={{language}}
where language can be whatever you want to have it in your own language
Just got Birdnet-go setup (using the add-on). Would there be an easy way to also pull the thumbnail/picture of each identified bird into the card?
At the moment the solution is to open a BirdWeather account to connect your BirdNet to and then use this: Bird detector sensors and dashboard
Tangentially related, I’d like to setup two additional template sensors: The total number of detections and the total number of species identified (both above a defined confidence level and for each day, same as the markup card and main template sensor). Has anyone done this or care to show me how? Interacting with lists of data in the attributes is just a touch beyond my native abilities. Thanks in advance!
Combining a bunch of the suggestions here including @alexbelgium 's ebird links and @brooksben11 's request for totals
In my HA config file I set up the triggered template sensor (note the speciesCode
field I added that the previous examples didn’t include):
template:
- trigger:
- platform: mqtt
topic: "birdnet"
- platform: time
at: "00:00:00"
id: reset
sensor:
- unique_id: c893533c-3c06-4ebe-a5bb-da833da0a947
name: BirdNET-Go Events
state: "{{ today_at(trigger.payload_json.Time) }}"
attributes:
bird_events: >
{% if trigger.id == 'reset' %}
{{ [] }}
{% else %}
{% set time = trigger.payload_json.Time %}
{% set name = trigger.payload_json.CommonName %}
{% set speciesCode = trigger.payload_json.SpeciesCode %}
{% set confidence = trigger.payload_json.Confidence|round(2) * 100 ~ '%' %}
{% set current = this.attributes.get('bird_events', []) %}
{% set new = dict(time=time, name=name, speciesCode=speciesCode, confidence=confidence) %}
{{ current + [new] }}
{% endif %}
I then addeed a card to my dashboard with this yaml:
type: markdown
content: >-
Time| Common Name|Day Count| Max Confidence
:---|:---|:---:|:---:
{%- set t = now() %}
{%- set bird_list = state_attr('sensor.birdnet_go_events','bird_events') |
sort(attribute='time', reverse=true) | map(attribute='name') | unique | list
%}
{%- set bird_objects = state_attr('sensor.birdnet_go_events','bird_events') |
sort(attribute='time', reverse=true) %}
{%- for thisbird in bird_list or [] %}
{%- set ubird = ((bird_objects | selectattr("name", "equalto", thisbird)) |
list)[0] %}
{%- set ubird_count = ((bird_objects | selectattr("name", "equalto",
thisbird)) | list) | length %}
{%- set ubird_max_confidence = ((bird_objects | selectattr("name", "equalto",
thisbird)) | map(attribute='confidence') | max) %}
{{ubird.time}} |
[{{ubird.name}}](https://ebird.org/species/{{ubird.speciesCode}}) |
{{ubird_count}} | {{ubird_max_confidence }}
{%- endfor %}
Total Detections: {{bird_objects | count}}
Total Species Detected: {{bird_list | count}}
title: Birds Seen Today
Which gives me a card that looks like this:
As an aside, my setup runs the mic outside just dumping to RTSP so since I already had the RTSP set up I included that on my dashboard as well (with a live spectrogram )