From fdc717703aa83853ae870411bd302065f1c444bf Mon Sep 17 00:00:00 2001 From: Alexandre Date: Wed, 14 Aug 2024 08:54:06 +0200 Subject: [PATCH 01/14] mqtt_hook branch --- birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh | 27 ++++++---- birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py | 55 +++++--------------- birdnet-pi/rootfs/helpers/birdnet_to_mqtt.sh | 5 -- 3 files changed, 29 insertions(+), 58 deletions(-) delete mode 100755 birdnet-pi/rootfs/helpers/birdnet_to_mqtt.sh diff --git a/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh b/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh index 8f6f41342..4a8cffb0b 100755 --- a/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh +++ b/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh @@ -2,6 +2,17 @@ # shellcheck shell=bash set -e +common_steps () { + + # Copy script + cp /helpers/birdnet_to_mqtt.py "$HOME"/BirdNET-Pi/scripts/birdnet_to_mqtt.py + chmod +x "$HOME"/BirdNET-Pi/scripts/birdnet_to_mqtt.py + + # Add hook + sed -i "/import sendAppriseNotifications/a from .birdnet_to_mqtt import automatic_mqtt_publish" "$HOME"/BirdNET-Pi/scripts/utils/reporting.py + +} + if bashio::services.available 'mqtt' && ! bashio::config.true 'MQTT_DISABLED' ; then bashio::log.green "---" bashio::log.blue "MQTT addon is active on your system! Birdnet-pi is now automatically configured to send its ouptut to MQTT" @@ -19,11 +30,9 @@ if bashio::services.available 'mqtt' && ! bashio::config.true 'MQTT_DISABLED' ; sed -i "s|%%mqtt_user%%|$(bashio::services "mqtt" "username")|g" /helpers/birdnet_to_mqtt.py sed -i "s|%%mqtt_pass%%|$(bashio::services "mqtt" "password")|g" /helpers/birdnet_to_mqtt.py - # Copy script - cp /helpers/birdnet_to_mqtt.py /usr/bin/birdnet_to_mqtt.py - cp /helpers/birdnet_to_mqtt.sh /custom-services.d - chmod 777 /usr/bin/birdnet_to_mqtt.py - chmod 777 /custom-services.d/birdnet_to_mqtt.sh + # Common steps + common_steps + elif bashio::config.has_value "MQTT_HOST_manual" && bashio::config.has_value "MQTT_PORT_manual"; then bashio::log.green "---" bashio::log.blue "MQTT is manually configured in the addon options" @@ -39,9 +48,7 @@ elif bashio::config.has_value "MQTT_HOST_manual" && bashio::config.has_value "MQ sed -i "s|%%mqtt_user%%|$(bashio::config "MQTT_USER_manual")|g" /helpers/birdnet_to_mqtt.py sed -i "s|%%mqtt_pass%%|$(bashio::config "MQTT_PASSWORD_manual")|g" /helpers/birdnet_to_mqtt.py - # Copy script - cp /helpers/birdnet_to_mqtt.py /usr/bin/birdnet_to_mqtt.py - cp /helpers/birdnet_to_mqtt.sh /custom-services.d - chmod +x /usr/bin/birdnet_to_mqtt.py - chmod +x /custom-services.d/birdnet_to_mqtt.sh + # Common steps + common_steps + fi diff --git a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py index a57c9ad21..cbeb36392 100644 --- a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py +++ b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py @@ -4,9 +4,6 @@ # Adapted from : https://gist.github.com/deepcoder/c309087c456fc733435b47d83f4113ff # Adapted from : https://gist.github.com/JuanMeeske/08b839246a62ff38778f701fc1da5554 # -# monitor the records in the syslog file for info from the birdnet system on birds that it detects -# publish this data to mqtt -# import time import re @@ -26,19 +23,6 @@ flickr_images = {} conf = get_settings() settings_dict = dict(conf) -# Setup basic configuration for logging -logging.basicConfig(level=logging.INFO) - -# this generator function monitors the requested file handle for new lines added at its end -# the newly added line is returned by the function -def file_row_generator(s): - while True : - line = s.readline() - if not line: - time.sleep(0.1) - continue - yield line - # mqtt server mqtt_server = "%%mqtt_server%%" # server for mqtt mqtt_user = "%%mqtt_user%%" # Replace with your MQTT username @@ -51,11 +35,6 @@ mqtt_topic_confident_birds = 'birdnet' # url base for website that will be used to look up info about bird bird_lookup_url_base = 'http://en.wikipedia.org/wiki/' -# regular expression patters used to decode the records from birdnet -re_high_clean = re.compile(r'(?<=^\[birdnet_analysis\]\[INFO\] ).*?(?=\.mp3$)') - -syslog = open('/proc/1/fd/1', 'r') - def on_connect(client, userdata, flags, rc, properties=None): """ Callback for when the client receives a CONNACK response from the server. """ if rc == 0: @@ -91,16 +70,11 @@ mqttc.connect(mqtt_server, mqtt_port) # Connect to (broker, port, keepalive-tim mqttc.on_connect = on_connect mqttc.loop_start() -# call the generator function and process each line that is returned -for row in file_row_generator(syslog): - # bird found above confidence level found, process it - if re_high_clean.search(row) : - # this slacker regular expression work, extracts the data about the bird found from the log line - # I do the parse in two passes, because I did not know the re to do it in one! - - raw_high_bird = re.search(re_high_clean, row) - raw_high_bird = raw_high_bird.group(0) +# Call function +def automatic_mqtt_publish(species, confidence, confidencepct, path, + date, time, week, latitude, longitude, cutoff, + sens, overlap, settings_dict, db_path=DB_PATH): # the fields we want are separated by semicolons, so split high_bird_fields = raw_high_bird.split(';') @@ -108,22 +82,17 @@ for row in file_row_generator(syslog): # build a structure in python that will be converted to json bird = {} - # human time in this record is in two fields, date and time. They are human format - # combine them together separated by a space and they turn the human data into a python - # timestamp - raw_ts = high_bird_fields[0] + ' ' + high_bird_fields[1] - #bird['ts'] = str(datetime.datetime.timestamp(dateparser.parse(raw_ts))) - bird['Date'] = high_bird_fields[0] - bird['Time'] = high_bird_fields[1] - bird['ScientificName'] = high_bird_fields[2] - bird['CommonName'] = high_bird_fields[3] - bird['Confidence'] = high_bird_fields[4] - bird['SpeciesCode'] = get_bird_code(high_bird_fields[2]) - bird['ClipName'] = high_bird_fields[11] + bird['Date'] = date + bird['Time'] = time + bird['ScientificName'] = sciName + bird['CommonName'] = comName + bird['Confidence'] = confidence + bird['SpeciesCode'] = get_bird_code(sciName) + bird['ClipName'] = path # build a url from scientific name of bird that can be used to lookup info about bird - bird['url'] = bird_lookup_url_base + high_bird_fields[2].replace(' ', '_') + bird['url'] = bird_lookup_url_base + sciName.replace(' ', '_') # Flickimage image_url = "" diff --git a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.sh b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.sh deleted file mode 100755 index 54045d508..000000000 --- a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/with-contenv bashio -# shellcheck shell=bash - -echo "Starting service: mqtt automated publish" -"$PYTHON_VIRTUAL_ENV" /usr/bin/birdnet_to_mqtt.py &>/proc/1/fd/1 From 9f60703f748f21d208bd44f1745d6497559e76c9 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:00:51 +0200 Subject: [PATCH 02/14] Add hooks --- birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh b/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh index 4a8cffb0b..ad6616604 100755 --- a/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh +++ b/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh @@ -5,11 +5,12 @@ set -e common_steps () { # Copy script - cp /helpers/birdnet_to_mqtt.py "$HOME"/BirdNET-Pi/scripts/birdnet_to_mqtt.py - chmod +x "$HOME"/BirdNET-Pi/scripts/birdnet_to_mqtt.py + cp /helpers/birdnet_to_mqtt.py "$HOME"/BirdNET-Pi/scripts/utils/birdnet_to_mqtt.py + chmod +x "$HOME"/BirdNET-Pi/scripts/utils/birdnet_to_mqtt.py - # Add hook - sed -i "/import sendAppriseNotifications/a from .birdnet_to_mqtt import automatic_mqtt_publish" "$HOME"/BirdNET-Pi/scripts/utils/reporting.py + # Add hooks + sed -i "/load_global_model, run_analysis/a from utils.birdnet_to_mqtt import automatic_mqtt_publish" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py + sed -i "/heartbeat\(/a\ automatic_mqtt_publish(file, detections)" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py } From 975c828d5e4f1b940540b6a97895cbe7d740539c Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:11:13 +0200 Subject: [PATCH 03/14] Correct code --- birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py | 122 ++++++++----------- 1 file changed, 51 insertions(+), 71 deletions(-) diff --git a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py index cbeb36392..fc9d5cda1 100644 --- a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py +++ b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py @@ -1,9 +1,5 @@ #! /usr/bin/env python3 # birdnet_to_mqtt.py -# -# Adapted from : https://gist.github.com/deepcoder/c309087c456fc733435b47d83f4113ff -# Adapted from : https://gist.github.com/JuanMeeske/08b839246a62ff38778f701fc1da5554 -# import time import re @@ -15,6 +11,8 @@ import paho.mqtt.client as mqtt import subprocess import requests import sys +import os + sys.path.append('/home/pi/BirdNET-Pi/scripts/utils') from helpers import get_settings @@ -23,16 +21,13 @@ flickr_images = {} conf = get_settings() settings_dict = dict(conf) -# mqtt server -mqtt_server = "%%mqtt_server%%" # server for mqtt -mqtt_user = "%%mqtt_user%%" # Replace with your MQTT username -mqtt_pass = "%%mqtt_pass%%" # Replace with your MQTT password -mqtt_port = %%mqtt_port%% # port for mqtt +# MQTT server configuration +mqtt_server = "%%mqtt_server%%" +mqtt_user = "%%mqtt_user%%" +mqtt_pass = "%%mqtt_pass%%" +mqtt_port = %%mqtt_port%% -# mqtt topic for bird heard above threshold will be published mqtt_topic_confident_birds = 'birdnet' - -# url base for website that will be used to look up info about bird bird_lookup_url_base = 'http://en.wikipedia.org/wiki/' def on_connect(client, userdata, flags, rc, properties=None): @@ -46,80 +41,65 @@ def get_bird_code(scientific_name): with open('/home/pi/BirdNET-Pi/scripts/ebird.php', 'r') as file: data = file.read() - # Extract the array from the PHP file array_str = re.search(r'\$ebirds = \[(.*?)\];', data, re.DOTALL).group(1) - # Convert the PHP array to a Python dictionary 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 the corresponding value for the given bird's scientific name return bird_dict.get(scientific_name) -# this little hack is to make each received record for the all birds section unique -# the date and time that the log returns is only down to the 1 second accuracy, do -# you can get multiple records with same date and time, this will make Home Assistant not -# think there is a new reading so we add a incrementing tenth of second to each record received ts_noise = 0.0 -#try : -# connect to MQTT server -mqttc = mqtt.Client('birdnet_mqtt') # Create instance of client with client ID -mqttc.username_pw_set(mqtt_user, mqtt_pass) # Use credentials -mqttc.connect(mqtt_server, mqtt_port) # Connect to (broker, port, keepalive-time) +mqttc = mqtt.Client('birdnet_mqtt') +mqttc.username_pw_set(mqtt_user, mqtt_pass) mqttc.on_connect = on_connect -mqttc.loop_start() +try: + mqttc.connect(mqtt_server, mqtt_port) + mqttc.loop_start() -# Call function -def automatic_mqtt_publish(species, confidence, confidencepct, path, - date, time, week, latitude, longitude, cutoff, - sens, overlap, settings_dict, db_path=DB_PATH): + def automatic_mqtt_publish(file, detections): + for detection in detections: + 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'] = os.path.basename(detection.file_name_ext) + bird['url'] = bird_lookup_url_base + detection.scientific_name - # the fields we want are separated by semicolons, so split - high_bird_fields = raw_high_bird.split(';') + 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) - # build a structure in python that will be converted to json - bird = {} + resp.encoding = "utf-8" + data = resp.json()["photos"]["photo"][0] - #bird['ts'] = str(datetime.datetime.timestamp(dateparser.parse(raw_ts))) - bird['Date'] = date - bird['Time'] = time - bird['ScientificName'] = sciName - bird['CommonName'] = comName - bird['Confidence'] = confidence - bird['SpeciesCode'] = get_bird_code(sciName) - bird['ClipName'] = path + 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: + logging.error("FLICKR API ERROR: " + str(e)) + image_url = "" + else: + image_url = flickr_images[common_name] + bird['Flickrimage'] = image_url - # build a url from scientific name of bird that can be used to lookup info about bird - bird['url'] = bird_lookup_url_base + sciName.replace(' ', '_') + json_bird = json.dumps(bird) + mqttc.publish(mqtt_topic_confident_birds, json_bird, 1) + logging.info('Posted to MQTT: ok') - # Flickimage - image_url = "" - common_name = high_bird_fields[3] - 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) +except Exception as e: + logging.error(f"An error occurred: {e}") - 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[comName] = image_url - except Exception as e: - print("FLICKR API ERROR: "+str(e)) - image_url = "" - else: - image_url = flickr_images[comName] - bird['Flickrimage'] = image_url - - # convert to json string we can sent to mqtt - json_bird = json.dumps(bird) - - print('Posted to MQTT : ok') - - mqttc.publish(mqtt_topic_confident_birds, json_bird, 1) +finally: + mqttc.loop_stop() + mqttc.disconnect() From c82d8f3e8edd15b15257ca356b8fab4d96e092c5 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:25:24 +0200 Subject: [PATCH 04/14] New logic --- birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py | 92 ++++++++++---------- 1 file changed, 47 insertions(+), 45 deletions(-) diff --git a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py index fc9d5cda1..b1d600328 100644 --- a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py +++ b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py @@ -3,12 +3,10 @@ import time import re -import dateparser import datetime import json import logging import paho.mqtt.client as mqtt -import subprocess import requests import sys import os @@ -16,6 +14,9 @@ import os sys.path.append('/home/pi/BirdNET-Pi/scripts/utils') from helpers import get_settings +# Setup logging +log = logging.getLogger(__name__) + # Used in flickrimage flickr_images = {} conf = get_settings() @@ -25,7 +26,7 @@ settings_dict = dict(conf) mqtt_server = "%%mqtt_server%%" mqtt_user = "%%mqtt_user%%" mqtt_pass = "%%mqtt_pass%%" -mqtt_port = %%mqtt_port%% +mqtt_port = "%%mqtt_port%%" mqtt_topic_confident_birds = 'birdnet' bird_lookup_url_base = 'http://en.wikipedia.org/wiki/' @@ -33,9 +34,9 @@ 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: - logging.info("Connected to MQTT Broker!") + log.info("Connected to MQTT Broker!") else: - logging.error(f"Failed to connect, return code {rc}\n") + 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: @@ -48,7 +49,44 @@ def get_bird_code(scientific_name): return bird_dict.get(scientific_name) -ts_noise = 0.0 +def automatic_mqtt_publish(file, detections): + for detection in detections: + 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'] = os.path.basename(detection.file_name_ext) + bird['url'] = bird_lookup_url_base + detection.scientific_name + + 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: + log.error("FLICKR API ERROR: " + str(e)) + image_url = "" + else: + image_url = flickr_images[common_name] + bird['Flickrimage'] = image_url + + json_bird = json.dumps(bird) + mqttc.publish(mqtt_topic_confident_birds, json_bird, 1) + log.info("Posted to MQTT: ok") mqttc = mqtt.Client('birdnet_mqtt') mqttc.username_pw_set(mqtt_user, mqtt_pass) @@ -58,47 +96,11 @@ try: mqttc.connect(mqtt_server, mqtt_port) mqttc.loop_start() - def automatic_mqtt_publish(file, detections): - for detection in detections: - 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'] = os.path.basename(detection.file_name_ext) - bird['url'] = bird_lookup_url_base + detection.scientific_name - - 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: - logging.error("FLICKR API ERROR: " + str(e)) - image_url = "" - else: - image_url = flickr_images[common_name] - bird['Flickrimage'] = image_url - - json_bird = json.dumps(bird) - mqttc.publish(mqtt_topic_confident_birds, json_bird, 1) - logging.info('Posted to MQTT: ok') + # Assuming `file` and `detections` are provided from somewhere + # automatic_mqtt_publish(file, detections) except Exception as e: - logging.error(f"An error occurred: {e}") + log.error("Cannot post mqtt: %s", e) finally: mqttc.loop_stop() From 0bdeb830fb7a67f3e2ee0505e2aefd595eaac0ac Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:35:50 +0200 Subject: [PATCH 05/14] Readability --- birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py index b1d600328..e2ae45493 100644 --- a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py +++ b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py @@ -27,8 +27,8 @@ mqtt_server = "%%mqtt_server%%" mqtt_user = "%%mqtt_user%%" mqtt_pass = "%%mqtt_pass%%" mqtt_port = "%%mqtt_port%%" +mqtt_topic = 'birdnet' -mqtt_topic_confident_birds = 'birdnet' bird_lookup_url_base = 'http://en.wikipedia.org/wiki/' def on_connect(client, userdata, flags, rc, properties=None): @@ -85,7 +85,7 @@ def automatic_mqtt_publish(file, detections): bird['Flickrimage'] = image_url json_bird = json.dumps(bird) - mqttc.publish(mqtt_topic_confident_birds, json_bird, 1) + mqttc.publish(mqtt_topic, json_bird, 1) log.info("Posted to MQTT: ok") mqttc = mqtt.Client('birdnet_mqtt') From ba39f95f711cbc5d3042d1f0ff2a76703fa8a646 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:37:03 +0200 Subject: [PATCH 06/14] Update 33-mqtt.sh --- birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh b/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh index ad6616604..ad1b9bc33 100755 --- a/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh +++ b/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh @@ -6,6 +6,7 @@ common_steps () { # Copy script cp /helpers/birdnet_to_mqtt.py "$HOME"/BirdNET-Pi/scripts/utils/birdnet_to_mqtt.py + chown pi:pi "$HOME"/BirdNET-Pi/scripts/utils/birdnet_to_mqtt.py chmod +x "$HOME"/BirdNET-Pi/scripts/utils/birdnet_to_mqtt.py # Add hooks From fea5e2882b7fe60f6265fb2cdb82df0c17e6c000 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:40:28 +0200 Subject: [PATCH 07/14] Update birdnet_to_mqtt.py --- birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py index e2ae45493..fdbf32b19 100644 --- a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py +++ b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py @@ -14,7 +14,8 @@ import os sys.path.append('/home/pi/BirdNET-Pi/scripts/utils') from helpers import get_settings -# Setup logging +# Setup basic configuration for logging +logging.basicConfig(level=logging.INFO) log = logging.getLogger(__name__) # Used in flickrimage From d168737a43d89712456a4603442381aac6cdf00b Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:58:05 +0200 Subject: [PATCH 08/14] Update 33-mqtt.sh --- birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh b/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh index ad1b9bc33..ba016fa4c 100755 --- a/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh +++ b/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh @@ -11,7 +11,7 @@ common_steps () { # Add hooks sed -i "/load_global_model, run_analysis/a from utils.birdnet_to_mqtt import automatic_mqtt_publish" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/heartbeat\(/a\ automatic_mqtt_publish(file, detections)" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py + sed -i "/heartbeat\(/a\ automatic_mqtt_publish(file, detections, detection.file_name_extr)" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py } From ecd48d457179d305b8afa0768cdfd9601f4a1143 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 14 Aug 2024 11:58:20 +0200 Subject: [PATCH 09/14] Update birdnet_to_mqtt.py --- birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py index fdbf32b19..30068ff5e 100644 --- a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py +++ b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py @@ -59,7 +59,7 @@ def automatic_mqtt_publish(file, detections): bird['CommonName'] = detection.common_name bird['Confidence'] = detection.confidence bird['SpeciesCode'] = get_bird_code(detection.scientific_name) - bird['ClipName'] = os.path.basename(detection.file_name_ext) + bird['ClipName'] = path bird['url'] = bird_lookup_url_base + detection.scientific_name image_url = "" From 884d6b6a7da2535145b12eb892ae8b28eaee0259 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 14 Aug 2024 12:00:27 +0200 Subject: [PATCH 10/14] Update 33-mqtt.sh --- birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh b/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh index ba016fa4c..17d449dbe 100755 --- a/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh +++ b/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh @@ -11,7 +11,7 @@ common_steps () { # Add hooks sed -i "/load_global_model, run_analysis/a from utils.birdnet_to_mqtt import automatic_mqtt_publish" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/heartbeat\(/a\ automatic_mqtt_publish(file, detections, detection.file_name_extr)" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py + sed -i "/write_to_db\(/a\ automatic_mqtt_publish(file, detections, detection.file_name_extr)" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py } From 56f1d288c6feb105d069c758a42806ba44c8b0eb Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 14 Aug 2024 12:02:55 +0200 Subject: [PATCH 11/14] Update 33-mqtt.sh --- birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh b/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh index 17d449dbe..af7f799ab 100755 --- a/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh +++ b/birdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh @@ -11,7 +11,7 @@ common_steps () { # Add hooks sed -i "/load_global_model, run_analysis/a from utils.birdnet_to_mqtt import automatic_mqtt_publish" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/write_to_db\(/a\ automatic_mqtt_publish(file, detections, detection.file_name_extr)" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py + 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 } From 8549b0f31aea615494315bfa6cefad63bebfe323 Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 14 Aug 2024 12:05:01 +0200 Subject: [PATCH 12/14] Correct FlickrImage --- birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py index 30068ff5e..344254915 100644 --- a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py +++ b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py @@ -62,14 +62,14 @@ def automatic_mqtt_publish(file, detections): bird['ClipName'] = path bird['url'] = bird_lookup_url_base + detection.scientific_name + # Flickimage image_url = "" - common_name = detection.common_name - if len(settings_dict.get('FLICKR_API_KEY', '')) > 0: + common_name = high_bird_fields[3] + 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')) + + 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) @@ -77,12 +77,12 @@ def automatic_mqtt_publish(file, detections): 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 + flickr_images[comName] = image_url except Exception as e: - log.error("FLICKR API ERROR: " + str(e)) + print("FLICKR API ERROR: "+str(e)) image_url = "" else: - image_url = flickr_images[common_name] + image_url = flickr_images[comName] bird['Flickrimage'] = image_url json_bird = json.dumps(bird) From b2b3160f9194b6061c5121d317a937d621ebed8b Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 14 Aug 2024 12:05:58 +0200 Subject: [PATCH 13/14] Update birdnet_to_mqtt.py --- birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py index 344254915..d9b8dab52 100644 --- a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py +++ b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py @@ -50,7 +50,7 @@ def get_bird_code(scientific_name): return bird_dict.get(scientific_name) -def automatic_mqtt_publish(file, detections): +def automatic_mqtt_publish(file, detections, path): for detection in detections: bird = {} bird['Date'] = file.date From fba631009a2a3768bc8745bcce4dc37a94d910cf Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 14 Aug 2024 12:08:00 +0200 Subject: [PATCH 14/14] Update birdnet_to_mqtt.py --- birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py index d9b8dab52..da4aeb25e 100644 --- a/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py +++ b/birdnet-pi/rootfs/helpers/birdnet_to_mqtt.py @@ -64,7 +64,7 @@ def automatic_mqtt_publish(file, detections, path): # Flickimage image_url = "" - common_name = high_bird_fields[3] + common_name = detection.common_name if len(settings_dict.get('FLICKR_API_KEY')) > 0: if common_name not in flickr_images: try: @@ -77,12 +77,12 @@ def automatic_mqtt_publish(file, detections, path): 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[comName] = image_url + flickr_images[common_name] = image_url except Exception as e: print("FLICKR API ERROR: "+str(e)) image_url = "" else: - image_url = flickr_images[comName] + image_url = flickr_images[common_name] bird['Flickrimage'] = image_url json_bird = json.dumps(bird)