From 97c29ce36cbd8ed4cd536777cd859c4546cce66e Mon Sep 17 00:00:00 2001 From: Joe Weiss Date: Sat, 18 Jun 2022 13:15:43 -0400 Subject: [PATCH 01/22] Refactor notifications into its own module with tests --- __init__.py | 0 requirements.txt | 4 +- scripts/__init__.py | 0 scripts/notifications.py | 96 +++++++++++++++++++++++++++++ scripts/server.py | 67 ++++---------------- tests/__init__.py | 0 tests/test_apprise_notifications.py | 51 +++++++++++++++ 7 files changed, 162 insertions(+), 56 deletions(-) create mode 100644 __init__.py create mode 100644 scripts/__init__.py create mode 100644 scripts/notifications.py create mode 100644 tests/__init__.py create mode 100644 tests/test_apprise_notifications.py diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/requirements.txt b/requirements.txt index 22f27e2..51443bf 100644 --- a/requirements.txt +++ b/requirements.txt @@ -10,4 +10,6 @@ pandas seaborn streamlit plotly -apprise \ No newline at end of file +apprise +pytest==7.1.2 +pytest-mock==3.7.0 diff --git a/scripts/__init__.py b/scripts/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scripts/notifications.py b/scripts/notifications.py new file mode 100644 index 0000000..8c1ef4a --- /dev/null +++ b/scripts/notifications.py @@ -0,0 +1,96 @@ +import apprise +import os +import socket +import sqlite3 +from sqlite3 import Error +import time +from datetime import datetime, timedelta + +userDir = os.path.expanduser('~') +APPRISE_CONFIG = userDir + '/BirdNET-Pi/apprise.txt' +THIS_RUN_PATH = userDir + '/BirdNET-Pi/scripts/thisrun.txt' +DB_PATH = userDir + '/BirdNET-Pi/scripts/birds.db' + +def notify(body, title): + apobj = apprise.Apprise() + config = apprise.AppriseConfig() + config.add(APPRISE_CONFIG) + apobj.add(config) + apobj.notify( + body=body, + title=title, + ) + +def get_setting(param): + with open(THIS_RUN_PATH, 'r') as f: + this_run = f.readlines() + return str(str(str([i for i in this_run if i.startswith(param)]).split('=')[1]).split('\\')[0]).replace('"', '') + +def sendAppriseNotifications(species, confidence, path, db_path=DB_PATH): + if os.path.exists(APPRISE_CONFIG) and os.path.getsize(APPRISE_CONFIG) > 0: + + title = get_setting('APPRISE_NOTIFICATION_TITLE') + body = get_setting('APPRISE_NOTIFICATION_BODY') + + try: + websiteurl = get_setting('BIRDNETPI_URL') + if len(websiteurl) == 0: + raise ValueError('Blank URL') + except Exception as e: + websiteurl = "http://"+socket.gethostname()+".local" + + listenurl = websiteurl+"?filename="+path + + if get_setting('APPRISE_NOTIFY_EACH_DETECTION') == "1": + apobj = apprise.Apprise() + config = apprise.AppriseConfig() + config.add(APPRISE_CONFIG) + apobj.add(config) + + apobj.notify( + body=body.replace("$sciname", species.split("_")[0]).replace("$comname", species.split("_")[1]).replace("$confidence", confidence).replace("$listenurl", listenurl), + title=title.replace("$sciname", species.split("_")[0]).replace("$comname", species.split("_")[1]).replace("$confidence", confidence).replace("$listenurl", listenurl), + ) + + APPRISE_NOTIFICATION_NEW_SPECIES_DAILY = True + APPRISE_NOTIFICATION_NEW_SPECIES_DAILY_COUNT_LIMIT = 2 # Notifies the first N per day. + if APPRISE_NOTIFICATION_NEW_SPECIES_DAILY: + try: + con = sqlite3.connect(db_path) + cur = con.cursor() + cur.execute("SELECT DISTINCT(Com_Name), count(Com_Name) FROM detections WHERE date > (SELECT DATETIME('now', '-1 day')) GROUP BY Com_Name") + known_species = cur.fetchall() + sciName, comName = species.split("_") + numberDetections = [d[1] for d in known_species if d[0] == comName.replace("'","")][0] + if numberDetections < APPRISE_NOTIFICATION_NEW_SPECIES_DAILY_COUNT_LIMIT: + notify_body=body.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections))+" times today)", + notify_title=title.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections))+" times today)", + notify(notify_body, notify_title) + con.close() + except sqlite3.Error as e: + print(e) + print("Database busy") + time.sleep(2) + + if get_setting('APPRISE_NOTIFY_NEW_SPECIES') == "1": + try: + con = sqlite3.connect(db_path) + cur = con.cursor() + cur.execute("SELECT DISTINCT(Com_Name), count(Com_Name) FROM detections WHERE date > (SELECT DATETIME('now', '-7 day')) GROUP BY Com_Name") + known_species = cur.fetchall() + sciName, comName = species.split("_") + numberDetections = [d[1] for d in known_species if d[0] == comName.replace("'","")][0] + if numberDetections <= 5: + notify_body=body.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections))+" times in last 7d)" + notify_title=title.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections))+" times in last 7d)" + notify(notify_body, notify_title) + con.close() + except sqlite3.Error: + print("Database busy") + time.sleep(2) + + +if __name__ == "__main__": + print("notfications") + + \ No newline at end of file diff --git a/scripts/server.py b/scripts/server.py index 5472e7f..fce5319 100755 --- a/scripts/server.py +++ b/scripts/server.py @@ -13,6 +13,9 @@ import operator import socket import threading import os + +from notifications import sendAppriseNotifications + os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' os.environ['CUDA_VISIBLE_DEVICES'] = '' @@ -228,59 +231,6 @@ def analyzeAudioData(chunks, lat, lon, week, sensitivity, overlap,): return detections -def sendAppriseNotifications(species, confidence, path): - if os.path.exists(userDir + '/BirdNET-Pi/apprise.txt') and os.path.getsize(userDir + '/BirdNET-Pi/apprise.txt') > 0: - with open(userDir + '/BirdNET-Pi/scripts/thisrun.txt', 'r') as f: - this_run = f.readlines() - title = str(str(str([i for i in this_run if i.startswith('APPRISE_NOTIFICATION_TITLE')]).split('=')[1]).split('\\')[0]).replace('"', '') - body = str(str(str([i for i in this_run if i.startswith('APPRISE_NOTIFICATION_BODY')]).split('=')[1]).split('\\')[0]).replace('"', '') - - try: - websiteurl = str(str(str([i for i in this_run if i.startswith('BIRDNETPI_URL')]).split('=')[1]).split('\\')[0]).replace('"', '') - if len(websiteurl) == 0: - raise ValueError('Blank URL') - except Exception as e: - websiteurl = "http://"+socket.gethostname()+".local" - - listenurl = websiteurl+"?filename="+path - - if str(str(str([i for i in this_run if i.startswith('APPRISE_NOTIFY_EACH_DETECTION')]).split('=')[1]).split('\\')[0]) == "1": - - apobj = apprise.Apprise() - config = apprise.AppriseConfig() - config.add(userDir + '/BirdNET-Pi/apprise.txt') - apobj.add(config) - - apobj.notify( - body=body.replace("$sciname", species.split("_")[0]).replace("$comname", species.split("_")[1]).replace("$confidence", confidence).replace("$listenurl", listenurl), - title=title.replace("$sciname", species.split("_")[0]).replace("$comname", species.split("_")[1]).replace("$confidence", confidence).replace("$listenurl", listenurl), - ) - - if str(str(str([i for i in this_run if i.startswith('APPRISE_NOTIFY_NEW_SPECIES')]).split('=')[1]).split('\\')[0]) == "1": - try: - con = sqlite3.connect(userDir + '/BirdNET-Pi/scripts/birds.db') - cur = con.cursor() - cur.execute("SELECT DISTINCT(Com_Name), count(Com_Name) FROM detections WHERE date > (SELECT DATETIME('now', '-7 day')) GROUP BY Com_Name") - known_species = cur.fetchall() - sciName, comName = species.split("_") - numberDetections = [d[1] for d in known_species if d[0] == comName.replace("'","")][0] - - if numberDetections <= 5: - apobj = apprise.Apprise() - config = apprise.AppriseConfig() - config.add(userDir + '/BirdNET-Pi/apprise.txt') - apobj.add(config) - apobj.notify( - body=body.replace("$sciname", species.split("_")[0]).replace("$comname", species.split("_")[1]).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections)+1)+" times in last 7d)", - title=title.replace("$sciname", species.split("_")[0]).replace("$comname", species.split("_")[1]).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections)+1)+" times in last 7d)", - ) - - con.close() - except BaseException: - print("Database busy") - time.sleep(2) - - def writeResultsToFile(detections, min_conf, path): print('WRITING RESULTS TO', path, '...', end=' ') @@ -408,13 +358,16 @@ def handle_client(conn, addr): with open(userDir + '/BirdNET-Pi/BirdDB.txt', 'a') as rfile: for d in detections: + species_apprised_this_run = [] for entry in detections[d]: if entry[1] >= min_conf and ((entry[0] in INCLUDE_LIST or len(INCLUDE_LIST) == 0) and (entry[0] not in EXCLUDE_LIST or len(EXCLUDE_LIST) == 0)): + # Write to text file. rfile.write(str(current_date) + ';' + str(current_time) + ';' + entry[0].replace('_', ';') + ';' + str(entry[1]) + ";" + str(args.lat) + ';' + str(args.lon) + ';' + str(min_conf) + ';' + str(week) + ';' + str(args.sensitivity) + ';' + str(args.overlap) + '\n') + # Write to database Date = str(current_date) Time = str(current_time) species = entry[0] @@ -445,8 +398,12 @@ def handle_client(conn, addr): except BaseException: print("Database busy") time.sleep(2) - - sendAppriseNotifications(str(entry[0]), str(entry[1]), File_Name) + + # Apprise of detection if not already alerted this run. + if not str(entry[0] in species_apprised_this_run: + sendAppriseNotifications(str(entry[0]), str(entry[1]), File_Name) + + species_apprised_this_run.append(str(entry[0]) print(str(current_date) + ';' + diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_apprise_notifications.py b/tests/test_apprise_notifications.py new file mode 100644 index 0000000..deee959 --- /dev/null +++ b/tests/test_apprise_notifications.py @@ -0,0 +1,51 @@ +import os +import sqlite3 +import pytest + +from scripts.notifications import sendAppriseNotifications +from datetime import datetime, timedelta + +def create_test_db(db_file): + """ create a database connection to a SQLite database """ + conn = None + try: + conn = sqlite3.connect(db_file) + sql_create_detections_table = """ CREATE TABLE IF NOT EXISTS detections ( + id integer PRIMARY KEY, + Com_Name text NOT NULL, + Date date NULL, + Time time NULL + ); """ + cur = conn.cursor() + cur.execute(sql_create_detections_table) + sql = ''' INSERT INTO detections(Com_Name, Date) + VALUES(?,?) ''' + + cur = conn.cursor() + cur.execute(sql, ["Great Crested Flycatcher", datetime.now()]) + conn.commit() + + except Error as e: + print(e) + finally: + if conn: + conn.close() + + +@pytest.fixture(autouse=True) +def clean_up_after_each_test(): + yield + os.remove("test.db") + +def test_daily_notifications(mocker): + notify_call = mocker.patch('scripts.notifications.notify') + create_test_db("test.db") + assert(0 == 0) + sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", "91", "filename", "test.db") + assert(notify_call.call_count == 2) + assert( + notify_call.call_args_list[0][0][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (only seen 1 times today)" + ) + assert( + notify_call.call_args_list[1][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (only seen 1 times in last 7d)" + ) From bd52aabaab383eece9414ae1a2fe4fcb48cb7623 Mon Sep 17 00:00:00 2001 From: Joe Weiss Date: Sat, 18 Jun 2022 14:50:41 -0400 Subject: [PATCH 02/22] Ignore non-tracked upstream files --- .gitignore | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.gitignore b/.gitignore index c622287..99afbb4 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,14 @@ birdnet.conf IdentifiedSoFar.txt IdentifiedSoFar.txt.bak Birders_Guide_Installer_Configuration.txt +birdnet/ +templates/*.service +scripts/*.txt +scripts/birds.db +analyzing_now.txt +apprise.txt +BirdDB.txt +exclude_species_list.txt +firstrun.ini +HUMAN.txt +include_species_list.txt From 6865274bd253413b5555ca0a560db9c81f09ca9d Mon Sep 17 00:00:00 2001 From: Joe Weiss Date: Sat, 18 Jun 2022 14:52:42 -0400 Subject: [PATCH 03/22] Add utility to parse thisrun format --- scripts/notifications.py | 40 +++++++++----------------- scripts/server.py | 4 ++- scripts/utils/__init__.py | 0 scripts/utils/parse_settings.py | 16 +++++++++++ tests/test_apprise_notifications.py | 37 +++++++++++++++++++++--- tests/test_settings_parse.py | 44 +++++++++++++++++++++++++++++ 6 files changed, 110 insertions(+), 31 deletions(-) create mode 100644 scripts/utils/__init__.py create mode 100644 scripts/utils/parse_settings.py create mode 100644 tests/test_settings_parse.py diff --git a/scripts/notifications.py b/scripts/notifications.py index 8c1ef4a..312b8a8 100644 --- a/scripts/notifications.py +++ b/scripts/notifications.py @@ -21,19 +21,16 @@ def notify(body, title): title=title, ) -def get_setting(param): - with open(THIS_RUN_PATH, 'r') as f: - this_run = f.readlines() - return str(str(str([i for i in this_run if i.startswith(param)]).split('=')[1]).split('\\')[0]).replace('"', '') - -def sendAppriseNotifications(species, confidence, path, db_path=DB_PATH): +def sendAppriseNotifications(species, confidence, path, settings_dict, db_path=DB_PATH): + # print(settings_dict) if os.path.exists(APPRISE_CONFIG) and os.path.getsize(APPRISE_CONFIG) > 0: - title = get_setting('APPRISE_NOTIFICATION_TITLE') - body = get_setting('APPRISE_NOTIFICATION_BODY') + title = settings_dict.get('APPRISE_NOTIFICATION_TITLE') + body = settings_dict.get('APPRISE_NOTIFICATION_BODY') + sciName, comName = species.split("_") try: - websiteurl = get_setting('BIRDNETPI_URL') + websiteurl = settings_dict.get('BIRDNETPI_URL') if len(websiteurl) == 0: raise ValueError('Blank URL') except Exception as e: @@ -41,28 +38,20 @@ def sendAppriseNotifications(species, confidence, path, db_path=DB_PATH): listenurl = websiteurl+"?filename="+path - if get_setting('APPRISE_NOTIFY_EACH_DETECTION') == "1": - apobj = apprise.Apprise() - config = apprise.AppriseConfig() - config.add(APPRISE_CONFIG) - apobj.add(config) + if settings_dict.get('APPRISE_NOTIFY_EACH_DETECTION') == "1": + notify_body=body.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + notify_title=title.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + notify(notify_body, notify_title) - apobj.notify( - body=body.replace("$sciname", species.split("_")[0]).replace("$comname", species.split("_")[1]).replace("$confidence", confidence).replace("$listenurl", listenurl), - title=title.replace("$sciname", species.split("_")[0]).replace("$comname", species.split("_")[1]).replace("$confidence", confidence).replace("$listenurl", listenurl), - ) - - APPRISE_NOTIFICATION_NEW_SPECIES_DAILY = True - APPRISE_NOTIFICATION_NEW_SPECIES_DAILY_COUNT_LIMIT = 2 # Notifies the first N per day. - if APPRISE_NOTIFICATION_NEW_SPECIES_DAILY: + APPRISE_NOTIFICATION_NEW_SPECIES_DAILY_COUNT_LIMIT = 1 # Notifies the first N per day. + if settings_dict.get('APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY') == "1": try: con = sqlite3.connect(db_path) cur = con.cursor() cur.execute("SELECT DISTINCT(Com_Name), count(Com_Name) FROM detections WHERE date > (SELECT DATETIME('now', '-1 day')) GROUP BY Com_Name") known_species = cur.fetchall() - sciName, comName = species.split("_") numberDetections = [d[1] for d in known_species if d[0] == comName.replace("'","")][0] - if numberDetections < APPRISE_NOTIFICATION_NEW_SPECIES_DAILY_COUNT_LIMIT: + if numberDetections <= APPRISE_NOTIFICATION_NEW_SPECIES_DAILY_COUNT_LIMIT: notify_body=body.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections))+" times today)", notify_title=title.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections))+" times today)", notify(notify_body, notify_title) @@ -72,13 +61,12 @@ def sendAppriseNotifications(species, confidence, path, db_path=DB_PATH): print("Database busy") time.sleep(2) - if get_setting('APPRISE_NOTIFY_NEW_SPECIES') == "1": + if settings_dict.get('APPRISE_NOTIFY_NEW_SPECIES') == "1": try: con = sqlite3.connect(db_path) cur = con.cursor() cur.execute("SELECT DISTINCT(Com_Name), count(Com_Name) FROM detections WHERE date > (SELECT DATETIME('now', '-7 day')) GROUP BY Com_Name") known_species = cur.fetchall() - sciName, comName = species.split("_") numberDetections = [d[1] for d in known_species if d[0] == comName.replace("'","")][0] if numberDetections <= 5: notify_body=body.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections))+" times in last 7d)" diff --git a/scripts/server.py b/scripts/server.py index fce5319..72b7cc3 100755 --- a/scripts/server.py +++ b/scripts/server.py @@ -15,6 +15,7 @@ import threading import os from notifications import sendAppriseNotifications +from utils.parse_settings import config_to_settings os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' os.environ['CUDA_VISIBLE_DEVICES'] = '' @@ -49,6 +50,7 @@ with open(userDir + '/BirdNET-Pi/scripts/thisrun.txt', 'r') as f: audiofmt = "." + str(str(str([i for i in this_run if i.startswith('AUDIOFMT')]).split('=')[1]).split('\\')[0]) priv_thresh = float("." + str(str(str([i for i in this_run if i.startswith('PRIVACY_THRESHOLD')]).split('=')[1]).split('\\')[0])) / 10 +settings_dict = config_to_settings(userDir + '/BirdNET-Pi/scripts/thisrun.txt') def loadModel(): @@ -401,7 +403,7 @@ def handle_client(conn, addr): # Apprise of detection if not already alerted this run. if not str(entry[0] in species_apprised_this_run: - sendAppriseNotifications(str(entry[0]), str(entry[1]), File_Name) + sendAppriseNotifications(str(entry[0]), str(entry[1]), File_Name, settings_dict) species_apprised_this_run.append(str(entry[0]) diff --git a/scripts/utils/__init__.py b/scripts/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/scripts/utils/parse_settings.py b/scripts/utils/parse_settings.py new file mode 100644 index 0000000..d0e2166 --- /dev/null +++ b/scripts/utils/parse_settings.py @@ -0,0 +1,16 @@ +def config_to_settings(path): + # Returns settings dict from BirdNET-pi text format. + # Consider refactoring to use ConfigParser files, or another standardized format. + settings = {} + with open(path, 'r') as f: + this_run = f.readlines() + for i in this_run: + key = i.split("=")[0] + value = i.split("=")[1][:-1] + # Trim for strings, not ideal + if value.startswith('"') and value.endswith('"'): + value = value[1:-1] + if value.startswith("'") and value.endswith("'"): + value = value[1:-1] + settings[key] = value + return settings diff --git a/tests/test_apprise_notifications.py b/tests/test_apprise_notifications.py index deee959..5418113 100644 --- a/tests/test_apprise_notifications.py +++ b/tests/test_apprise_notifications.py @@ -37,15 +37,44 @@ def clean_up_after_each_test(): yield os.remove("test.db") -def test_daily_notifications(mocker): +def test_notifications(mocker): notify_call = mocker.patch('scripts.notifications.notify') create_test_db("test.db") - assert(0 == 0) - sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", "91", "filename", "test.db") + settings_dict = { + "APPRISE_NOTIFICATION_TITLE": "New backyard bird!", + "APPRISE_NOTIFICATION_BODY": "A $comname ($sciname) was just detected with a confidence of $confidence", + "APPRISE_NOTIFY_EACH_DETECTION": "0", + "APPRISE_NOTIFY_NEW_SPECIES": "0", + "APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY": "0" + } + + # No active apprise notifcations configured. Confirm no notifications. + sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", "91", "filename", settings_dict, "test.db") + assert(notify_call.call_count == 0) # No notification should be sent. + + # Add daily notification. + notify_call.reset_mock() + settings_dict["APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY"] = "1" + sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", "91", "filename", settings_dict, "test.db") + assert(notify_call.call_count == 1) + assert( + notify_call.call_args_list[0][0][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (only seen 1 times today)" + ) + + # Add new species notification. + notify_call.reset_mock() + settings_dict["APPRISE_NOTIFY_NEW_SPECIES"] = "1" + sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", "91", "filename", settings_dict, "test.db") assert(notify_call.call_count == 2) assert( notify_call.call_args_list[0][0][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (only seen 1 times today)" ) assert( notify_call.call_args_list[1][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (only seen 1 times in last 7d)" - ) + ) + + # Add each species notification. + notify_call.reset_mock() + settings_dict["APPRISE_NOTIFY_EACH_DETECTION"] = "1" + sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", "91", "filename", settings_dict, "test.db") + assert(notify_call.call_count == 3) diff --git a/tests/test_settings_parse.py b/tests/test_settings_parse.py new file mode 100644 index 0000000..de68b9f --- /dev/null +++ b/tests/test_settings_parse.py @@ -0,0 +1,44 @@ +from scripts.utils.parse_settings import config_to_settings +import tempfile + +def test(): + text = """LATITUDE=32.0 +LONGITUDE=-73.0 +BIRDWEATHER_ID= +CADDY_PWD="nonsuchpass" +ICE_PWD=birdnetpi +BIRDNETPI_URL= +RTSP_STREAM= +APPRISE_NOTIFICATION_TITLE="Bird!" +APPRISE_NOTIFICATION_BODY="A $comname ($sciname) was just detected with a confidence of $confidence" +APPRISE_NOTIFY_EACH_DETECTION=0 +APPRISE_NOTIFY_NEW_SPECIES=1 +FLICKR_API_KEY= +FLICKR_FILTER_EMAIL= +RECS_DIR=/home/pi/BirdSongs +REC_CARD=default +PROCESSED=/home/pi/BirdSongs/Processed +EXTRACTED=/home/pi/BirdSongs/Extracted +OVERLAP=0.0 +CONFIDENCE=0.7 +SENSITIVITY=1.25 +CHANNELS=2 +FULL_DISK=purge +PRIVACY_THRESHOLD=0 +RECORDING_LENGTH=15 +EXTRACTION_LENGTH= +AUDIOFMT=mp3 +DATABASE_LANG=en +LAST_RUN= +THIS_RUN= +IDFILE=/home/pi/BirdNET-Pi/IdentifiedSoFar.txt""" + + filename = tempfile.NamedTemporaryFile(suffix='.txt', delete=False) + with open(filename.name, 'w', encoding='utf8', newline='') as f: + f.write(text) + + settings = config_to_settings(filename.name) + assert(settings["APPRISE_NOTIFICATION_TITLE"] == "Bird!") + assert(settings["FULL_DISK"] == "purge") + assert(settings["OVERLAP"] == "0.0") # Yes, it's a string at this point. + From e05e72449b53ee1658bbf19d5a94f481d489349f Mon Sep 17 00:00:00 2001 From: Joe Weiss Date: Sun, 19 Jun 2022 06:58:49 -0400 Subject: [PATCH 04/22] Fix typos --- scripts/server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/server.py b/scripts/server.py index 72b7cc3..7b58635 100755 --- a/scripts/server.py +++ b/scripts/server.py @@ -402,10 +402,10 @@ def handle_client(conn, addr): time.sleep(2) # Apprise of detection if not already alerted this run. - if not str(entry[0] in species_apprised_this_run: + if not str(entry[0]) in species_apprised_this_run: sendAppriseNotifications(str(entry[0]), str(entry[1]), File_Name, settings_dict) - species_apprised_this_run.append(str(entry[0]) + species_apprised_this_run.append(str(entry[0])) print(str(current_date) + ';' + From 5c4763b44daf4c00b2a03bc8688123b896681e8e Mon Sep 17 00:00:00 2001 From: Joe Weiss Date: Mon, 20 Jun 2022 11:58:42 -0400 Subject: [PATCH 05/22] Improve query accuracy for today's birds --- scripts/notifications.py | 29 +++++++++++++++++++---------- scripts/server.py | 8 +++----- tests/test_apprise_notifications.py | 7 ++++--- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/scripts/notifications.py b/scripts/notifications.py index 312b8a8..71f5500 100644 --- a/scripts/notifications.py +++ b/scripts/notifications.py @@ -8,7 +8,6 @@ from datetime import datetime, timedelta userDir = os.path.expanduser('~') APPRISE_CONFIG = userDir + '/BirdNET-Pi/apprise.txt' -THIS_RUN_PATH = userDir + '/BirdNET-Pi/scripts/thisrun.txt' DB_PATH = userDir + '/BirdNET-Pi/scripts/birds.db' def notify(body, title): @@ -22,7 +21,8 @@ def notify(body, title): ) def sendAppriseNotifications(species, confidence, path, settings_dict, db_path=DB_PATH): - # print(settings_dict) + print(sendAppriseNotifications) + print(settings_dict) if os.path.exists(APPRISE_CONFIG) and os.path.getsize(APPRISE_CONFIG) > 0: title = settings_dict.get('APPRISE_NOTIFICATION_TITLE') @@ -48,12 +48,17 @@ def sendAppriseNotifications(species, confidence, path, settings_dict, db_path=D try: con = sqlite3.connect(db_path) cur = con.cursor() - cur.execute("SELECT DISTINCT(Com_Name), count(Com_Name) FROM detections WHERE date > (SELECT DATETIME('now', '-1 day')) GROUP BY Com_Name") + today = datetime.now().strftime("%Y-%m-%d") + cur.execute(f"SELECT DISTINCT(Com_Name), count(Com_Name) FROM detections WHERE Date = date('{today}') GROUP BY Com_Name") known_species = cur.fetchall() - numberDetections = [d[1] for d in known_species if d[0] == comName.replace("'","")][0] - if numberDetections <= APPRISE_NOTIFICATION_NEW_SPECIES_DAILY_COUNT_LIMIT: - notify_body=body.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections))+" times today)", - notify_title=title.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections))+" times today)", + detections = [d[1] for d in known_species if d[0] == comName.replace("'","")] + numberDetections = 0 + if len(detections): + numberDetections = detections[0] + if numberDetections > 0 and numberDetections <= APPRISE_NOTIFICATION_NEW_SPECIES_DAILY_COUNT_LIMIT: + print("send the notification") + notify_body=body.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (first time today)" + notify_title=title.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (first time today)" notify(notify_body, notify_title) con.close() except sqlite3.Error as e: @@ -65,10 +70,14 @@ def sendAppriseNotifications(species, confidence, path, settings_dict, db_path=D try: con = sqlite3.connect(db_path) cur = con.cursor() - cur.execute("SELECT DISTINCT(Com_Name), count(Com_Name) FROM detections WHERE date > (SELECT DATETIME('now', '-7 day')) GROUP BY Com_Name") + today = datetime.now().strftime("%Y-%m-%d") + cur.execute(f"SELECT DISTINCT(Com_Name), count(Com_Name) FROM detections WHERE Date >= date('{today}', '-7 day') GROUP BY Com_Name") known_species = cur.fetchall() - numberDetections = [d[1] for d in known_species if d[0] == comName.replace("'","")][0] - if numberDetections <= 5: + detections = [d[1] for d in known_species if d[0] == comName.replace("'","")] + numberDetections = 0 + if len(detections): + numberDetections = detections[0] + if numberDetections > 0 and numberDetections <= 5: notify_body=body.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections))+" times in last 7d)" notify_title=title.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections))+" times in last 7d)" notify(notify_body, notify_title) diff --git a/scripts/server.py b/scripts/server.py index 7b58635..c7e5ffe 100755 --- a/scripts/server.py +++ b/scripts/server.py @@ -50,8 +50,6 @@ with open(userDir + '/BirdNET-Pi/scripts/thisrun.txt', 'r') as f: audiofmt = "." + str(str(str([i for i in this_run if i.startswith('AUDIOFMT')]).split('=')[1]).split('\\')[0]) priv_thresh = float("." + str(str(str([i for i in this_run if i.startswith('PRIVACY_THRESHOLD')]).split('=')[1]).split('\\')[0])) / 10 -settings_dict = config_to_settings(userDir + '/BirdNET-Pi/scripts/thisrun.txt') - def loadModel(): global INPUT_LAYER_INDEX @@ -402,10 +400,10 @@ def handle_client(conn, addr): time.sleep(2) # Apprise of detection if not already alerted this run. - if not str(entry[0]) in species_apprised_this_run: + if not entry[0] in species_apprised_this_run: + settings_dict = config_to_settings(userDir + '/BirdNET-Pi/scripts/thisrun.txt') sendAppriseNotifications(str(entry[0]), str(entry[1]), File_Name, settings_dict) - - species_apprised_this_run.append(str(entry[0])) + species_apprised_this_run.append(entry[0]) print(str(current_date) + ';' + diff --git a/tests/test_apprise_notifications.py b/tests/test_apprise_notifications.py index 5418113..b2c5300 100644 --- a/tests/test_apprise_notifications.py +++ b/tests/test_apprise_notifications.py @@ -22,7 +22,8 @@ def create_test_db(db_file): VALUES(?,?) ''' cur = conn.cursor() - cur.execute(sql, ["Great Crested Flycatcher", datetime.now()]) + today = datetime.now().strftime("%Y-%m-%d") # SQLite stores date as YYYY-MM-DD + cur.execute(sql, ["Great Crested Flycatcher", today]) conn.commit() except Error as e: @@ -58,7 +59,7 @@ def test_notifications(mocker): sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", "91", "filename", settings_dict, "test.db") assert(notify_call.call_count == 1) assert( - notify_call.call_args_list[0][0][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (only seen 1 times today)" + notify_call.call_args_list[0][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (first time today)" ) # Add new species notification. @@ -67,7 +68,7 @@ def test_notifications(mocker): sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", "91", "filename", settings_dict, "test.db") assert(notify_call.call_count == 2) assert( - notify_call.call_args_list[0][0][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (only seen 1 times today)" + notify_call.call_args_list[0][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (first time today)" ) assert( notify_call.call_args_list[1][0][0] == "A Great Crested Flycatcher (Myiarchus crinitus) was just detected with a confidence of 91 (only seen 1 times in last 7d)" From 4ecab0eb6d5a3327d948ffd7863b474b3667e541 Mon Sep 17 00:00:00 2001 From: Joe Weiss Date: Tue, 21 Jun 2022 09:00:59 -0400 Subject: [PATCH 06/22] Remove debug print statements --- scripts/notifications.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/notifications.py b/scripts/notifications.py index 71f5500..a510252 100644 --- a/scripts/notifications.py +++ b/scripts/notifications.py @@ -21,8 +21,8 @@ def notify(body, title): ) def sendAppriseNotifications(species, confidence, path, settings_dict, db_path=DB_PATH): - print(sendAppriseNotifications) - print(settings_dict) + # print(sendAppriseNotifications) + # print(settings_dict) if os.path.exists(APPRISE_CONFIG) and os.path.getsize(APPRISE_CONFIG) > 0: title = settings_dict.get('APPRISE_NOTIFICATION_TITLE') From f8025b79d834934407083f31cb387d06bd2fe1c2 Mon Sep 17 00:00:00 2001 From: Joe Weiss Date: Tue, 21 Jun 2022 17:02:27 -0400 Subject: [PATCH 07/22] Add ability to edit apprise_notify_new_species_each_day via web --- scripts/config.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/scripts/config.php b/scripts/config.php index cbf3d25..95f42bd 100644 --- a/scripts/config.php +++ b/scripts/config.php @@ -41,6 +41,11 @@ if(isset($_GET["latitude"])){ } else { $apprise_notify_new_species = 0; } + if(isset($_GET['apprise_notify_new_species_each_day'])) { + $apprise_notify_new_species_each_day = 1; + } else { + $apprise_notify_new_species_each_day = 0; + } if(isset($timezone)) { shell_exec("sudo timedatectl set-timezone ".$timezone); @@ -95,6 +100,7 @@ if(isset($_GET["latitude"])){ $contents = preg_replace("/APPRISE_NOTIFICATION_BODY=.*/", "APPRISE_NOTIFICATION_BODY=\"$apprise_notification_body\"", $contents); $contents = preg_replace("/APPRISE_NOTIFY_EACH_DETECTION=.*/", "APPRISE_NOTIFY_EACH_DETECTION=$apprise_notify_each_detection", $contents); $contents = preg_replace("/APPRISE_NOTIFY_NEW_SPECIES=.*/", "APPRISE_NOTIFY_NEW_SPECIES=$apprise_notify_new_species", $contents); + $contents = preg_replace("/APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY=.*/", "APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY=$apprise_notify_new_species_each_day", $contents); $contents = preg_replace("/FLICKR_API_KEY=.*/", "FLICKR_API_KEY=$flickr_api_key", $contents); $contents = preg_replace("/DATABASE_LANG=.*/", "DATABASE_LANG=$language", $contents); $contents = preg_replace("/FLICKR_FILTER_EMAIL=.*/", "FLICKR_FILTER_EMAIL=$flickr_filter_email", $contents); @@ -107,6 +113,7 @@ if(isset($_GET["latitude"])){ $contents2 = preg_replace("/APPRISE_NOTIFICATION_BODY=.*/", "APPRISE_NOTIFICATION_BODY=\"$apprise_notification_body\"", $contents2); $contents2 = preg_replace("/APPRISE_NOTIFY_EACH_DETECTION=.*/", "APPRISE_NOTIFY_EACH_DETECTION=$apprise_notify_each_detection", $contents2); $contents2 = preg_replace("/APPRISE_NOTIFY_NEW_SPECIES=.*/", "APPRISE_NOTIFY_NEW_SPECIES=$apprise_notify_new_species", $contents2); + $contents2 = preg_replace("/APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY=.*/", "APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY=$apprise_notify_new_species_each_day", $contents2); $contents2 = preg_replace("/FLICKR_API_KEY=.*/", "FLICKR_API_KEY=$flickr_api_key", $contents2); $contents2 = preg_replace("/DATABASE_LANG=.*/", "DATABASE_LANG=$language", $contents2); $contents2 = preg_replace("/FLICKR_FILTER_EMAIL=.*/", "FLICKR_FILTER_EMAIL=$flickr_filter_email", $contents2); @@ -210,6 +217,8 @@ https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken}
>
+ > +
>


From 8393613303c0c32bffddf8bb7bf20666a19f95eb Mon Sep 17 00:00:00 2001 From: Joe Weiss Date: Tue, 21 Jun 2022 17:02:51 -0400 Subject: [PATCH 08/22] Add APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY to conf if missing --- scripts/update_birdnet_snippets.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/update_birdnet_snippets.sh b/scripts/update_birdnet_snippets.sh index d7e86c2..6651e63 100755 --- a/scripts/update_birdnet_snippets.sh +++ b/scripts/update_birdnet_snippets.sh @@ -40,6 +40,9 @@ fi if ! grep APPRISE_NOTIFY_NEW_SPECIES /etc/birdnet/birdnet.conf &>/dev/null;then sudo -u$USER echo "APPRISE_NOTIFY_NEW_SPECIES=0 " >> /etc/birdnet/birdnet.conf fi +if ! grep APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY /etc/birdnet/birdnet.conf &>/dev/null;then + sudo -u$USER echo "APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY=0 " >> /etc/birdnet/birdnet.conf +fi # If the config does not contain the DATABASE_LANG setting, we'll want to add it. # Defaults to not-selected, which config.php will know to render as a language option. From 75a13f80d3ff4247a3ad8ea81d37e3f69398a301 Mon Sep 17 00:00:00 2001 From: Joe Weiss Date: Thu, 23 Jun 2022 09:11:55 -0400 Subject: [PATCH 09/22] Move notifications utility into script.utils --- scripts/server.py | 2 +- scripts/{ => utils}/notifications.py | 0 tests/test_apprise_notifications.py | 5 +++-- 3 files changed, 4 insertions(+), 3 deletions(-) rename scripts/{ => utils}/notifications.py (100%) diff --git a/scripts/server.py b/scripts/server.py index c7e5ffe..239432f 100755 --- a/scripts/server.py +++ b/scripts/server.py @@ -14,7 +14,7 @@ import socket import threading import os -from notifications import sendAppriseNotifications +from utils.notifications import sendAppriseNotifications from utils.parse_settings import config_to_settings os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' diff --git a/scripts/notifications.py b/scripts/utils/notifications.py similarity index 100% rename from scripts/notifications.py rename to scripts/utils/notifications.py diff --git a/tests/test_apprise_notifications.py b/tests/test_apprise_notifications.py index b2c5300..b17c389 100644 --- a/tests/test_apprise_notifications.py +++ b/tests/test_apprise_notifications.py @@ -2,7 +2,7 @@ import os import sqlite3 import pytest -from scripts.notifications import sendAppriseNotifications +from scripts.utils.notifications import sendAppriseNotifications from datetime import datetime, timedelta def create_test_db(db_file): @@ -38,8 +38,9 @@ def clean_up_after_each_test(): yield os.remove("test.db") + def test_notifications(mocker): - notify_call = mocker.patch('scripts.notifications.notify') + notify_call = mocker.patch('scripts.utils.notifications.notify') create_test_db("test.db") settings_dict = { "APPRISE_NOTIFICATION_TITLE": "New backyard bird!", From 97e7b19aa2f382a082fbf6815f332ab3ce5efb21 Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Fri, 24 Jun 2022 07:46:37 -0400 Subject: [PATCH 10/22] linted --- scripts/utils/notifications.py | 39 ++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/scripts/utils/notifications.py b/scripts/utils/notifications.py index a510252..90e2b7b 100644 --- a/scripts/utils/notifications.py +++ b/scripts/utils/notifications.py @@ -2,14 +2,14 @@ import apprise import os import socket import sqlite3 -from sqlite3 import Error import time -from datetime import datetime, timedelta +from datetime import datetime userDir = os.path.expanduser('~') APPRISE_CONFIG = userDir + '/BirdNET-Pi/apprise.txt' DB_PATH = userDir + '/BirdNET-Pi/scripts/birds.db' + def notify(body, title): apobj = apprise.Apprise() config = apprise.AppriseConfig() @@ -20,6 +20,7 @@ def notify(body, title): title=title, ) + def sendAppriseNotifications(species, confidence, path, settings_dict, db_path=DB_PATH): # print(sendAppriseNotifications) # print(settings_dict) @@ -28,22 +29,22 @@ def sendAppriseNotifications(species, confidence, path, settings_dict, db_path=D title = settings_dict.get('APPRISE_NOTIFICATION_TITLE') body = settings_dict.get('APPRISE_NOTIFICATION_BODY') sciName, comName = species.split("_") - + try: websiteurl = settings_dict.get('BIRDNETPI_URL') if len(websiteurl) == 0: raise ValueError('Blank URL') - except Exception as e: + except Exception: websiteurl = "http://"+socket.gethostname()+".local" listenurl = websiteurl+"?filename="+path - + if settings_dict.get('APPRISE_NOTIFY_EACH_DETECTION') == "1": - notify_body=body.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) - notify_title=title.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + notify_body = body.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + notify_title = title.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) notify(notify_body, notify_title) - APPRISE_NOTIFICATION_NEW_SPECIES_DAILY_COUNT_LIMIT = 1 # Notifies the first N per day. + APPRISE_NOTIFICATION_NEW_SPECIES_DAILY_COUNT_LIMIT = 1 # Notifies the first N per day. if settings_dict.get('APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY') == "1": try: con = sqlite3.connect(db_path) @@ -51,14 +52,18 @@ def sendAppriseNotifications(species, confidence, path, settings_dict, db_path=D today = datetime.now().strftime("%Y-%m-%d") cur.execute(f"SELECT DISTINCT(Com_Name), count(Com_Name) FROM detections WHERE Date = date('{today}') GROUP BY Com_Name") known_species = cur.fetchall() - detections = [d[1] for d in known_species if d[0] == comName.replace("'","")] + detections = [d[1] for d in known_species if d[0] == comName.replace("'", "")] numberDetections = 0 if len(detections): numberDetections = detections[0] if numberDetections > 0 and numberDetections <= APPRISE_NOTIFICATION_NEW_SPECIES_DAILY_COUNT_LIMIT: print("send the notification") - notify_body=body.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (first time today)" - notify_title=title.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (first time today)" + notify_body = body.replace("$sciname", sciName).replace("$comname", comName)\ + .replace("$confidence", confidence).replace("$listenurl", listenurl)\ + + " (first time today)" + notify_title = title.replace("$sciname", sciName).replace("$comname", comName)\ + .replace("$confidence", confidence).replace("$listenurl", listenurl)\ + + " (first time today)" notify(notify_body, notify_title) con.close() except sqlite3.Error as e: @@ -73,13 +78,17 @@ def sendAppriseNotifications(species, confidence, path, settings_dict, db_path=D today = datetime.now().strftime("%Y-%m-%d") cur.execute(f"SELECT DISTINCT(Com_Name), count(Com_Name) FROM detections WHERE Date >= date('{today}', '-7 day') GROUP BY Com_Name") known_species = cur.fetchall() - detections = [d[1] for d in known_species if d[0] == comName.replace("'","")] + detections = [d[1] for d in known_species if d[0] == comName.replace("'", "")] numberDetections = 0 if len(detections): numberDetections = detections[0] if numberDetections > 0 and numberDetections <= 5: - notify_body=body.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections))+" times in last 7d)" - notify_title=title.replace("$sciname", sciName).replace("$comname", comName).replace("$confidence", confidence).replace("$listenurl", listenurl) + " (only seen "+str(int(numberDetections))+" times in last 7d)" + notify_body = body.replace("$sciname", sciName).replace("$comname", comName)\ + .replace("$confidence", confidence).replace("$listenurl", listenurl)\ + + " (only seen " + str(int(numberDetections)) + " times in last 7d)" + notify_title = title.replace("$sciname", sciName).replace("$comname", comName)\ + .replace("$confidence", confidence).replace("$listenurl", listenurl)\ + + " (only seen " + str(int(numberDetections)) + " times in last 7d)" notify(notify_body, notify_title) con.close() except sqlite3.Error: @@ -89,5 +98,3 @@ def sendAppriseNotifications(species, confidence, path, settings_dict, db_path=D if __name__ == "__main__": print("notfications") - - \ No newline at end of file From 3d991d6cab6bcefcdfad8d423ed0a14e7c6c9c27 Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Fri, 24 Jun 2022 09:15:36 -0400 Subject: [PATCH 11/22] linted --- scripts/server.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/server.py b/scripts/server.py index 239432f..350a013 100755 --- a/scripts/server.py +++ b/scripts/server.py @@ -1,4 +1,3 @@ -import apprise from pathlib import Path from tzlocal import get_localzone import datetime @@ -50,6 +49,7 @@ with open(userDir + '/BirdNET-Pi/scripts/thisrun.txt', 'r') as f: audiofmt = "." + str(str(str([i for i in this_run if i.startswith('AUDIOFMT')]).split('=')[1]).split('\\')[0]) priv_thresh = float("." + str(str(str([i for i in this_run if i.startswith('PRIVACY_THRESHOLD')]).split('=')[1]).split('\\')[0])) / 10 + def loadModel(): global INPUT_LAYER_INDEX @@ -389,8 +389,8 @@ def handle_client(conn, addr): try: con = sqlite3.connect(userDir + '/BirdNET-Pi/scripts/birds.db') cur = con.cursor() - cur.execute("INSERT INTO detections VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", (Date, Time, - Sci_Name, Com_Name, str(score), Lat, Lon, Cutoff, Week, Sens, Overlap, File_Name)) + cur.execute("INSERT INTO detections VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", (Date, Time, + Sci_Name, Com_Name, str(score), Lat, Lon, Cutoff, Week, Sens, Overlap, File_Name, "UNVERIFIED")) con.commit() con.close() @@ -398,7 +398,7 @@ def handle_client(conn, addr): except BaseException: print("Database busy") time.sleep(2) - + # Apprise of detection if not already alerted this run. if not entry[0] in species_apprised_this_run: settings_dict = config_to_settings(userDir + '/BirdNET-Pi/scripts/thisrun.txt') From 5a971cea4152c74867275a42896aa27be63a16d3 Mon Sep 17 00:00:00 2001 From: mcguirepr89 Date: Fri, 24 Jun 2022 09:15:59 -0400 Subject: [PATCH 12/22] linted plotly --- scripts/plotly_streamlit.py | 167 +++++++++++++++++------------------- 1 file changed, 80 insertions(+), 87 deletions(-) diff --git a/scripts/plotly_streamlit.py b/scripts/plotly_streamlit.py index d555e48..fe8fa08 100755 --- a/scripts/plotly_streamlit.py +++ b/scripts/plotly_streamlit.py @@ -6,13 +6,11 @@ from numpy import ma import plotly.graph_objects as go from plotly.subplots import make_subplots import plotly.io as pio -from datetime import timedelta, datetime -from pathlib import Path +from datetime import timedelta import sqlite3 from sqlite3 import Connection import plotly.express as px from sklearn.preprocessing import normalize -import time pio.templates.default = "plotly_white" @@ -40,9 +38,8 @@ st.markdown(""" """, unsafe_allow_html=True) - @st.cache(hash_funcs={Connection: id}) -#@st.cache(allow_output_mutation=True) +# @st.cache(allow_output_mutation=True) def get_connection(path: str): return sqlite3.connect(path, check_same_thread=False) @@ -58,19 +55,18 @@ df2 = df.copy() df2['DateTime'] = pd.to_datetime(df2['Date'] + " " + df2['Time']) df2 = df2.set_index('DateTime') -daily = st.sidebar.checkbox('Single Day View', help= 'Select if you want single day view, unselect for multi-day views') +daily = st.sidebar.checkbox('Single Day View', help='Select if you want single day view, unselect for multi-day views') if daily: -# Date as slider + # Date as slider Start_Date = pd.to_datetime(df2.index.min()).date() End_Date = pd.to_datetime(df2.index.max()).date() # cols1, cols2 = st.columns((1, 1)) end_date = st.sidebar.date_input('Date to View', - min_value = Start_Date, - max_value = End_Date, - value=(End_Date), - help= 'Select date for single day view' - ) + min_value=Start_Date, + max_value=End_Date, + value=(End_Date), + help='Select date for single day view') start_date = end_date else: Start_Date = pd.to_datetime(df2.index.min()).date() @@ -78,11 +74,10 @@ else: # cols1, cols2 = st.columns((1, 1)) start_date, end_date = st.sidebar.slider('Date Range', - min_value = Start_Date-timedelta(days=1), - max_value = End_Date, - value=(Start_Date, End_Date), - help= 'Select start and end date, if same date get a clockplot for a single day' - ) + min_value=Start_Date-timedelta(days=1), + max_value=End_Date, + value=(Start_Date, End_Date), + help='Select start and end date, if same date get a clockplot for a single day') # start_date, end_date = cols1.date_input( # "Date Input for Analysis - select Range for single specie analysis, select single date for daily view", @@ -93,12 +88,14 @@ else: # start_date = datetime(2022 ,5 ,17).date() # end_date = datetime(2022 ,5 ,17).date() + @st.cache() def date_filter(df, start_date, end_date): filt = (df2.index >= pd.Timestamp(start_date)) & (df2.index <= pd.Timestamp(end_date + timedelta(days=1))) df = df[filt] return(df) + df2 = date_filter(df2, start_date, end_date) st.write('', @@ -112,7 +109,7 @@ st.write('