Closed UlrichThiess closed 2 months ago
I'll probably rewrite the logic to hook in the detection py (as for apprise) instead of reading the log
And currently it only works for mp3 not other formats
Rewriting the logic to have a python hook in the https://github.com/Nachtzuster/BirdNETPi/blob/main/scripts/utils/reporting.py (like sendAppriseNotifications) instead of blindly reading the log would be the right way to go but it is more complex than I anticipated.
I probably won't be able to look at it in the next 2 weeks
I've created a branch here to modify the code : https://github.com/alexbelgium/hassio-addons/tree/mqtt_hook
New logic in the PR :
I've tried merging to test
small improvements:
change print
to logging.info
change syslog = open('/proc/1/fd/1', 'r')
to syslog = open('/proc/1/fd/1', 'r', buffering=1)
change
def file_row_generator(s):
...
to
def file_row_generator(s):
for line in iter(s.readline, ''):
yield line
as i see all new detections will be published could say more tommorrow
hm - not perfect but better - i work on it
I've tried pushing a new logic with a hook in birdnet_analysis instead of reading the log. Not sure if it fully works though
should i reinstall the AddOn?
Nono it is just in the incremental updates (v81 is building now)
Installed v81.
LOG: ERROR:utils.birdnet_to_mqtt:Cannot post mqtt: '<=' not supported between instances of 'str' and 'int'
sed: -e expression #1, char 15: Unmatched ( or \(
Error : /etc/cont-init.d/33-mqtt.sh exiting 1
change in 33-mqtt.sh
sed -i "/write_to_db\(/a\ automatic_mqtt_publish\(file, detections, os.path.basename\(detection.file_name_extr\)\)" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py
into (escaping of ( is not necassary)
sed -i "/write_to_db(/a\ \ \ \ \ \ \ \ automatic_mqtt_publish(file, detections, os.path.basename(detection.file_name_extr))" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py
thanks for the corrections
log:
INFO:birdnet_analysis:2024-08-15;09:03:51;Passer domesticus;Haussperling;0.828;47.9379;7.6354;0.7;33;1.25;0.0;Haussperling-83-2024-08-15-birdnet-RTSP_1-09:03:51.mp3
[birdnet_analysis][INFO] 2024-08-15;09:03:51;Passer domesticus;Haussperling;0.828;47.9379;7.6354;0.7;33;1.25;0.0;Haussperling-83-2024-08-15-birdnet-RTSP_1-09:03:51.mp3
INFO:utils.birdnet_to_mqtt:Posted to MQTT: ok
[utils.birdnet_to_mqtt][INFO] Posted to MQTT: ok
but nothing is posted
changes in birdnet_to_mqtt.py
won't be recognized immediately, which service or process could i restart/kill?
You need to do systemctl restart birdnet_analysis
to do it manually but it is automatically restarted at boot. Mmh it seems it's due to the ClipName which doesn't work yet. Perhaps I'll remove it for the moment
can't update the addon : "manifest error"
Die Aktion update/install konnte nicht ausgeführt werden. Error updating BirdNET-pi: Can't install ghcr.io/alexbelgium/birdnet-pi-amd64:0.13-83: 500 Server Error for http+docker://localhost/v1.45/images/create?tag=0.13-83&fromImage=ghcr.io%2Falexbelgium%2Fbirdnet-pi-amd64&platform=linux%2Famd64: Internal Server Error ("manifest unknown")
got it (i deleted all my old messages)
33-mqtt.sh line 14 should be
sed -i '/write_to_db(/a\ automatic_mqtt_publish(file, detection)' "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py
birdnet_to_mqtt.py
#! /usr/bin/env python3
# birdnet_to_mqtt.py
import time
import re
import datetime
import json
import logging
import paho.mqtt.client as mqtt
import requests
import sys
import os
sys.path.append('/home/pi/BirdNET-Pi/scripts/utils')
from helpers import get_settings
# Setup basic configuration for logging
logging.basicConfig(level=logging.INFO)
log = logging.getLogger(__name__)
# Used in flickrimage
flickr_images = {}
conf = get_settings()
settings_dict = dict(conf)
# MQTT server configuration
mqtt_server = "%%mqtt_server%%"
mqtt_user = "%%mqtt_user%%"
mqtt_pass = "%%mqtt_pass%%"
mqtt_port = %%mqtt_port%%
mqtt_topic = 'birdnet'
bird_lookup_url_base = 'http://en.wikipedia.org/wiki/'
def on_connect(client, userdata, flags, rc ): #, properties=None):
""" Callback for when the client receives a CONNACK response from the server. """
if rc == 0:
log.info("Connected to MQTT Broker!")
else:
log.error(f"Failed to connect, return code {rc}\n")
def get_bird_code(scientific_name):
with open('/home/pi/BirdNET-Pi/scripts/ebird.php', 'r') as file:
data = file.read()
array_str = re.search(r'\$ebirds = \[(.*?)\];', data, re.DOTALL).group(1)
bird_dict = {re.search(r'"(.*?)"', line).group(1): re.search(r'=> "(.*?)"', line).group(1)
for line in array_str.split('\n') if '=>' in line}
return bird_dict.get(scientific_name)
def automatic_mqtt_publish(file, detection, path):
bird = {}
bird['Date'] = file.date
bird['Time'] = file.time
bird['ScientificName'] = detection.scientific_name.replace('_', ' ')
bird['CommonName'] = detection.common_name
bird['Confidence'] = detection.confidence
bird['SpeciesCode'] = get_bird_code(detection.scientific_name)
bird['ClipName'] = path
bird['url'] = bird_lookup_url_base + detection.scientific_name.replace(' ', '_')
# Flickimage
image_url = ""
common_name = detection.common_name
if len(settings_dict.get('FLICKR_API_KEY')) > 0:
if common_name not in flickr_images:
try:
headers = {'User-Agent': 'Python_Flickr/1.0'}
url = ('https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=' + str(settings_dict.get('FLICKR_API_KEY')) +
'&text=' + str(common_name) + ' bird&sort=relevance&per_page=5&media=photos&format=json&license=2%2C3%2C4%2C5%2C6%2C9&nojsoncallback=1')
resp = requests.get(url=url, headers=headers, timeout=10)
resp.encoding = "utf-8"
data = resp.json()["photos"]["photo"][0]
image_url = 'https://farm'+str(data["farm"])+'.static.flickr.com/'+str(data["server"])+'/'+str(data["id"])+'_'+str(data["secret"])+'_n.jpg'
flickr_images[common_name] = image_url
except Exception as e:
print("FLICKR API ERROR: "+str(e))
image_url = ""
else:
image_url = flickr_images[common_name]
bird['FlickrImage'] = image_url
json_bird = json.dumps(bird)
mqttc.reconnect()
mqttc.publish(mqtt_topic, json_bird, 1)
log.info("Posted to MQTT: ok")
mqttc = mqtt.Client('birdnet_mqtt')
mqttc.username_pw_set(mqtt_user, mqtt_pass)
mqttc.on_connect = on_connect
try:
mqttc.connect(mqtt_server, mqtt_port)
mqttc.loop_start()
# Assuming `file` and `detections` are provided from somewhere
# automatic_mqtt_publish(file, detections)
except Exception as e:
log.error("Cannot post mqtt: %s", e)
finally:
mqttc.loop_stop()
mqttc.disconnect()
Thanks so much!!! I'll correct it now
I've pushed a v84, it shows "manifest unknown" until the build is completed and pushed to github through the automatic action. Thanks again for the collaborative effort! Now with this logic it should for sure push every detections to mqtt
I've pushed a v85 to remove path in automatic_mqtt_publish(file, detection, path)
and remove also line 61 in birdnet_to_mqtt.py
bird['ClipName'] = path
does anyone uses the ClipName in Home Assistant?
I would say the ClipName is usually used as unique identifier for detections. Now, do people actually use it... In 2 weeks I'll have more time so I can see how to re-implement it. Thanks very much for all the help on this mqtt code!
to reimplement ClipName:
change 33-mqtt.sh line 14 into
sed -i '/write_to_db(/a\ automatic_mqtt_publish(file, detection,os.path.basename(detection.file_name_extr))' "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py
change birdnet_to_mqtt.py line 52 into
def automatic_mqtt_publish(file, detection, path):
and remove line 53
as i could see: BirdNET has 192 detections and Home Assistant shows 192 detections
perfect
thank you very much it was my pleasure
Description
I have a running BirdNET-Pi AddOn. It uses two mics via rtsp. This works perfectly. BirdNET-Pi counts till now 243 detections with 19 species. In HA i have a table to show the birds from https://community.home-assistant.io/t/displaying-birdnet-go-detections/713611 But in HA i count only 76 detections with 13 species. If i look with MQTT Explorer i could see, that not all detections will be send by mqtt. I enabled eMail: Works for all detections.
Reproduction steps
Addon Logs
Architecture
No response
OS
No response