Merge pull request #754 from bdoner/feature/add-confidencepct-variable-to-apprise-notification

Add confidencepct variable to apprise notification
This commit is contained in:
ehpersonal38
2023-05-30 12:30:25 -04:00
committed by GitHub
9 changed files with 79 additions and 68 deletions
+4 -2
View File
@@ -519,6 +519,8 @@ https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken}
<dd>Common Name</dd> <dd>Common Name</dd>
<dt>$confidence</dt> <dt>$confidence</dt>
<dd>Confidence Score</dd> <dd>Confidence Score</dd>
<dt>$confidencepct</dt>
<dd>Confidence Score as a percentage (eg. 0.91 => 91)</dd>
<dt>$listenurl</dt> <dt>$listenurl</dt>
<dd>A link to the detection</dd> <dd>A link to the detection</dd>
<dt>$date</dt> <dt>$date</dt>
@@ -542,9 +544,9 @@ https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken}
</dl> </dl>
<p>Use the variables defined above to customize your notification title and body.</p> <p>Use the variables defined above to customize your notification title and body.</p>
<label for="apprise_notification_title">Notification Title: </label> <label for="apprise_notification_title">Notification Title: </label>
<input name="apprise_notification_title" type="text" value="<?php print($config['APPRISE_NOTIFICATION_TITLE']);?>" /><br> <input name="apprise_notification_title" style="width: 100%" type="text" value="<?php print($config['APPRISE_NOTIFICATION_TITLE']);?>" /><br>
<label for="apprise_notification_body">Notification Body: </label> <label for="apprise_notification_body">Notification Body: </label>
<input name="apprise_notification_body" type="text" value='<?php print($config['APPRISE_NOTIFICATION_BODY']);?>' /><br> <input name="apprise_notification_body" style="width: 100%" type="text" value='<?php print($config['APPRISE_NOTIFICATION_BODY']);?>' /><br>
<input type="checkbox" name="apprise_notify_new_species" <?php if($config['APPRISE_NOTIFY_NEW_SPECIES'] == 1 && filesize($home."/BirdNET-Pi/apprise.txt") != 0) { echo "checked"; };?> > <input type="checkbox" name="apprise_notify_new_species" <?php if($config['APPRISE_NOTIFY_NEW_SPECIES'] == 1 && filesize($home."/BirdNET-Pi/apprise.txt") != 0) { echo "checked"; };?> >
<label for="apprise_notify_new_species">Notify each new infrequent species detection (<5 visits per week)</label><br> <label for="apprise_notify_new_species">Notify each new infrequent species detection (<5 visits per week)</label><br>
<input type="checkbox" name="apprise_notify_new_species_each_day" <?php if($config['APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY'] == 1 && filesize($home."/BirdNET-Pi/apprise.txt") != 0) { echo "checked"; };?> > <input type="checkbox" name="apprise_notify_new_species_each_day" <?php if($config['APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY'] == 1 && filesize($home."/BirdNET-Pi/apprise.txt") != 0) { echo "checked"; };?> >
+2 -1
View File
@@ -48,7 +48,8 @@ readings = 10
plt_top10_today = (df_plt_today['Com_Name'].value_counts()[:readings]) plt_top10_today = (df_plt_today['Com_Name'].value_counts()[:readings])
df_plt_top10_today = df_plt_today[df_plt_today.Com_Name.isin(plt_top10_today.index)] df_plt_top10_today = df_plt_today[df_plt_today.Com_Name.isin(plt_top10_today.index)]
if df_plt_top10_today.empty: exit(0) if df_plt_top10_today.empty:
exit(0)
# Set Palette for graphics # Set Palette for graphics
pal = "Greens" pal = "Greens"
+8 -8
View File
@@ -95,7 +95,7 @@ else:
def date_filter(df, start_date, end_date): def date_filter(df, start_date, end_date):
filt = (df2.index >= pd.Timestamp(start_date)) & (df2.index <= pd.Timestamp(end_date + timedelta(days=1))) filt = (df2.index >= pd.Timestamp(start_date)) & (df2.index <= pd.Timestamp(end_date + timedelta(days=1)))
df = df[filt] df = df[filt]
return(df) return (df)
df2 = date_filter(df2, start_date, end_date) df2 = date_filter(df2, start_date, end_date)
@@ -142,7 +142,7 @@ def time_resample(df, resample_time):
else: else:
df_resample = df.resample(resample_time)['Com_Name'].aggregate('unique').explode() df_resample = df.resample(resample_time)['Com_Name'].aggregate('unique').explode()
return(df_resample) return (df_resample)
top_bird = df2['Com_Name'].mode()[0] top_bird = df2['Com_Name'].mode()[0]
@@ -236,10 +236,10 @@ if daily is False:
if resample_time != '1D': if resample_time != '1D':
specie = st.selectbox( specie = st.selectbox(
'Which bird would you like to explore for the dates ' 'Which bird would you like to explore for the dates '
+ str(start_date) + ' to ' + str(end_date) + '?', + str(start_date) + ' to ' + str(end_date) + '?',
species, species,
index=0) index=0)
# filt = df2['Com_Name'] == specie # filt = df2['Com_Name'] == specie
if specie == 'All': if specie == 'All':
@@ -256,7 +256,7 @@ if daily is False:
# '{:.2f}%'.format(max(df2[df2['Com_Name'] == specie]['Confidence']) * 100)) + # '{:.2f}%'.format(max(df2[df2['Com_Name'] == specie]['Confidence']) * 100)) +
# ' ' + ' Median:' + str( # ' ' + ' Median:' + str(
# '{:.2f}%'.format(np.median(df2[df2['Com_Name'] == specie]['Confidence']) * 100)) # '{:.2f}%'.format(np.median(df2[df2['Com_Name'] == specie]['Confidence']) * 100))
) )
) )
fig.layout.annotations[1].update(x=0.7, y=0.25, font_size=15) fig.layout.annotations[1].update(x=0.7, y=0.25, font_size=15)
@@ -316,7 +316,7 @@ if daily is False:
fig = make_subplots( fig = make_subplots(
rows=3, cols=1, rows=3, cols=1,
specs=[[{"type": "polar", "rowspan": 2}], [{"rowspan": 1}], [{"type": "xy", "rowspan": 1}]] specs=[[{"type": "polar", "rowspan": 2}], [{"rowspan": 1}], [{"type": "xy", "rowspan": 1}]]
) )
# Set 360 degrees, 24 hours for polar plot # Set 360 degrees, 24 hours for polar plot
theta = np.linspace(0.0, 360, 24, endpoint=False) theta = np.linspace(0.0, 360, 24, endpoint=False)
+18 -9
View File
@@ -57,10 +57,11 @@ with open(userDir + '/BirdNET-Pi/scripts/thisrun.txt', 'r') as f:
try: try:
model = str(str(str([i for i in this_run if i.startswith('MODEL')]).split('=')[1]).split('\\')[0]) model = str(str(str([i for i in this_run if i.startswith('MODEL')]).split('=')[1]).split('\\')[0])
sf_thresh = str(str(str([i for i in this_run if i.startswith('SF_THRESH')]).split('=')[1]).split('\\')[0]) sf_thresh = str(str(str([i for i in this_run if i.startswith('SF_THRESH')]).split('=')[1]).split('\\')[0])
except Exception as e: except Exception:
model = "BirdNET_6K_GLOBAL_MODEL" model = "BirdNET_6K_GLOBAL_MODEL"
sf_thresh = 0.03 sf_thresh = 0.03
def loadModel(): def loadModel():
global INPUT_LAYER_INDEX global INPUT_LAYER_INDEX
@@ -97,6 +98,7 @@ def loadModel():
return myinterpreter return myinterpreter
def loadMetaModel(): def loadMetaModel():
global M_INTERPRETER global M_INTERPRETER
@@ -117,15 +119,16 @@ def loadMetaModel():
print("loaded META model") print("loaded META model")
def predictFilter(lat, lon, week): def predictFilter(lat, lon, week):
global M_INTERPRETER global M_INTERPRETER
# Does interpreter exist? # Does interpreter exist?
try: try:
if M_INTERPRETER == None: if M_INTERPRETER is None:
loadMetaModel() loadMetaModel()
except Exception as e: except Exception:
loadMetaModel() loadMetaModel()
# Prepare mdata as sample # Prepare mdata as sample
@@ -137,6 +140,7 @@ def predictFilter(lat, lon, week):
return M_INTERPRETER.get_tensor(M_OUTPUT_LAYER_INDEX)[0] return M_INTERPRETER.get_tensor(M_OUTPUT_LAYER_INDEX)[0]
def explore(lat, lon, week): def explore(lat, lon, week):
# Make filter prediction # Make filter prediction
@@ -153,15 +157,17 @@ def explore(lat, lon, week):
return l_filter return l_filter
def predictSpeciesList(lat, lon, week): def predictSpeciesList(lat, lon, week):
l_filter = explore(lat, lon, week) l_filter = explore(lat, lon, week)
for s in l_filter: for s in l_filter:
if s[0] >= float(sf_thresh): if s[0] >= float(sf_thresh):
#if there's a custom user-made include list, we only want to use the species in that # if there's a custom user-made include list, we only want to use the species in that
if(len(INCLUDE_LIST) == 0): if (len(INCLUDE_LIST) == 0):
PREDICTED_SPECIES_LIST.append(s[1]) PREDICTED_SPECIES_LIST.append(s[1])
def loadCustomSpeciesList(path): def loadCustomSpeciesList(path):
slist = [] slist = []
@@ -274,8 +280,7 @@ def analyzeAudioData(chunks, lat, lon, week, sensitivity, overlap,):
if model == "BirdNET_GLOBAL_3K_V2.3_Model_FP16": if model == "BirdNET_GLOBAL_3K_V2.3_Model_FP16":
if len(PREDICTED_SPECIES_LIST) == 0 or len(INCLUDE_LIST) != 0: if len(PREDICTED_SPECIES_LIST) == 0 or len(INCLUDE_LIST) != 0:
predictSpeciesList(lat,lon,week) predictSpeciesList(lat, lon, week)
# Convert and prepare metadata # Convert and prepare metadata
mdata = convertMetadata(np.array([lat, lon, week])) mdata = convertMetadata(np.array([lat, lon, week]))
@@ -322,7 +327,9 @@ def writeResultsToFile(detections, min_conf, path):
rfile.write('Start (s);End (s);Scientific name;Common name;Confidence\n') rfile.write('Start (s);End (s);Scientific name;Common name;Confidence\n')
for d in detections: for d in detections:
for entry in detections[d]: 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) and (entry[0] in PREDICTED_SPECIES_LIST or len(PREDICTED_SPECIES_LIST) == 0) ): 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)
and (entry[0] in PREDICTED_SPECIES_LIST or len(PREDICTED_SPECIES_LIST) == 0)):
rfile.write(d + ';' + entry[0].replace('_', ';').split("/")[0] + ';' + str(entry[1]) + '\n') rfile.write(d + ';' + entry[0].replace('_', ';').split("/")[0] + ';' + str(entry[1]) + '\n')
rcnt += 1 rcnt += 1
print('DONE! WROTE', rcnt, 'RESULTS.') print('DONE! WROTE', rcnt, 'RESULTS.')
@@ -468,7 +475,8 @@ def handle_client(conn, addr):
species_apprised_this_run = [] species_apprised_this_run = []
for entry in detections[d]: for entry in detections[d]:
if entry[1] >= min_conf and ((entry[0] in INCLUDE_LIST or len(INCLUDE_LIST) == 0) 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) and (entry[0] in PREDICTED_SPECIES_LIST or len(PREDICTED_SPECIES_LIST) == 0) ): and (entry[0] not in EXCLUDE_LIST or len(EXCLUDE_LIST) == 0)
and (entry[0] in PREDICTED_SPECIES_LIST or len(PREDICTED_SPECIES_LIST) == 0)):
# Write to text file. # Write to text file.
rfile.write(str(current_date) + ';' + str(current_time) + ';' + entry[0].replace('_', ';').split("/")[0] + ';' rfile.write(str(current_date) + ';' + str(current_time) + ';' + entry[0].replace('_', ';').split("/")[0] + ';'
+ str(entry[1]) + ";" + str(args.lat) + ';' + str(args.lon) + ';' + str(min_conf) + ';' + str(week) + ';' + str(entry[1]) + ";" + str(args.lat) + ';' + str(args.lon) + ';' + str(min_conf) + ';' + str(week) + ';'
@@ -511,6 +519,7 @@ def handle_client(conn, addr):
settings_dict = config_to_settings(userDir + '/BirdNET-Pi/scripts/thisrun.txt') settings_dict = config_to_settings(userDir + '/BirdNET-Pi/scripts/thisrun.txt')
sendAppriseNotifications(species, sendAppriseNotifications(species,
str(score), str(score),
str(round(score * 100)),
File_Name, File_Name,
Date, Date,
Time, Time,
+14 -29
View File
@@ -1,18 +1,5 @@
from pathlib import Path
from tzlocal import get_localzone
import datetime
import sqlite3
import requests
import json
import time
import math
import numpy as np import numpy as np
import librosa
import operator
import socket
import threading
import os import os
import sys
import argparse import argparse
import datetime import datetime
@@ -22,7 +9,6 @@ except BaseException:
from tensorflow import lite as tflite from tensorflow import lite as tflite
def loadMetaModel(): def loadMetaModel():
global M_INTERPRETER global M_INTERPRETER
@@ -51,15 +37,16 @@ def loadMetaModel():
print("loaded META model") print("loaded META model")
def predictFilter(lat, lon, week): def predictFilter(lat, lon, week):
global M_INTERPRETER global M_INTERPRETER
# Does interpreter exist? # Does interpreter exist?
try: try:
if M_INTERPRETER == None: if M_INTERPRETER is None:
loadMetaModel() loadMetaModel()
except Exception as e: except Exception:
loadMetaModel() loadMetaModel()
# Prepare mdata as sample # Prepare mdata as sample
@@ -71,6 +58,7 @@ def predictFilter(lat, lon, week):
return M_INTERPRETER.get_tensor(M_OUTPUT_LAYER_INDEX)[0] return M_INTERPRETER.get_tensor(M_OUTPUT_LAYER_INDEX)[0]
def explore(lat, lon, week, threshold): def explore(lat, lon, week, threshold):
# Make filter prediction # Make filter prediction
@@ -87,6 +75,7 @@ def explore(lat, lon, week, threshold):
return l_filter return l_filter
def getSpeciesList(lat, lon, week, threshold=0.05, sort=False): def getSpeciesList(lat, lon, week, threshold=0.05, sort=False):
print('Getting species list for {}/{}, Week {}...'.format(lat, lon, week), end='', flush=True) print('Getting species list for {}/{}, Week {}...'.format(lat, lon, week), end='', flush=True)
@@ -98,7 +87,7 @@ def getSpeciesList(lat, lon, week, threshold=0.05, sort=False):
slist = [] slist = []
for p in pred: for p in pred:
if p[0] >= threshold: if p[0] >= threshold:
slist.append([p[1],p[0]]) slist.append([p[1], p[0]])
return slist return slist
@@ -115,13 +104,10 @@ weekofyear = datetime.datetime.today().isocalendar()[1]
if __name__ == '__main__': if __name__ == '__main__':
# Parse arguments # Parse arguments
parser = argparse.ArgumentParser(description='Get list of species for a given location with BirdNET. Sorted by occurrence frequency.') parser = argparse.ArgumentParser(
#parser.add_argument('--o', default='/home/pi/BirdNET-Pi/include_species_list.txt', help='Path to output file or folder. If this is a folder, file will be named \'species_list.txt\'.') description='Get list of species for a given location with BirdNET. Sorted by occurrence frequency.'
#parser.add_argument('--lat', type=float, default=##, help='Recording location latitude. Set -1 to ignore.') )
#parser.add_argument('--lon', type=float, default=##, help='Recording location longitude. Set -1 to ignore.')
#parser.add_argument('--week', type=int, default=dayofweek, help='Week of the year when the recording was made. Values in [1, 48] (4 weeks per month). Set -1 for year-round species list.')
parser.add_argument('--threshold', type=float, default=0.05, help='Occurrence frequency threshold. Defaults to 0.05.') parser.add_argument('--threshold', type=float, default=0.05, help='Occurrence frequency threshold. Defaults to 0.05.')
#parser.add_argument('--sortby', default='freq', help='Sort species by occurrence frequency or alphabetically. Values in [\'freq\', \'alpha\']. Defaults to \'freq\'.')
args = parser.parse_args() args = parser.parse_args()
@@ -130,10 +116,9 @@ if __name__ == '__main__':
# Get species list # Get species list
species_list = getSpeciesList(lat, lon, weekofyear, LOCATION_FILTER_THRESHOLD, False) species_list = getSpeciesList(lat, lon, weekofyear, LOCATION_FILTER_THRESHOLD, False)
for x in range(len(species_list)): for x in range(len(species_list)):
print(species_list[x][0] + " - "+ str(species_list[x][1])) print(species_list[x][0] + " - " + str(species_list[x][1]))
print("\nThe above species list describes all the species that the model will attempt to detect. If you don't see a species you want detected on this list, decrease your threshold.")
print("\nNOTE: no actual changes to your BirdNET-Pi species list were made by running this command. To set your desired frequency threshold, do it through the BirdNET-Pi web interface (Tools -> Settings -> Model)")
print("\nThe above species list describes all the species that the model will attempt to detect. \
If you don't see a species you want detected on this list, decrease your threshold.")
print("\nNOTE: no actual changes to your BirdNET-Pi species list were made by running this command. \
To set your desired frequency threshold, do it through the BirdNET-Pi web interface (Tools -> Settings -> Model)")
+13 -4
View File
@@ -24,6 +24,7 @@ config = apprise.AppriseConfig()
config.add(APPRISE_CONFIG) config.add(APPRISE_CONFIG)
apobj.add(config) apobj.add(config)
def notify(body, title, attached=""): def notify(body, title, attached=""):
if attached != "": if attached != "":
apobj.notify( apobj.notify(
@@ -38,7 +39,9 @@ def notify(body, title, attached=""):
) )
def sendAppriseNotifications(species, confidence, path, date, time, week, latitude, longitude, cutoff, sens, overlap, settings_dict, db_path=DB_PATH): def sendAppriseNotifications(species, confidence, confidencepct, path,
date, time, week, latitude, longitude, cutoff,
sens, overlap, settings_dict, db_path=DB_PATH):
# print(sendAppriseNotifications) # print(sendAppriseNotifications)
# print(settings_dict) # print(settings_dict)
if os.path.exists(APPRISE_CONFIG) and os.path.getsize(APPRISE_CONFIG) > 0: if os.path.exists(APPRISE_CONFIG) and os.path.getsize(APPRISE_CONFIG) > 0:
@@ -67,7 +70,7 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
print("APPRISE NOTIFICATION EXCEPTION: "+str(e)) print("APPRISE NOTIFICATION EXCEPTION: "+str(e))
return return
#TODO: this all needs to be changed, we changed the caddy default to allow direct IP access, so birdnetpi.local shouldn't be relied on anymore # TODO: this all needs to be changed, we changed the caddy default to allow direct IP access, so birdnetpi.local shouldn't be relied on anymore
try: try:
websiteurl = settings_dict.get('BIRDNETPI_URL') websiteurl = settings_dict.get('BIRDNETPI_URL')
if len(websiteurl) == 0: if len(websiteurl) == 0:
@@ -79,12 +82,13 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
image_url = "" image_url = ""
if len(settings_dict.get('FLICKR_API_KEY')) > 0 and "$flickrimage" in body: if len(settings_dict.get('FLICKR_API_KEY')) > 0 and "$flickrimage" in body:
if not comName in flickr_images: if comName not in flickr_images:
try: try:
# TODO: Make this work with non-english comnames. Implement the "// convert sci name to English name" logic from overview.php here # TODO: Make this work with non-english comnames. Implement the "// convert sci name to English name" logic from overview.php here
headers = {'User-Agent': 'Python_Flickr/1.0'} 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(comName)+' bird&sort=relevance&per_page=5&media=photos&format=json&license=2%2C3%2C4%2C5%2C6%2C9&nojsoncallback=1' url = 'https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key='+str(settings_dict.get('FLICKR_API_KEY'))+'&text='+str(comName)+' 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) resp = requests.get(url=url, headers=headers)
resp.encoding = "utf-8" resp.encoding = "utf-8"
data = resp.json()["photos"]["photo"][0] data = resp.json()["photos"]["photo"][0]
@@ -96,10 +100,10 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
else: else:
image_url = flickr_images[comName] image_url = flickr_images[comName]
if settings_dict.get('APPRISE_NOTIFY_EACH_DETECTION') == "1": if settings_dict.get('APPRISE_NOTIFY_EACH_DETECTION') == "1":
notify_body = body.replace("$sciname", sciName)\ notify_body = body.replace("$sciname", sciName)\
.replace("$comname", comName)\ .replace("$comname", comName)\
.replace("$confidencepct", confidencepct)\
.replace("$confidence", confidence)\ .replace("$confidence", confidence)\
.replace("$listenurl", listenurl)\ .replace("$listenurl", listenurl)\
.replace("$date", date)\ .replace("$date", date)\
@@ -113,6 +117,7 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
.replace("$overlap", overlap) .replace("$overlap", overlap)
notify_title = title.replace("$sciname", sciName)\ notify_title = title.replace("$sciname", sciName)\
.replace("$comname", comName)\ .replace("$comname", comName)\
.replace("$confidencepct", confidencepct)\
.replace("$confidence", confidence)\ .replace("$confidence", confidence)\
.replace("$listenurl", listenurl)\ .replace("$listenurl", listenurl)\
.replace("$date", date)\ .replace("$date", date)\
@@ -143,6 +148,7 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
print("send the notification") print("send the notification")
notify_body = body.replace("$sciname", sciName)\ notify_body = body.replace("$sciname", sciName)\
.replace("$comname", comName)\ .replace("$comname", comName)\
.replace("$confidencepct", confidencepct)\
.replace("$confidence", confidence)\ .replace("$confidence", confidence)\
.replace("$listenurl", listenurl)\ .replace("$listenurl", listenurl)\
.replace("$date", date)\ .replace("$date", date)\
@@ -157,6 +163,7 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
+ " (first time today)" + " (first time today)"
notify_title = title.replace("$sciname", sciName)\ notify_title = title.replace("$sciname", sciName)\
.replace("$comname", comName)\ .replace("$comname", comName)\
.replace("$confidencepct", confidencepct)\
.replace("$confidence", confidence)\ .replace("$confidence", confidence)\
.replace("$listenurl", listenurl)\ .replace("$listenurl", listenurl)\
.replace("$date", date)\ .replace("$date", date)\
@@ -191,6 +198,7 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
if numberDetections > 0 and numberDetections <= 5: if numberDetections > 0 and numberDetections <= 5:
notify_body = body.replace("$sciname", sciName)\ notify_body = body.replace("$sciname", sciName)\
.replace("$comname", comName)\ .replace("$comname", comName)\
.replace("$confidencepct", confidencepct)\
.replace("$confidence", confidence)\ .replace("$confidence", confidence)\
.replace("$listenurl", listenurl)\ .replace("$listenurl", listenurl)\
.replace("$date", date)\ .replace("$date", date)\
@@ -205,6 +213,7 @@ def sendAppriseNotifications(species, confidence, path, date, time, week, latitu
+ " (only seen " + str(int(numberDetections)) + " times in last 7d)" + " (only seen " + str(int(numberDetections)) + " times in last 7d)"
notify_title = title.replace("$sciname", sciName)\ notify_title = title.replace("$sciname", sciName)\
.replace("$comname", comName)\ .replace("$comname", comName)\
.replace("$confidencepct", confidencepct)\
.replace("$confidence", confidence)\ .replace("$confidence", confidence)\
.replace("$listenurl", listenurl)\ .replace("$listenurl", listenurl)\
.replace("$date", date)\ .replace("$date", date)\
+1 -1
View File
@@ -6,7 +6,7 @@ def config_to_settings(path):
this_run = f.readlines() this_run = f.readlines()
for i in this_run: for i in this_run:
key = i.split("=")[0] key = i.split("=")[0]
value = i.split("=")[1][:-1] value = "=".join(i.split("=")[1:])[:-1]
# Trim for strings, not ideal # Trim for strings, not ideal
if value.startswith('"') and value.endswith('"'): if value.startswith('"') and value.endswith('"'):
value = value[1:-1] value = value[1:-1]
+13 -8
View File
@@ -50,6 +50,7 @@ def test_notifications(mocker):
"APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY": "0" "APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY": "0"
} }
sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher",
"0.91",
"91", "91",
"filename", "filename",
"1666-06-06", "1666-06-06",
@@ -64,12 +65,13 @@ def test_notifications(mocker):
"test.db") "test.db")
# No active apprise notifcations configured. Confirm no notifications. # No active apprise notifcations configured. Confirm no notifications.
assert(notify_call.call_count == 0) # No notification should be sent. assert (notify_call.call_count == 0) # No notification should be sent.
# Add daily notification. # Add daily notification.
notify_call.reset_mock() notify_call.reset_mock()
settings_dict["APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY"] = "1" settings_dict["APPRISE_NOTIFY_NEW_SPECIES_EACH_DAY"] = "1"
sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher",
"0.91",
"91", "91",
"filename", "filename",
"1666-06-06", "1666-06-06",
@@ -83,8 +85,8 @@ def test_notifications(mocker):
settings_dict, settings_dict,
"test.db") "test.db")
assert(notify_call.call_count == 1) assert (notify_call.call_count == 1)
assert( assert (
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)" 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)"
) )
@@ -92,6 +94,7 @@ def test_notifications(mocker):
notify_call.reset_mock() notify_call.reset_mock()
settings_dict["APPRISE_NOTIFY_NEW_SPECIES"] = "1" settings_dict["APPRISE_NOTIFY_NEW_SPECIES"] = "1"
sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher",
"0.91",
"91", "91",
"filename", "filename",
"1666-06-06", "1666-06-06",
@@ -105,18 +108,20 @@ def test_notifications(mocker):
settings_dict, settings_dict,
"test.db") "test.db")
assert(notify_call.call_count == 2) assert (notify_call.call_count == 2)
assert( assert (
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)" 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( 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)" 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. # Add each species notification.
notify_call.reset_mock() notify_call.reset_mock()
settings_dict["APPRISE_NOTIFY_EACH_DETECTION"] = "1" settings_dict["APPRISE_NOTIFY_EACH_DETECTION"] = "1"
sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher", sendAppriseNotifications("Myiarchus crinitus_Great Crested Flycatcher",
"0.91",
"91", "91",
"filename", "filename",
"1666-06-06", "1666-06-06",
@@ -130,4 +135,4 @@ def test_notifications(mocker):
settings_dict, settings_dict,
"test.db") "test.db")
assert(notify_call.call_count == 3) assert (notify_call.call_count == 3)
+3 -3
View File
@@ -39,6 +39,6 @@ IDFILE=/home/pi/BirdNET-Pi/IdentifiedSoFar.txt"""
f.write(text) f.write(text)
settings = config_to_settings(filename.name) settings = config_to_settings(filename.name)
assert(settings["APPRISE_NOTIFICATION_TITLE"] == "Bird!") assert (settings["APPRISE_NOTIFICATION_TITLE"] == "Bird!")
assert(settings["FULL_DISK"] == "purge") assert (settings["FULL_DISK"] == "purge")
assert(settings["OVERLAP"] == "0.0") # Yes, it's a string at this point. assert (settings["OVERLAP"] == "0.0") # Yes, it's a string at this point.