Merge pull request #90 from mcguirepr89/birdweather

Birdweather
This commit is contained in:
Patrick McGuire
2021-12-04 18:32:57 -05:00
committed by GitHub
31 changed files with 1065 additions and 409 deletions
+6
View File
@@ -141,6 +141,12 @@ DB_PWD=changeme
ICE_PWD=changeme ICE_PWD=changeme
#--------------------- BirdWeather Station Information -----------------------#
#_____________The variable below can be set to have your BirdNET-Pi____________#
#__________________also act as a BirdWeather listening station_________________#
BIRDWEATHER_ID=${BIRDWEATHER_ID}
#----------------------- Web-hosting/Caddy File-server -----------------------# #----------------------- Web-hosting/Caddy File-server -----------------------#
#________The four variables below can be set to enable internet access_________# #________The four variables below can be set to enable internet access_________#
#____________to your data,(e.g., extractions, raw data, live___________________# #____________to your data,(e.g., extractions, raw data, live___________________#
+22 -14
View File
@@ -1,18 +1,19 @@
# Birders Guide Installer Configuration File # Birders Guide Installer Configuration File
########################################################################### ################################################################################
# Fill this out in order to install BirdNET-Lite # Fill this out in order to install BirdNET-Lite
# Follow the instructions for each section. # Follow the instructions for each section.
########################################################################### ################################################################################
# 1. To find your latitude and longitude, you can go to https://maps.google.com # 1. To find your latitude and longitude, you can go to https://maps.google.com
# 1a. Find the location on the map where you will be putting the BirdNET-Lite # 1a. Find the location on the map where you will be putting the BirdNET-Lite
# 1b. Right-click the location to view the latitude and longitude and click them to # 1b. Right-click the location to view the latitude and longitude and click
# copy them to your clip-board. # them to copy them to your clip-board.
# 2. Enter the latitude and longitude here. Be certain not to mix them up and # 2. Enter the latitude and longitude here. Be certain not to mix them up.
# only go to the thousandth's decimal place. The first number is the latitude, # The first number is the latitude, and the second is longitude. See the
# and the second is longitude. See the example below. # example below.
#
# Example: these coordinates would indicate the Eiffel Tower in Paris, France. # Example: these coordinates would indicate the Eiffel Tower in Paris, France.
# LATITUDE=48.858 # LATITUDE=48.858
# LONGITUDE=2.294 # LONGITUDE=2.294
@@ -22,17 +23,17 @@ LONGITUDE=
# 1. CADDY_PWD is the password you will use to access your live audio stream and # 1. CADDY_PWD is the password you will use to access your live audio stream and
# maintenance tools. You can set this to anything, but keep it alpha-numeric. # maintenance tools. You can set this to anything, but keep it alpha-numeric.
# You will probably also want to write this one down if you ever plan to listen # You will probably also want to write this one down if you ever plan to
# to the live stream. # listen to the live stream.
# 2. ICE_PWD is the password that IceCast2 will use to authenticate the stream source. # 2. ICE_PWD is the password that IceCast2 will use to authenticate the stream
# You can set this to anything also, but keep it alpha-numeric. You will never use # source.You can set this to anything also, but keep it alpha-numeric. You
# this again, so just set it to your favorite word. # will never use this again, so just set it to your favorite word.
CADDY_PWD= CADDY_PWD=
ICE_PWD= ICE_PWD=
# DB_PWD is the password that the system will use to access the database. Set this to # DB_PWD is the password that the system will use to access the database. Set
# anything you want. # this to anything you want.
DB_PWD= DB_PWD=
@@ -49,3 +50,10 @@ PUSHED_APP_KEY=
BIRDNETPI_URL= BIRDNETPI_URL=
BIRDNETLOG_URL= BIRDNETLOG_URL=
EXTRACTIONLOG_URL= EXTRACTIONLOG_URL=
# If you would like to POST your BirdNET-Pi detections to
# https://app.birdweather.com, reach out to github:@timsterc for a unique and
# confidential BirdWeather ID. Place that here if you have one already.
# You can always add this later and the system will immediately start POSTing.
BIRDWEATHER_ID=
+2 -2
View File
@@ -570,11 +570,11 @@ Caddy, and Adminer use the Apache License Version 2.0
limitations under the License. limitations under the License.
============================================================================= =============================================================================
GoTTY use the MIT License GoTTY and autoAP scripts use the MIT License
============================================================================= =============================================================================
MIT License MIT License
BirdNET - Copyright (c) 2019 Stefan Kahl autoAP - Copywrite (c) 2021 Benn
GoTTY - Copyright (c) 2015-2017 Iwasaki Yudai GoTTY - Copyright (c) 2015-2017 Iwasaki Yudai
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
+1
View File
@@ -24,6 +24,7 @@ Check out birds from around the world
* Web interface access to all data and logs * Web interface access to all data and logs
* Automatic extraction of detected data (creating audio clips of detected bird sounds) * Automatic extraction of detected data (creating audio clips of detected bird sounds)
* Spectrograms available for all extractions * Spectrograms available for all extractions
* [BirdWeather](https://app.birdweather.com) integration (you will need to be issued a BirdWeather ID -- for now, request that from [@timsterc here](https://github.com/mcguirepr89/BirdNET-Pi/discussions/82))
* MariaDB integration * MariaDB integration
* NoMachine remote desktop (for personal use only) * NoMachine remote desktop (for personal use only)
* Live audio stream * Live audio stream
+109 -46
View File
@@ -1,3 +1,5 @@
# BirdWeather edits by @timsterc
# Other edits by @CaiusX and @mcguirepr89
import os import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
os.environ['CUDA_VISIBLE_DEVICES'] = '' os.environ['CUDA_VISIBLE_DEVICES'] = ''
@@ -13,10 +15,17 @@ import librosa
import numpy as np import numpy as np
import math import math
import time import time
from decimal import Decimal
import json
############################################################################### ###############################################################################
import requests
import mysql.connector import mysql.connector
############################################################################### ###############################################################################
from datetime import date, datetime import datetime
import pytz
from tzlocal import get_localzone
from pathlib import Path
def loadModel(): def loadModel():
global INPUT_LAYER_INDEX global INPUT_LAYER_INDEX
@@ -196,6 +205,7 @@ def main():
parser.add_argument('--sensitivity', type=float, default=1.0, help='Detection sensitivity; Higher values result in higher sensitivity. Values in [0.5, 1.5]. Defaults to 1.0.') parser.add_argument('--sensitivity', type=float, default=1.0, help='Detection sensitivity; Higher values result in higher sensitivity. Values in [0.5, 1.5]. Defaults to 1.0.')
parser.add_argument('--min_conf', type=float, default=0.1, help='Minimum confidence threshold. Values in [0.01, 0.99]. Defaults to 0.1.') parser.add_argument('--min_conf', type=float, default=0.1, help='Minimum confidence threshold. Values in [0.01, 0.99]. Defaults to 0.1.')
parser.add_argument('--custom_list', default='', help='Path to text file containing a list of species. Not used if not provided.') parser.add_argument('--custom_list', default='', help='Path to text file containing a list of species. Not used if not provided.')
parser.add_argument('--birdweather_id', default='99999', help='Private Station ID for BirdWeather.')
args = parser.parse_args() args = parser.parse_args()
@@ -208,75 +218,128 @@ def main():
else: else:
WHITE_LIST = [] WHITE_LIST = []
birdweather_id = args.birdweather_id
# Read audio data # Read audio data
audioData = readAudioData(args.i, args.overlap) audioData = readAudioData(args.i, args.overlap)
# Process audio data and get detections # Get Date/Time from filename in case Pi gets behind
week = max(1, min(args.week, 48)) #now = datetime.now()
full_file_name = args.i
file_name = Path(full_file_name).stem
file_date = file_name.split('-birdnet-')[0]
file_time = file_name.split('-birdnet-')[1]
date_time_str = file_date + ' ' + file_time
date_time_obj = datetime.datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S')
#print('Date:', date_time_obj.date())
#print('Time:', date_time_obj.time())
print('Date-time:', date_time_obj)
now = date_time_obj
current_date = now.strftime("%Y/%m/%d")
current_time = now.strftime("%H:%M:%S")
current_iso8601 = now.astimezone(get_localzone()).isoformat()
week_number = int(now.strftime("%V"))
week = max(1, min(week_number, 48))
sensitivity = max(0.5, min(1.0 - (args.sensitivity - 1.0), 1.5)) sensitivity = max(0.5, min(1.0 - (args.sensitivity - 1.0), 1.5))
# Process audio data and get detections
detections = analyzeAudioData(audioData, args.lat, args.lon, week, sensitivity, args.overlap, interpreter) detections = analyzeAudioData(audioData, args.lat, args.lon, week, sensitivity, args.overlap, interpreter)
# Write detections to output file # Write detections to output file
min_conf = max(0.01, min(args.min_conf, 0.99)) min_conf = max(0.01, min(args.min_conf, 0.99))
writeResultsToFile(detections, min_conf, args.o) writeResultsToFile(detections, min_conf, args.o)
now = datetime.now()
############################################################################### ###############################################################################
############################################################################### ###############################################################################
soundscape_uploaded = False
# Write detections to Database # Write detections to Database
for i in detections: for i in detections:
print("\n", detections[i][0],"\n") print("\n", detections[i][0],"\n")
with open('BirdDB.txt', 'a') as rfile: with open('BirdDB.txt', 'a') as rfile:
for d in detections: for d in detections:
print("\n", "Database Entry", "\n") print("\n", "Database Entry", "\n")
for entry in detections[d]: for entry in detections[d]:
if entry[1] >= min_conf and (entry[0] in WHITE_LIST or len(WHITE_LIST) == 0): if entry[1] >= min_conf and (entry[0] in WHITE_LIST or len(WHITE_LIST) == 0):
current_date = now.strftime("%Y/%m/%d") rfile.write(str(current_date) + ';' + str(current_time) + ';' + entry[0].replace('_', ';') + ';' \
current_time = now.strftime("%H:%M:%S") + str(entry[1]) +";" + str(args.lat) + ';' + str(args.lon) + ';' + str(min_conf) + ';' + str(week) + ';' \
rfile.write(str(current_date) + ';' + str(current_time) + ';' + entry[0].replace('_', ';') + ';' \ + str(sensitivity) +';' + str(args.overlap) + '\n')
+ str(entry[1]) +";" + str(args.lat) + ';' + str(args.lon) + ';' + str(min_conf) + ';' + str(week) + ';' \
+ str(sensitivity) +';' + str(args.overlap) + '\n')
def insert_variables_into_table(Date, Time, Sci_Name, Com_Name, Confidence, Lat, Lon, Cutoff, Week, Sens, Overlap): def insert_variables_into_table(Date, Time, Sci_Name, Com_Name, Confidence, Lat, Lon, Cutoff, Week, Sens, Overlap):
try: try:
connection = mysql.connector.connect(host='localhost', connection = mysql.connector.connect(host='localhost',
database='birds', database='birds',
user='birder', user='birder',
password='databasepassword') password='databasepassword')
cursor = connection.cursor() cursor = connection.cursor()
mySql_insert_query = """INSERT INTO detections (Date, Time, Sci_Name, Com_Name, Confidence, Lat, Lon, Cutoff, Week, Sens, Overlap) mySql_insert_query = """INSERT INTO detections (Date, Time, Sci_Name, Com_Name, Confidence, Lat, Lon, Cutoff, Week, Sens, Overlap)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) """ VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) """
record = (Date, Time, Sci_Name, Com_Name, Confidence, Lat, Lon, Cutoff, Week, Sens, Overlap)
cursor.execute(mySql_insert_query, record)
connection.commit()
print("Record inserted successfully into detections table")
except mysql.connector.Error as error:
print("Failed to insert record into detections table {}".format(error))
record = (Date, Time, Sci_Name, Com_Name, Confidence, Lat, Lon, Cutoff, Week, Sens, Overlap) finally:
if connection.is_connected():
connection.close()
print("MySQL connection is closed")
cursor.execute(mySql_insert_query, record) species = entry[0]
connection.commit() sci_name,com_name = species.split('_')
print("Record inserted successfully into detections table") insert_variables_into_table(str(current_date), str(current_time), sci_name, com_name, \
str(entry[1]), str(args.lat), str(args.lon), str(min_conf), str(week), \
str(args.sensitivity), str(args.overlap))
print(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')
except mysql.connector.Error as error:
print("Failed to insert record into detections table {}".format(error))
finally:
if connection.is_connected():
connection.close()
print("MySQL connection is closed")
species = entry[0] if birdweather_id != "99999":
sci_name,com_name = species.split('_')
insert_variables_into_table(str(current_date), str(current_time), sci_name, com_name, \
str(entry[1]), str(args.lat), str(args.lon), str(min_conf), str(week), \
str(args.sensitivity), str(args.overlap))
print(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') if soundscape_uploaded is False:
# POST soundscape to server
soundscape_url = "https://app.birdweather.com/api/v1/stations/" + birdweather_id + "/soundscapes" + "?timestamp=" + current_iso8601
time.sleep(3) with open(args.i, 'rb') as f:
wav_data = f.read()
response = requests.post(url=soundscape_url, data=wav_data, headers={'Content-Type': 'application/octet-stream'})
print("Soundscape POST Response Status - ", response.status_code)
sdata = response.json()
soundscape_id = sdata['soundscape']['id']
soundscape_uploaded = True
now = datetime.now() # POST detection to server
detection_url = "https://app.birdweather.com/api/v1/stations/" + birdweather_id + "/detections"
start_time = d.split(';')[0]
end_time = d.split(';')[1]
post_begin = "{ "
now_p_start = now + datetime.timedelta(seconds=float(start_time))
current_iso8601 = now_p_start.astimezone(get_localzone()).isoformat()
post_timestamp = "\"timestamp\": \"" + current_iso8601 + "\","
post_lat = "\"lat\": " + str(args.lat) + ","
post_lon = "\"lon\": " + str(args.lon) + ","
post_soundscape_id = "\"soundscapeId\": " + str(soundscape_id) + ","
post_soundscape_start_time = "\"soundscapeStartTime\": " + start_time + ","
post_soundscape_end_time = "\"soundscapeEndTime\": " + end_time + ","
post_commonName = "\"commonName\": \"" + entry[0].split('_')[1] + "\","
post_scientificName = "\"scientificName\": \"" + entry[0].split('_')[0] + "\","
post_algorithm = "\"algorithm\": " + "\"alpha\"" + ","
post_confidence = "\"confidence\": " + str(entry[1])
post_end = " }"
post_json = post_begin + post_timestamp + post_lat + post_lon + post_soundscape_id + post_soundscape_start_time + post_soundscape_end_time + post_commonName + post_scientificName + post_algorithm + post_confidence + post_end
print(post_json)
response = requests.post(detection_url, json=json.loads(post_json))
print("Detection POST Response Status - ", response.status_code)
#time.sleep(3)
############################################################################### ###############################################################################
############################################################################### ###############################################################################
+6
View File
@@ -53,6 +53,12 @@ DB_PWD=changeme
ICE_PWD=changeme ICE_PWD=changeme
#--------------------- BirdWeather Station Information -----------------------#
#_____________The variable below can be set to have your BirdNET-Pi____________#
#__________________also act as a BirdWeather listening station_________________#
BIRDWEATHER_ID=
#----------------------- Web-hosting/Caddy File-server -----------------------# #----------------------- Web-hosting/Caddy File-server -----------------------#
#________The four variables below can be set to enable internet access_________# #________The four variables below can be set to enable internet access_________#
#____________to your data,(e.g., extractions, raw data, live___________________# #____________to your data,(e.g., extractions, raw data, live___________________#
+34 -37
View File
@@ -1,45 +1,42 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd"> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html> <html>
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>BirdNET-Pi</title> <title>BirdNET-Pi</title>
<style> <style>
* { * {
background-color: background-color: rgb(119, 196, 135); background-color: background-color: rgb(119, 196, 135);
} }
</style> </style>
</head> </head>
<!-- <!--
Note the following: Note the following:
1. Each frame has it's own 'frame' tag. 1. Each frame has it's own 'frame' tag.
2. Each frame has a name (eg, name="menu"). This is used for when you need to load one frame from another. For example, your left frame might have links that, when clicked on, loads a new page in the right frame. This is acheived by using 'target="content"' within your links/anchor tags. 2. Each frame has a name (eg, name="menu"). This is used for when you need to load one frame from another. For example, your left frame might have links that, when clicked on, loads a new page in the right frame. This is acheived by using 'target="content"' within your links/anchor tags.
3. Each 'frame' tag has a 'src' attribute. This is where you specify the name of the file to be loaded into that frame when the page first loads. 3. Each 'frame' tag has a 'src' attribute. This is where you specify the name of the file to be loaded into that frame when the page first loads.
4. You can change the size of the frames by changing the value of the 'cols' and/or 'rows' attribute. A value of "200" sets the frame at 200 pixels. An asterisk (*) specifies that the frame should use up whatever space is left over from the other frames. You can also use percentage values if desired (i.e. 20%,80%) 4. You can change the size of the frames by changing the value of the 'cols' and/or 'rows' attribute. A value of "200" sets the frame at 200 pixels. An asterisk (*) specifies that the frame should use up whatever space is left over from the other frames. You can also use percentage values if desired (i.e. 20%,80%)
5. To specify a border, set 'frameborder' and 'border' to "1". I included both attributes for maximum browser compatibility. 5. To specify a border, set 'frameborder' and 'border' to "1". I included both attributes for maximum browser compatibility.
6. The 'framespacing' attribute doesn't work in all browsers, but you can set any numeric value you like here. 6. The 'framespacing' attribute doesn't work in all browsers, but you can set any numeric value you like here.
7. To learn more about HTML frames, check out: http://www.quackit.com/html/tutorial/html_frames.cfm 7. To learn more about HTML frames, check out: http://www.quackit.com/html/tutorial/html_frames.cfm
--> -->
<script type="text/javascript"> <script type="text/javascript">
if (screen.width <= 699) { if (screen.width <= 699) {
document.location = "/mobile.html"; document.location = "/mobile.html";
} }
</script> </script>
<frameset rows="100,*" frameborder="0" border="0" framespacing="0"> <frameset rows="100,*" frameborder="0" border="0" framespacing="0">
<frameset style="background-color: rgb(119, 196, 135);" cols="150,*,150" frameborder="0" border="0" framespacing="0"> <frameset style="background-color: rgb(119, 196, 135);" cols="*,150" frameborder="0" border="0" framespacing="0" />
<frame style="fill: none;background: rgb(119, 196, 135);padding-top: 15px;padding-left: 32.5px;padding-right: 32.5px;"src="images/bird.png" class="ribbon"/> <frame name="topNav" src="top.html" scrolling="off">
<frame name="topNav" src="top.html" scrolling="off"> <frame name="footer" src="footer.html" scrolling="off">
<frame name="footer" src="footer.html" scrolling="off"> </frameset>
</frameset> <frameset cols="150,*" frameborder="0" border="0" framespacing="0">
<frameset cols="150,*" frameborder="0" border="0" framespacing="0"> <frame name="menu" src="menu.html" marginheight="0" marginwidth="0" scrolling="auto" noresize>
<frame name="menu" src="menu.html" marginheight="0" marginwidth="0" scrolling="off" noresize> <frame name="content" src="/overview.php" marginheight="0" marginwidth="0" scrolling="auto" noresize>
<frame name="content" src="/viewdb.php" marginheight="0" marginwidth="0" scrolling="auto" noresize>
<! -- <frame name="footer" src="footer.html" scrolling="off"> --> <noframes>
<p>This section (everything between the 'noframes' tags) will only be displayed if the users' browser doesn't support frames. You can provide a link to a non-frames version of the website here. Feel free to use HTML tags within this section.</p>
</noframes>
<noframes> </frameset>
<p>This section (everything between the 'noframes' tags) will only be displayed if the users' browser doesn't support frames. You can provide a link to a non-frames version of the website here. Feel free to use HTML tags within this section.</p>
</noframes>
</frameset>
</html> </html>
+59 -54
View File
@@ -1,74 +1,79 @@
<html> <html>
<head> <head>
<title>HTML Frames Example - Menu</title> <title>HTML Frames Example - Menu</title>
<style type="text/css"> <style type="text/css">
a { a {
text-decoration:none; text-decoration:none;
margin: 0px 0px 0px 0px; margin: 0px 0px 0px 0px;
color:black; color:black;
font-size: small;
} }
body { body {
font-family:verdana,arial,sans-serif; font-family:verdana,arial,sans-serif;
font-size:medium; font-size:medium;
margin:10px; margin:10px;
background-color: rgb(119, 196, 135); background-color: rgb(119, 196, 135);
text-align: left;
padding-bottom: 30px;
} }
h3 { h3 {
margin: 0px 0px -15px 0px; margin: 0px 0px -15px 0px;
text-align: center; text-align: center;
} }
h4,h5 { h4,h5 {
text-align: center; text-align: center;
margin: 0px 0px 5px 0px; margin: 0px 0px 5px 0px;
} }
footer { footer {
position:absolute; background: rgb(119, 196, 135);
bottom:0; position: fixed;
left:0; padding-top: 10px;
width:100%; left: 0;
bottom: 0;
width:100%;
} }
hr { hr {
border-bottom: 1px solid black; border-bottom: 1px solid black;
} }
</style> body::-webkit-scrollbar {
</head> display:none
<body> }
<h5>Extractions</h5> </style>
<p style="font-size: small;text-align: center"> </head>
<a href="http://birdnetpi.local/By_Date/" target="content">By Date</a><br> <body>
<a href="http://birdnetpi.local/By_Common_Name/" target="content">By Common Name</a><br>
<a href="http://birdnetpi.local/By_Scientific_Name/" target="content">By Scientific Name</a><br>
<a href="http://birdnetpi.local/Processed/" target="content">Processed</a><br>
</p> <h5>Extractions</h5>
<hr class="solid"> - <a href="http://birdnetpi.local/By_Date/" target="content">By Date</a><br>
<h5>System Links</h5> - <a href="http://birdnetpi.local/By_Common_Name/" target="content">By Common Name</a><br>
<p style="font-size: small;text-align: center"> - <a href="http://birdnetpi.local/By_Scientific_Name/" target="content">By Scientific Name</a><br>
<a href="http://birdnetpi.local/scripts/" target="content">Tools</a><br> - <a href="http://birdnetpi.local/Processed/" target="content">Processed</a><br>
<a href="http://birdnetpi.local/phpsysinfo/" target="content">System Info</a><br> <hr class="solid">
<a href="http://birdnetpi.local:8080/" target="content">BirdNET-Lite Log</a><br> <h5>System Links</h5>
- <a href="http://birdnetpi.local/scripts/" target="content">Tools</a><br>
- <a href="http://birdnetpi.local/phpsysinfo/" target="content">System Info</a><br>
- <a href="http://birdnetpi.local:8080" target="content">BirdNET-Lite Log</a><br>
- <a href="http://birdnetpi.local:8888" target="content">Extraction Log</a><br>
<a href="http://birdnetpi.local:8888/" target="content">Extraction Log</a><br> <hr class="solid">
</p> <h5>External Links</h5>
<hr class="solid"> - <a href="https://app.birdweather.com" target="_content">BirdWeather</a><br>
<h5>External Links</h5> - <a href="https://github.com/mcguirepr89/BirdNET-Pi" target="_content">Repository</a><br>
<p style="font-size: small;text-align: center"> - <a href="https://github.com/mcguirepr89/BirdNET-Pi/wiki" target="_content">Wiki Help Page</a><br>
<a href="https://github.com/mcguirepr89/BirdNET-Pi" target="_content">Repository</a><br> - <a href="https://v2.wttr.in/" target="content">Wttr.in Report</a><br>
<a href="https://github.com/mcguirepr89/BirdNET-Pi/wiki" target="_content">Wiki Help Page</a><br> - <a href="https://www.birds.cornell.edu" target="_content">Cornell Lab of Ornithology</a><br>
<a href="https://wttr.in/" target="content">Wttr.in Report</a><br> <hr class="solid">
<a href="https://www.birds.cornell.edu" target="_content">Cornell Lab of Ornithology</a><br>
</p> <h5>Other<br>BirdNET-Pis</h5>
<hr class="solid"> - <a href="https://birdnetpi.pmcgui.xyz" target="_content">United States</a><br>
<h5>Other<br>BirdNET-Pis</h5> - <a href="https://birds.naturestation.net" target="_content">South Africa</a><br>
<a style="font-size: small;" href="https://birdnetpi.pmcgui.xyz" target="_content">United States,</a> - <a href="https://birdnetpigermany.hopto.org" target="_content">Germany</a>
<a style="font-size: small;" href="https://birds.naturestation.net" target="_content">South Africa,</a>
<a style="font-size: small;" href="https://birdnetpigermany.hopto.org" target="_content">Germany</a> </body>
</body> <footer style="font-size: small;">
<footer style="font-size: small;"> Icon by <a target="_content" style="font-weight: bold" href="https://www.freepik.com" title="Freepik">Freepik</a> from <a target="_content" style="font-weight: bold" href="https://www.flaticon.com/" title="Flaticon">Flaticon.com</a>
Icon by <a style="font-weight: bold" href="https://www.freepik.com" title="Freepik">Freepik</a> from <a style="font-weight: bold" href="https://www.flaticon.com/" title="Flaticon">Flaticon.com</a> </footer>
</footer>
</html> </html>
+13 -1
View File
@@ -324,9 +324,21 @@ footer {
</h1> </h1>
</header> </header>
<hr> <hr>
<h2>
<a href="/overview.php">
<span class="name">🐦 Overview</span>
</a>
</h2>
<hr style="border-top: dotted 2px #ccc;">
<h2>
<a href="/viewday.php">
<span class="name">🐦 Today's Top 10</span>
</a>
</h2>
<hr style="border-top: dotted 2px #ccc;">
<h2> <h2>
<a href="/viewdb.php"> <a href="/viewdb.php">
<span class="name">🐦 Recognized Birds</span> <span class="name">🐦 View the Database</span>
</a> </a>
</h2> </h2>
<hr style="border-top: dotted 2px #ccc;"> <hr style="border-top: dotted 2px #ccc;">
+61 -68
View File
@@ -1,18 +1,34 @@
/* style sheet */ /* style sheet */
* { * {
font-family: 'Arial', 'Gill Sans', 'Gill Sans MT',
' Calibri', 'Trebuchet MS', 'sans-serif';
box-sizing: border-box; box-sizing: border-box;
} }
.row { /* Create two equal columns that floats next to each other */
display: flex; .column2 {
margin-left: auto;
margin-right: auto;
width: 75%;
padding: 5px;
} }
/* Create two equal columns that floats next to each other */
.column { .column {
flex: 50%; float: left;
padding-right: 5px; width: 50%;
padding: 5px;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
} }
table { table {
background-color: rgb(219, 255, 235);
margin: 0 auto; margin: 0 auto;
font-size: large; font-size: large;
border-collapse: collapse; border-collapse: collapse;
@@ -22,82 +38,59 @@ table {
} }
h1 { h1 {
text-align: center; text-align: center;
color: black; color: black;
font-size: xx-large; font-size: xx-large;
font-family: 'Gill Sans', 'Gill Sans MT',
' Calibri', 'Trebuchet MS', 'sans-serif';
} }
h2 { h2 {
text-align: center; margin-left: -150px;
color: black; text-align: center;
font-size: large; color: black;
font-family: 'Gill Sans', 'Gill Sans MT', font-size: large;
' Calibri', 'Trebuchet MS', 'sans-serif'; }
h3 {
text-align: center;
color: black;
font-size: large;
} }
td { td {
background-color: rgb(119, 196, 135); background-color: rgb(219, 255, 235);
border: 1px solid black; font-weight: lighter;
border: 1px solid black;
padding: 10px;
text-align: center;
} }
th, th {
td { background-color: rgb(219, 255, 235);
font-weight: bold; font-weight: bold;
border: 1px solid black; border: 1px solid black;
padding: 10px; padding: 10px;
text-align: center; text-align: center;
background-color: rgb(219, 296, 235);
} }
@media screen and (max-width: 800px) { @media screen and (max-width: 600px) {
.column {
float: none;
width: 100%;
}
table {
margin: 0 auto;
font-size: medium;
border-collapse: collapse;
border-spacing: 1;
width: 100%;
border: 1px solid black;
}
h1 {
text-align: center;
color: black;
font-size: large;
font-family: 'Gill Sans', 'Gill Sans MT',
' Calibri', 'Trebuchet MS', 'sans-serif';
}
h2 { h2 {
text-align: center; margin-left: 0;
color: black; text-align: center;
font-size: large; color: black;
font-family: 'Gill Sans', 'Gill Sans MT', font-size: large;
' Calibri', 'Trebuchet MS', 'sans-serif';
} }
td {
background-color: rgb(119, 196, 135);
border: 1px solid black;
}
th,
td {
font-weight: bold;
border: 1px solid black;
padding: 10px;
text-align: center;
}
}
td { .column {
font-weight: lighter; width: 100%;
}
/* Create two equal columns that floats next to each other */
.column2 {
float: center;
width: 100%;
padding: 0px;
}
} }
body::-webkit-scrollbar { body::-webkit-scrollbar {
display:none display:none
}
+37 -32
View File
@@ -1,45 +1,50 @@
<html> <html>
<head> <head>
<title>BirdNET-Pi</title> <title>BirdNET-Pi</title>
<style type="text/css"> <style type="text/css">
a { a {
font-weight:bold; font-weight:bold;
text-decoration:none; text-decoration:none;
color:black; color:black;
} }
body { body {
text-align:center; text-align:center;
font-family:verdana,arial,sans-serif; font-family:verdana,arial,sans-serif;
font-size:medium; font-size:medium;
margin:10px; margin:10px;
background-color: rgb(119, 196, 135); background-color: rgb(119, 196, 135);
} }
#content { #content {
position: relative; position: relative;
} }
#content img { #content img {
position: absolute; position: absolute;
top: 0px; top: 0px;
left: 0px; left: 0px;
padding-top: 5px; padding-top: 5px;
padding-left: 10px; padding-left: 10px;
} }
footer { footer {
position: absolute; position: absolute;
bottom: 0px; bottom: 0px;
left: 0px; left: 0px;
right: 0px; right: 0px;
width: 100%; width: 100%;
} }
</style> </style>
</head> </head>
<body> <body>
<h1>BirdNET-Pi<img style="padding-left: 5px" src="images/version.svg" class="ribbon"/></h1> <a href="https://github.com/mcguirepr89/BirdNET-Pi" target="_content">
</div> <img alt="BirdNET-Pi" src="images/bird.png" style="position:absolute;left:32.5px;top:15px;">
<p> </a>
<a href="/viewdb.php" target="content">Database View</a> | <h1 style="padding-left:150px">BirdNET-Pi<img style="padding-left: 5px" src="images/version.svg" class="ribbon"/></h1>
<a href="/spectrogram.php" target="content">Spectrogram View</a> </div>
</p> <p style="padding-left:150px;">
</body> <a href="/overview.php" target="content">Overview</a> |
<a href="/viewdb.php" target="content">Database View</a> |
<a href="/viewday.php" target="content">Today View</a> |
<a href="/spectrogram.php" target="content">Spectrogram View</a>
</p>
</body>
</html> </html>
+41
View File
@@ -0,0 +1,41 @@
appdirs
audioread
certifi
cffi
charset-normalizer
colorama
cycler
decorator
idna
joblib
kiwisolver
librosa
llvmlite
matplotlib
mysql-connector-python
numba
numpy
packaging
pandas
Pillow
pip
pkg_resources
pooch
protobuf
pycparser
pyparsing
python-dateutil
pytz
requests
resampy
scikit-learn
scipy
seaborn
setuptools
six
SoundFile
tflite-runtime
threadpoolctl
tzlocal
urllib3
wheel
+54 -10
View File
@@ -91,18 +91,18 @@ run_analysis() {
if [ "${RECORDING_LENGTH}" == "01:00" ];then if [ "${RECORDING_LENGTH}" == "01:00" ];then
until [ "$(ffmpeg -i ${1}/${i} 2>&1 | awk -F. '/Duration/ {print $1}' | cut -d':' -f3-4)" == "${RECORDING_LENGTH}" ];do until [ "$(ffmpeg -i ${1}/${i} 2>&1 | awk -F. '/Duration/ {print $1}' | cut -d':' -f3-4)" == "${RECORDING_LENGTH}" ];do
sleep 1 sleep 1
[ $a -ge 60 ] && sudo rm -f ${1}/${i} && break [ $a -ge 60 ] && sudo rm -f ${1}/${i} && break
a=$((a+1)) a=$((a+1))
done done
else else
until [ "$(ffmpeg -i ${1}/${i} 2>&1 | awk -F. '/Duration/ {print $1}' | cut -d':' -f3-4)" == "00:${RECORDING_LENGTH}" ];do until [ "$(ffmpeg -i ${1}/${i} 2>&1 | awk -F. '/Duration/ {print $1}' | cut -d':' -f3-4)" == "00:${RECORDING_LENGTH}" ];do
sleep 1 sleep 1
[ $a -ge ${RECORDING_LENGTH} ] && sudo rm -f ${1}/${i} && break [ $a -ge ${RECORDING_LENGTH} ] && sudo rm -f ${1}/${i} && break
a=$((a+1)) a=$((a+1))
done done
fi fi
if [ -f ${1}/${i} ] && [ ! -f ${CUSTOM_LIST} ];then if [ -f ${1}/${i} ] && [ ! -f ${CUSTOM_LIST} ] && [ -z $BIRDWEATHER_ID ];then
echo "python3 analyze.py \ echo "python3 analyze.py \
--i "${1}/${i}" \ --i "${1}/${i}" \
--o "${1}/${i}.csv" \ --o "${1}/${i}.csv" \
@@ -119,9 +119,9 @@ run_analysis() {
--lon "${LONGITUDE}" \ --lon "${LONGITUDE}" \
--week "${WEEK}" \ --week "${WEEK}" \
--overlap "${OVERLAP}" \ --overlap "${OVERLAP}" \
--sensitivity "${SENSITIVITY}" \ --sensitivity "${SENSITIVITY}" \
--min_conf "${CONFIDENCE}" --min_conf "${CONFIDENCE}"
elif [ -f ${1}/${i} ] && [ -f ${CUSTOM_LIST} ];then elif [ -f ${1}/${i} ] && [ -f ${CUSTOM_LIST} ] && [ -z $BIRDWEATHER_ID ];then
echo "python3 analyze.py \ echo "python3 analyze.py \
--i "${1}/${i}" \ --i "${1}/${i}" \
--o "${1}/${i}.csv" \ --o "${1}/${i}.csv" \
@@ -139,10 +139,54 @@ run_analysis() {
--lon "${LONGITUDE}" \ --lon "${LONGITUDE}" \
--week "${WEEK}" \ --week "${WEEK}" \
--overlap "${OVERLAP}" \ --overlap "${OVERLAP}" \
--sensitivity "${SENSITIVITY}" \ --sensitivity "${SENSITIVITY}" \
--min_conf "${CONFIDENCE}" \ --min_conf "${CONFIDENCE}" \
--custom_list "${CUSTOM_LIST}" --custom_list "${CUSTOM_LIST}"
fi elif [ -f ${1}/${i} ] && [ ! -f ${CUSTOM_LIST} ] && [ ! -z $BIRDWEATHER_ID ];then
echo "python3 analyze.py \
--i "${1}/${i}" \
--o "${1}/${i}.csv" \
--lat "${LATITUDE}" \
--lon "${LONGITUDE}" \
--week "${WEEK}" \
--overlap "${OVERLAP}" \
--sensitivity "${SENSITIVITY}" \
--min_conf "${CONFIDENCE}" \
--birdweather_id IN_USE"
"${VENV}"/bin/python analyze.py \
--i "${1}/${i}" \
--o "${1}/${i}.csv" \
--lat "${LATITUDE}" \
--lon "${LONGITUDE}" \
--week "${WEEK}" \
--overlap "${OVERLAP}" \
--sensitivity "${SENSITIVITY}" \
--min_conf "${CONFIDENCE}" \
--birdweather_id "${BIRDWEATHER_ID}"
elif [ -f ${1}/${i} ] && [ -f ${CUSTOM_LIST} ] && [ ! -z $BIRDWEATHER_ID ];then
echo "python3 analyze.py \
--i "${1}/${i}" \
--o "${1}/${i}.csv" \
--lat "${LATITUDE}" \
--lon "${LONGITUDE}" \
--week "${WEEK}" \
--overlap "${OVERLAP}" \
--sensitivity "${SENSITIVITY}" \
--min_conf "${CONFIDENCE}" \
--custom_list "${CUSTOM_LIST}" \
--birdweather_id IN_USE"
"${VENV}"/bin/python analyze.py \
--i "${1}/${i}" \
--o "${1}/${i}.csv" \
--lat "${LATITUDE}" \
--lon "${LONGITUDE}" \
--week "${WEEK}" \
--overlap "${OVERLAP}" \
--sensitivity "${SENSITIVITY}" \
--min_conf "${CONFIDENCE}" \
--custom_list "${CUSTOM_LIST}" \
--birdweather_id "${BIRDWEATHER_ID}"
fi
done done
} }
+9 -1
View File
@@ -12,12 +12,13 @@ sudo systemctl stop birdnet_recording.service
echo "Removing all data . . . " echo "Removing all data . . . "
sudo rm -drf "${RECS_DIR}" sudo rm -drf "${RECS_DIR}"
sudo rm -f "${IDFILE}" sudo rm -f "${IDFILE}"
sudo rm -f $(dirname ${my_dir})/BirdDB.txt
echo "Recreating necessary directories" echo "Recreating necessary directories"
echo "Creating necessary directories"
[ -d ${EXTRACTED} ] || sudo -u ${USER} mkdir -p ${EXTRACTED} [ -d ${EXTRACTED} ] || sudo -u ${USER} mkdir -p ${EXTRACTED}
[ -d ${EXTRACTED}/By_Date ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Date [ -d ${EXTRACTED}/By_Date ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Date
[ -d ${EXTRACTED}/By_Common_Name ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Common_Name [ -d ${EXTRACTED}/By_Common_Name ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Common_Name
[ -d ${EXTRACTED}/By_Scientific_Name ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Scientific_Name [ -d ${EXTRACTED}/By_Scientific_Name ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Scientific_Name
[ -d ${EXTRACTED}/Charts ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/Charts
[ -d ${PROCESSED} ] || sudo -u ${USER} mkdir -p ${PROCESSED} [ -d ${PROCESSED} ] || sudo -u ${USER} mkdir -p ${PROCESSED}
sudo -u ${USER} ln -fs $(dirname ${my_dir})/homepage/* ${EXTRACTED} sudo -u ${USER} ln -fs $(dirname ${my_dir})/homepage/* ${EXTRACTED}
@@ -49,13 +50,20 @@ if [ ! -z ${BIRDNETPI_URL} ];then
fi fi
sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/spectrogram.php ${EXTRACTED} sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/spectrogram.php ${EXTRACTED}
sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/overview.php ${EXTRACTED}
sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/viewday.php ${EXTRACTED}
sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/viewdb.php ${EXTRACTED} sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/viewdb.php ${EXTRACTED}
sudo -u ${USER} ln -fs ${HOME}/phpsysinfo ${EXTRACTED} sudo -u ${USER} ln -fs ${HOME}/phpsysinfo ${EXTRACTED}
sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/phpsysinfo.ini ${HOME}/phpsysinfo/ sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/phpsysinfo.ini ${HOME}/phpsysinfo/
sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/green_bootstrap.css ${HOME}/phpsysinfo/templates/ sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/green_bootstrap.css ${HOME}/phpsysinfo/templates/
sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/index_bootstrap.html ${HOME}/phpsysinfo/templates/html sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/index_bootstrap.html ${HOME}/phpsysinfo/templates/html
echo "Setting Wttr.in URL to "${LATITUDE}", "${LONGITUDE}""
sudo -u${USER} sed -i "s/https:\/\/v2.wttr.in\//https:\/\/v2.wttr.in\/"${LATITUDE},${LONGITUDE}"/g" $(dirname ${my_dir})/homepage/menu.html
echo "Generating BirdDB.txt"
[ -f $(dirname ${my_dir})/BirdDB.txt ] || sudo -u ${USER} touch $(dirname ${my_dir})/BirdDB.txt
echo "Date;Time;Sci_Name;Com_Name;Confidence;Lat;Lon;Cutoff;Week;Sens;Overlap" | sudo -u ${BIRDNET_USER} tee -a $(dirname ${my_dir})/BirdDB.txt
sudo -u ${BIRDNET_USER} cp -f ${HOME}/BirdNET-Pi/homepage/index.html ${EXTRACTED}/ sudo -u ${BIRDNET_USER} cp -f ${HOME}/BirdNET-Pi/homepage/index.html ${EXTRACTED}/
echo "Dropping and re-creating database" echo "Dropping and re-creating database"
+4 -2
View File
@@ -39,5 +39,7 @@ GRANT ALL ON birds.* TO 'birder'@'localhost' IDENTIFIED BY '${DB_PWD}' WITH GRAN
FLUSH PRIVILEGES; FLUSH PRIVILEGES;
exit exit
EOF EOF
sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/analyze.py sudo -u${USER} sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/analyze.py
sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/viewdb.php sudo -u${USER} sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/viewdb.php
sudo -u${USER} sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/overview.php
sudo -u${USER} sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/viewday.php
+4 -2
View File
@@ -40,5 +40,7 @@ GRANT ALL ON birds.* TO 'birder'@'localhost' IDENTIFIED BY '${DB_PWD}' WITH GRAN
FLUSH PRIVILEGES; FLUSH PRIVILEGES;
exit exit
EOF EOF
sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/analyze.py sudo -u${USER} sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/analyze.py
sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/viewdb.php sudo -u${USER} sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/viewdb.php
sudo -u${USER} sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/viewday.php
sudo -u${USER} sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/overview.php
+154
View File
@@ -0,0 +1,154 @@
#!/home/pi/BirdNET-Pi/birdnet/bin/python3
import pandas as pd
import seaborn as sns
# import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LogNorm
from datetime import datetime
import textwrap
#Read database into Pandas dataframe
df = pd.read_csv('~/BirdNET-Pi/BirdDB.txt', sep=';')
#Convert Date and Time Fields to Panda's format
df['Date']=pd.to_datetime(df['Date'])
df['Time']=pd.to_datetime(df['Time'])
#Add round hours to dataframe
df['Hour of Day'] = [r.hour for r in df.Time]
#Create separate dataframes for separate locations
df_jhb=df[df.Lat > -32]
df_ec = df[df.Lat < -32]
#Get todays readings for Joburg
now = datetime.now()
df_jhb_today = df_jhb[df_jhb['Date']==now.strftime("%Y-%m-%d")]
# Definition to start getting top N detections - work in process
def filter_by_freq(df: pd.DataFrame, column: str, min_freq: int) -> pd.DataFrame:
"""Filters the DataFrame based on the value frequency in the specified column.
:param df: DataFrame to be filtered.
:param column: Column name that should be frequency filtered.
:param min_freq: Minimal value frequency for the row to be accepted.
:return: Frequency filtered DataFrame.
"""
# Frequencies of each value in the column.
freq = df[column].value_counts()
# Select frequent values. Value is in the index.
frequent_values = freq[freq >= min_freq].index
# Return only rows with value frequency above threshold.
return df[df[column].isin(frequent_values)]
#Get top readings today
min_valuecounts = 2
jhb_gt_min = filter_by_freq (df_jhb_today,'Com_Name', min_valuecounts)
jhb_gt_min_counts = jhb_gt_min['Com_Name'].value_counts()
print(jhb_gt_min_counts)
jhb_top10_today = (df_jhb_today['Com_Name'].value_counts()[:10])
df_jhb_top10_today = df_jhb_today[df_jhb_today.Com_Name.isin(jhb_top10_today.index)]
#Get bottom 10 today
jhb_bot10_today=(df_jhb_today['Com_Name'].value_counts()[-10:])
df_jhb_bot10_today = df_jhb_today[df_jhb_today.Com_Name.isin(jhb_bot10_today.index)]
#Set Palette for graphics
pal = "Greens"
#Set up plot axes and titles
f, axs = plt.subplots(1, 2, figsize = (10, 4), gridspec_kw=dict(width_ratios=[3, 5]))
plt.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0, hspace=None)
#Generate frequency plot
plot=sns.countplot(y='Com_Name', data = df_jhb_top10_today, palette = pal+"_r", order=pd.value_counts(df_jhb_top10_today['Com_Name']).iloc[:20].index, ax=axs[0])
#Try plot grid lines between bars - problem at the moment plots grid lines on bars - want between bars
# plot.grid(True, axis='y')
plot.set_yticklabels(['\n'.join(textwrap.wrap(ticklabel.get_text(),15)) for ticklabel in plot.get_yticklabels()])
plot.set(ylabel=None)
plot.set(xlabel="Detections")
#Generate crosstab matrix for heatmap plot
heat = pd.crosstab(df_jhb_top10_today['Com_Name'],df_jhb_top10_today['Hour of Day'])
#Order heatmap Birds by frequency of occurrance
heat.index = pd.CategoricalIndex(heat.index, categories = pd.value_counts(df_jhb_top10_today['Com_Name']).iloc[:10].index)
heat.sort_index(level=0, inplace=True)
hours_in_day = pd.Series(data = range(0,24))
heat_frame = pd.DataFrame(data=0, index=heat.index, columns = hours_in_day)
heat=(heat+heat_frame).fillna(0)
#Generatie heatmap plot
plot = sns.heatmap(heat, norm=LogNorm(), annot=True, annot_kws={"fontsize":7}, cmap = pal , square = False, cbar=False, linewidths = 0.5, linecolor = "Grey", ax=axs[1], yticklabels = False)
# Set heatmap border
for _, spine in plot.spines.items():
spine.set_visible(True)
plot.set(ylabel=None)
plot.set(xlabel="Hour of Day")
#Set combined plot layout and titles
plt.tight_layout()
f.subplots_adjust(top=0.9)
plt.suptitle("Last Updated: "+ str(now.strftime("%B, %d at %I:%M%P")))
#Save combined plot
savename='/home/pi/BirdSongs/Extracted/Charts/Combo-'+str(now.strftime("%d-%m-%Y"))+'.png'
plt.savefig(savename)
plt.close()
#Get bottom 10 today
jhb_bot10_today=(df_jhb_today['Com_Name'].value_counts()[-10:])
df_jhb_bot10_today = df_jhb_today[df_jhb_today.Com_Name.isin(jhb_bot10_today.index)]
#Set Palette for graphics
pal = "Reds"
#Set up plot axes and titles
f, axs = plt.subplots(1, 2, figsize = (8, 4), gridspec_kw=dict(width_ratios=[3, 5]))
#Generate frequency plot
plot=sns.countplot(y='Com_Name', data = df_jhb_bot10_today, palette = pal+"_r", order=pd.value_counts(df_jhb_bot10_today['Com_Name']).iloc[:10].index, ax=axs[0])
plot.set_yticklabels(['\n'.join(textwrap.wrap(ticklabel.get_text(),17)) for ticklabel in plot.get_yticklabels()])
plot.set(ylabel=None)
plot.set(xlabel="no. of detections")
#Generate crosstab matrix for heatmap plot
heat = pd.crosstab(df_jhb_bot10_today['Com_Name'],df_jhb_bot10_today['Hour of Day'])
#Order heatmap Birds by frequency of occurrance
heat.index = pd.CategoricalIndex(heat.index, categories = pd.value_counts(df_jhb_bot10_today['Com_Name']).iloc[:10].index)
heat.sort_index(level=0, inplace=True)
heat_frame = pd.DataFrame(data=0, index=heat.index, columns = hours_in_day)
heat=(heat+heat_frame).fillna(0)
#Generate heatmap plot
plot = sns.heatmap(heat, norm=LogNorm(), annot=True, annot_kws={"fontsize":7}, cmap = pal , square = False, cbar=False, linewidths = 0.5, linecolor = "Grey", ax=axs[1], yticklabels = False)
# Set heatmap border
for _, spine in plot.spines.items():
spine.set_visible(True)
plot.set(ylabel=None)
#Set combined plot layout and titles
plt.tight_layout()
f.subplots_adjust(top=0.9)
plt.suptitle("Bottom 10 Detected: "+ str(now.strftime("%d-%h-%Y %H:%M")))
plot.set(xlabel="Hour of Day")
#Save combined plot
savename='/home/pi/BirdSongs/Extracted/Charts/Combo2-'+str(now.strftime("%d-%m-%Y"))+'.png'
plt.savefig(savename)
plt.close()
+2 -2
View File
@@ -52,7 +52,6 @@ install_birdnet() {
source ./birdnet/bin/activate source ./birdnet/bin/activate
echo "Upgrading pip, wheel, and setuptools" echo "Upgrading pip, wheel, and setuptools"
pip3 install --upgrade pip wheel setuptools pip3 install --upgrade pip wheel setuptools
set -x
python_version="$(awk -F. '{print $2}' <(ls -l $(which /usr/bin/python3)))" python_version="$(awk -F. '{print $2}' <(ls -l $(which /usr/bin/python3)))"
echo "python_version=${python_version}" echo "python_version=${python_version}"
# TFLite Pre-built binaires from https://github.com/PINTO0309/TensorflowLite-bin # TFLite Pre-built binaires from https://github.com/PINTO0309/TensorflowLite-bin
@@ -67,13 +66,14 @@ set -x
echo "Installing the TFLite bin wheel" echo "Installing the TFLite bin wheel"
pip3 install --upgrade tflite_runtime-2.6.0-cp39-none-linux_aarch64.whl pip3 install --upgrade tflite_runtime-2.6.0-cp39-none-linux_aarch64.whl
fi fi
set +x
echo "Installing colorama==0.4.4" echo "Installing colorama==0.4.4"
pip3 install colorama==0.4.4 pip3 install colorama==0.4.4
echo "Installing librosa" echo "Installing librosa"
pip3 install librosa pip3 install librosa
echo "Installing mysql-connector-python" echo "Installing mysql-connector-python"
pip3 install mysql-connector-python pip3 install mysql-connector-python
echo "Making sure everything else is installed"
pip3 install -U -r /home/pi/BirdNET-Pi/requirements.txt
} }
read -sp "\ read -sp "\
+2 -1
View File
@@ -5,5 +5,6 @@ tar -vzxf noip-duc-linux.tar.gz
cd noip-2* cd noip-2*
make make
make install make install
sed '/^exit 0$/i \/usr\/local\/bin\/noip2' /etc/rc.local chmod a+wr /usr/local/etc/no-ip2.conf
sed -i '/^exit 0$/i \/usr\/local\/bin\/noip2' /etc/rc.local
noip2 -S noip2 -S
+37 -2
View File
@@ -36,9 +36,9 @@ install_mariadb() {
echo "Initializing the database" echo "Initializing the database"
source /etc/os-release source /etc/os-release
if [[ "${VERSION_CODENAME}" == "buster" ]];then if [[ "${VERSION_CODENAME}" == "buster" ]];then
${my_dir}/createdb_buster.sh USER=${USER} ${my_dir}/createdb_buster.sh
elif [[ "${VERSION_CODENAME}" == "bullseye" ]];then elif [[ "${VERSION_CODENAME}" == "bullseye" ]];then
${my_dir}/createdb_bullseye.sh USER=${USER} ${my_dir}/createdb_bullseye.sh
fi fi
} }
@@ -113,6 +113,7 @@ create_necessary_dirs() {
[ -d ${EXTRACTED}/By_Date ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Date [ -d ${EXTRACTED}/By_Date ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Date
[ -d ${EXTRACTED}/By_Common_Name ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Common_Name [ -d ${EXTRACTED}/By_Common_Name ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Common_Name
[ -d ${EXTRACTED}/By_Scientific_Name ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Scientific_Name [ -d ${EXTRACTED}/By_Scientific_Name ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Scientific_Name
[ -d ${EXTRACTED}/Charts ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/Charts
[ -d ${PROCESSED} ] || sudo -u ${USER} mkdir -p ${PROCESSED} [ -d ${PROCESSED} ] || sudo -u ${USER} mkdir -p ${PROCESSED}
sudo -u ${USER} ln -fs $(dirname ${my_dir})/homepage/* ${EXTRACTED} sudo -u ${USER} ln -fs $(dirname ${my_dir})/homepage/* ${EXTRACTED}
@@ -144,15 +145,29 @@ create_necessary_dirs() {
fi fi
sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/spectrogram.php ${EXTRACTED} sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/spectrogram.php ${EXTRACTED}
sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/viewday.php ${EXTRACTED}
sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/overview.php ${EXTRACTED}
sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/viewdb.php ${EXTRACTED} sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/viewdb.php ${EXTRACTED}
sudo -u ${USER} ln -fs ${HOME}/phpsysinfo ${EXTRACTED} sudo -u ${USER} ln -fs ${HOME}/phpsysinfo ${EXTRACTED}
sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/phpsysinfo.ini ${HOME}/phpsysinfo/ sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/phpsysinfo.ini ${HOME}/phpsysinfo/
sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/green_bootstrap.css ${HOME}/phpsysinfo/templates/ sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/green_bootstrap.css ${HOME}/phpsysinfo/templates/
sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/index_bootstrap.html ${HOME}/phpsysinfo/templates/html sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/index_bootstrap.html ${HOME}/phpsysinfo/templates/html
echo "Setting Wttr.in URL to "${LATITUDE}", "${LONGITUDE}""
sudo -u${USER} sed -i "s/https:\/\/v2.wttr.in\//https:\/\/v2.wttr.in\/"${LATITUDE},${LONGITUDE}"/g" $(dirname ${my_dir})/homepage/menu.html
} }
generate_BirdDB() {
echo "Generating BirdDB.txt"
if ! [ -f $(dirname ${my_dir})/BirdDB.txt ];then
sudo -u ${USER} touch $(dirname ${my_dir})/BirdDB.txt
echo "Date;Time;Sci_Name;Com_Name;Confidence;Lat;Lon;Cutoff;Week;Sens;Overlap" | sudo -u ${USER} tee -a $(dirname ${my_dir})/BirdDB.txt
elif ! grep Date $(dirname ${my_dir})/BirdDB.txt;then
sudo -u ${USER} sed -i '1 i\Date;Time;Sci_Name;Com_Name;Confidence;Lat;Lon;Cutoff;Week;Sens;Overlap' $(dirname ${my_dir})/BirdDB.txt
fi
}
install_alsa() { install_alsa() {
echo "Checking for alsa-utils and pulseaudio" echo "Checking for alsa-utils and pulseaudio"
if which arecord &> /dev/null ;then if which arecord &> /dev/null ;then
@@ -302,6 +317,24 @@ EOF
systemctl enable spectrogram_viewer.service systemctl enable spectrogram_viewer.service
} }
install_chart_viewer_service() {
echo "Installing the chart_viewer.service"
cat << EOF > /etc/systemd/system/chart_viewer.service
[Unit]
Description=BirdNET-Pi Chart Viewer Service
[Service]
Restart=always
RestartSec=300
Type=simple
User=pi
ExecStart=/usr/local/bin/daily_plot.py
[Install]
WantedBy=multi-user.target
EOF
systemctl enable chart_viewer.service
}
install_gotty_logs() { install_gotty_logs() {
echo "Installing GoTTY logging" echo "Installing GoTTY logging"
if ! which gotty &> /dev/null;then if ! which gotty &> /dev/null;then
@@ -492,6 +525,7 @@ install_selected_services() {
install_sox install_sox
install_mariadb install_mariadb
install_spectrogram_service install_spectrogram_service
install_chart_viewer_service
install_edit_birdnet_conf install_edit_birdnet_conf
install_pushed_notifications install_pushed_notifications
@@ -505,6 +539,7 @@ install_selected_services() {
fi fi
create_necessary_dirs create_necessary_dirs
generate_BirdDB
install_cleanup_cron install_cleanup_cron
} }
+128
View File
@@ -0,0 +1,128 @@
<?php
header("refresh: 300;");
$myDate = date('d-m-Y');
$user = 'birder';
$password = 'databasepassword';
$database = 'birds';
$servername='localhost';
$mysqli = new mysqli($servername, $user, $password, $database);
if ($mysqli->connect_error) {
die('Connect Error (' .
$mysqli->connect_errno . ') '.
$mysqli->connect_error);
}
// SQL query to select data from database
$sql0 = "SELECT * FROM detections";
$fulltable = $mysqli->query($sql0);
$totalcount = mysqli_num_rows($fulltable);
$sql1 = "SELECT Com_Name, Date, Time FROM detections
ORDER BY Date DESC, Time DESC LIMIT 1";
$mostrecent = $mysqli->query($sql1);
$sql2 = "SELECT * FROM detections
WHERE Date = CURDATE()";
$todaystable = $mysqli->query($sql2);
$todayscount = mysqli_num_rows($todaystable);
$sql3 = "SELECT * FROM detections
WHERE Date = CURDATE()
AND Time >= DATE_SUB(NOW(),INTERVAL 1 HOUR)";
$lasthourtable = $mysqli->query($sql3);
$lasthourcount = mysqli_num_rows($lasthourtable);
$sql4 = "SELECT Com_Name, Date, Time, MAX(Confidence)
FROM detections
WHERE Date = CURDATE()
GROUP BY Com_Name
ORDER BY MAX(Confidence) DESC";
$specieslist = $mysqli->query($sql4);
$speciescount = mysqli_num_rows($specieslist);
$mysqli->close();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Overview</title>
<!-- CSS FOR STYLING THE PAGE -->
<link rel="stylesheet" href="style.css">
<style>
.center {
display: block;
margin-left: 5px;
margin-right: 5px;
width: 90%;
padding: 5px;
}
.center2 {
display: block;
margin-left: 5px;
margin-right: 5px;
width: 100%;
padding: 5px;
}
</style>
</head>
<body style="background-color: rgb(119, 196, 135);">
<h2>Overview</h2>
<div class="row">
<div class="column2">
<?php // LOOP TILL END OF DATA
while($rows=$mostrecent ->fetch_assoc())
{
?>
<table>
<tr>
<th>Most Recent Detection</th>
<td><?php echo $rows['Com_Name'];?></td>
<td><?php echo $rows['Date'];?></td>
<td><?php echo $rows['Time'];?></td>
</tr>
</table>
</div>
</div>
<?php
}
?>
<div class="row">
<div class="column">
<table>
<tr>
<th></th>
<th>Total</th>
<th>Today</th>
<th>Last Hour</th>
</tr>
<tr>
<th>Number of Detections</th>
<td><?php echo $totalcount;?></td>
<td><?php echo $todayscount;?></td>
<td><?php echo $lasthourcount;?></td>
</tr>
</table>
</div>
<div class="column">
<table>
<tr>
<th>Species Detected Today</th>
<td><?php echo $speciescount;?></td>
</tr>
</table>
</div>
</div>
<h2>Today's Top 10 Species</h2>
<img src='/Charts/Combo-<?php echo $myDate;?>.png?nocache=<?php echo time();?>' style="width: 100%;padding: 5px;margin-left: auto;margin-right: auto;display: block;">
<h2>Currently Analyzing</h2>
<img src='/spectrogram.png?nocache=<?php echo time();?>' style="width: 100%;padding: 5px;">
</html>
+1 -1
View File
@@ -1,5 +1,5 @@
<?php <?php
header("refresh: 15;"); header("refresh: 15;");
echo "<body style='background-color:rgb(119, 196, 135)'>"; echo "<body style='background-color:rgb(119, 196, 135)'>";
echo "<img src='/spectrogram.png' >";
?> ?>
<img src='/spectrogram.png?nocache=<?php echo time();?>' style='display: block;margin-left: auto;margin-right: auto; height: 100%;'>
+3 -1
View File
@@ -4,7 +4,9 @@
services=(birdnet_recording.service services=(birdnet_recording.service
birdnet_analysis.service birdnet_analysis.service
extraction.timer) chart_viewer.service
extraction.timer
spectrogram_viewer.service)
for i in "${services[@]}";do for i in "${services[@]}";do
sudo systemctl stop ${i} sudo systemctl stop ${i}
+2
View File
@@ -9,3 +9,5 @@ git -C /home/pi/BirdNET-Pi checkout -f analyze.py
git -C /home/pi/BirdNET-Pi checkout -f scripts/viewdb.php git -C /home/pi/BirdNET-Pi checkout -f scripts/viewdb.php
sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/analyze.py sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/analyze.py
sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/viewdb.php sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/viewdb.php
sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/overview.php
sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/viewday.php
+2
View File
@@ -12,3 +12,5 @@ git -C /home/pi/BirdNET-Pi checkout -f analyze.py
git -C /home/pi/BirdNET-Pi checkout -f scripts/viewdb.php git -C /home/pi/BirdNET-Pi checkout -f scripts/viewdb.php
sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/analyze.py sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/analyze.py
sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/viewdb.php sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/viewdb.php
sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/overview.php
sed -i "s/databasepassword/${DB_PWD}/g" /home/pi/BirdNET-Pi/scripts/viewday.php
+38 -3
View File
@@ -7,7 +7,7 @@ USER=pi
HOME=/home/pi HOME=/home/pi
my_dir=${HOME}/BirdNET-Pi/scripts my_dir=${HOME}/BirdNET-Pi/scripts
tmpfile=$(mktemp) tmpfile=$(mktemp)
nomachine_url="https://download.nomachine.com/download/7.6/Arm/nomachine_7.6.2_3_arm64.deb" nomachine_url="https://download.nomachine.com/download/7.7/Arm/nomachine_7.7.4_1_arm64.deb"
gotty_url="https://github.com/yudai/gotty/releases/download/v1.0.1/gotty_linux_arm.tar.gz" gotty_url="https://github.com/yudai/gotty/releases/download/v1.0.1/gotty_linux_arm.tar.gz"
config_file="$(dirname ${my_dir})/birdnet.conf" config_file="$(dirname ${my_dir})/birdnet.conf"
@@ -35,9 +35,9 @@ install_mariadb() {
fi fi
source /etc/os-release source /etc/os-release
if [[ "${VERSION_CODENAME}" == "buster" ]];then if [[ "${VERSION_CODENAME}" == "buster" ]];then
${my_dir}/update_db_pwd_buster.sh USER=${USER} ${my_dir}/update_db_pwd_buster.sh
elif [[ "${VERSION_CODENAME}" == "bullseye" ]];then elif [[ "${VERSION_CODENAME}" == "bullseye" ]];then
${my_dir}/update_db_pwd_bullseye.sh USER=${USER} ${my_dir}/update_db_pwd_bullseye.sh
fi fi
} }
@@ -112,6 +112,7 @@ create_necessary_dirs() {
[ -d ${EXTRACTED}/By_Date ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Date [ -d ${EXTRACTED}/By_Date ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Date
[ -d ${EXTRACTED}/By_Common_Name ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Common_Name [ -d ${EXTRACTED}/By_Common_Name ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Common_Name
[ -d ${EXTRACTED}/By_Scientific_Name ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Scientific_Name [ -d ${EXTRACTED}/By_Scientific_Name ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/By_Scientific_Name
[ -d ${EXTRACTED}/Charts ] || sudo -u ${USER} mkdir -p ${EXTRACTED}/Charts
[ -d ${PROCESSED} ] || sudo -u ${USER} mkdir -p ${PROCESSED} [ -d ${PROCESSED} ] || sudo -u ${USER} mkdir -p ${PROCESSED}
sudo -u ${USER} ln -fs $(dirname ${my_dir})/homepage/* ${EXTRACTED} sudo -u ${USER} ln -fs $(dirname ${my_dir})/homepage/* ${EXTRACTED}
@@ -143,12 +144,26 @@ create_necessary_dirs() {
fi fi
sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/spectrogram.php ${EXTRACTED} sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/spectrogram.php ${EXTRACTED}
sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/viewday.php ${EXTRACTED}
sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/overview.php ${EXTRACTED}
sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/viewdb.php ${EXTRACTED} sudo -u ${USER} ln -fs $(dirname ${my_dir})/scripts/viewdb.php ${EXTRACTED}
sudo -u ${USER} ln -fs ${HOME}/phpsysinfo ${EXTRACTED} sudo -u ${USER} ln -fs ${HOME}/phpsysinfo ${EXTRACTED}
sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/phpsysinfo.ini ${HOME}/phpsysinfo/ sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/phpsysinfo.ini ${HOME}/phpsysinfo/
sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/green_bootstrap.css ${HOME}/phpsysinfo/templates/ sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/green_bootstrap.css ${HOME}/phpsysinfo/templates/
sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/index_bootstrap.html ${HOME}/phpsysinfo/templates/html sudo -u ${USER} cp -f $(dirname ${my_dir})/templates/index_bootstrap.html ${HOME}/phpsysinfo/templates/html
echo "Setting Wttr.in URL to "${LATITUDE}", "${LONGITUDE}""
sudo -u${USER} sed -i "s/https:\/\/v2.wttr.in\//https:\/\/v2.wttr.in\/"${LATITUDE},${LONGITUDE}"/g" $(dirname ${my_dir})/homepage/menu.html
}
generate_BirdDB() {
echo "Generating BirdDB.txt"
if ! [ -f $(dirname ${my_dir})/BirdDB.txt ];then
sudo -u ${USER} touch $(dirname ${my_dir})/BirdDB.txt
echo "Date;Time;Sci_Name;Com_Name;Confidence;Lat;Lon;Cutoff;Week;Sens;Overlap" | sudo -u ${USER} tee -a $(dirname ${my_dir})/BirdDB.txt
elif ! grep Date $(dirname ${my_dir})/BirdDB.txt;then
sudo -u ${USER} sed -i '1 i\Date;Time;Sci_Name;Com_Name;Confidence;Lat;Lon;Cutoff;Week;Sens;Overlap' $(dirname ${my_dir})/BirdDB.txt
fi
} }
install_alsa() { install_alsa() {
@@ -300,6 +315,24 @@ EOF
systemctl enable spectrogram_viewer.service systemctl enable spectrogram_viewer.service
} }
install_chart_viewer_service() {
echo "Installing the chart_viewer.service"
cat << EOF > /etc/systemd/system/chart_viewer.service
[Unit]
Description=BirdNET-Pi Chart Viewer Service
[Service]
Restart=always
RestartSec=300
Type=simple
User=pi
ExecStart=/usr/local/bin/daily_plot.py
[Install]
WantedBy=multi-user.target
EOF
systemctl enable chart_viewer.service
}
install_gotty_logs() { install_gotty_logs() {
echo "Installing GoTTY logging" echo "Installing GoTTY logging"
if ! which gotty &> /dev/null;then if ! which gotty &> /dev/null;then
@@ -489,6 +522,7 @@ install_selected_services() {
install_sox install_sox
install_mariadb install_mariadb
install_spectrogram_service install_spectrogram_service
install_chart_viewer_service
install_edit_birdnet_conf install_edit_birdnet_conf
install_pushed_notifications install_pushed_notifications
@@ -502,6 +536,7 @@ install_selected_services() {
fi fi
create_necessary_dirs create_necessary_dirs
generate_BirdDB
install_cleanup_cron install_cleanup_cron
} }
+98
View File
@@ -0,0 +1,98 @@
<?php
header("refresh: 300;");
$myDate = date('d-m-Y');
$user = 'birder';
$password = 'databasepassword';
$database = 'birds';
$servername='localhost';
$mysqli = new mysqli($servername, $user, $password, $database);
if ($mysqli->connect_error) {
die('Connect Error (' .
$mysqli->connect_errno . ') '.
$mysqli->connect_error);
}
// SQL query to select data from database
$sql1 = "SELECT * FROM detections
WHERE Date = CURDATE()
ORDER BY Date DESC, Time DESC";
$mosttable = $mysqli->query($sql1);
$sql2 = "SELECT * FROM detections
WHERE Date = CURDATE()";
$todaystable = $mysqli->query($sql2);
$todayscount=mysqli_num_rows($todaystable);
$sql3 = "SELECT * FROM detections
WHERE Date = CURDATE()
AND Time >= DATE_SUB(NOW(),INTERVAL 1 HOUR)";
$lasthourtable = $mysqli->query($sql3);
$lasthourcount=mysqli_num_rows($lasthourtable);
$sql4 = "SELECT Com_Name, Date, Time, MAX(Confidence)
FROM detections
WHERE Date = CURDATE()
GROUP BY Com_Name
ORDER BY MAX(Confidence) DESC";
$specieslist = $mysqli->query($sql4);
$speciescount=mysqli_num_rows($specieslist);
$mysqli->close();
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!-- <meta name="viewport" content="width=device-width, initial-scale=1"> -->
<title>Today's View</title>
<!-- CSS FOR STYLING THE PAGE -->
<link rel="stylesheet" href="style.css">
<style>
.center {
display: block;
margin-left: auto;
margin-right: auto;
width: 100%;
}
table,th,td {
background-color: rgb(219, 255, 235);
}
</style>
</head>
<img src='/Charts/Combo-<?php echo $myDate;?>.png?nocache=<?php echo time();?>' class="center">
<body style="background-color: rgb(119, 196, 135);">
<section>
<div class="row">
<div class="column2">
<table>
<tr>
<th></th>
<th>Today</th>
<th>Last Hour</th>
<th>Number of Unique Species Today</th>
</tr>
<tr>
<th>Number of Detections</th>
<td><?php echo $todayscount;?></td>
<td><?php echo $lasthourcount;?></td>
<td><?php echo $speciescount;?></td>
</tr>
</table>
</div>
</div>
</section>
</div>
</html>
+115 -120
View File
@@ -10,45 +10,45 @@ $servername='localhost';
$mysqli = new mysqli($servername, $user, $password, $database); $mysqli = new mysqli($servername, $user, $password, $database);
if ($mysqli->connect_error) { if ($mysqli->connect_error) {
die('Connect Error (' . die('Connect Error (' .
$mysqli->connect_errno . ') '. $mysqli->connect_errno . ') '.
$mysqli->connect_error); $mysqli->connect_error);
} }
// SQL query to select data from database // SQL query to select data from database
$sql = "SELECT * FROM detections $sql = "SELECT * FROM detections
ORDER BY Date DESC, Time DESC"; ORDER BY Date DESC, Time DESC";
$fulltable = $mysqli->query($sql); $fulltable = $mysqli->query($sql);
$totalcount=mysqli_num_rows($fulltable); $totalcount=mysqli_num_rows($fulltable);
$sql1 = "SELECT * FROM detections $sql1 = "SELECT * FROM detections
WHERE Date = CURDATE() WHERE Date = CURDATE()
ORDER BY Date DESC, Time DESC"; ORDER BY Date DESC, Time DESC";
$mosttable = $mysqli->query($sql1); $mosttable = $mysqli->query($sql1);
$sql2 = "SELECT * FROM detections $sql2 = "SELECT * FROM detections
WHERE Date = CURDATE()"; WHERE Date = CURDATE()";
$todaystable = $mysqli->query($sql2); $todaystable = $mysqli->query($sql2);
$todayscount=mysqli_num_rows($todaystable); $todayscount=mysqli_num_rows($todaystable);
$sql3 = "SELECT * FROM detections $sql3 = "SELECT * FROM detections
WHERE Date = CURDATE() WHERE Date = CURDATE()
AND Time >= DATE_SUB(NOW(),INTERVAL 1 HOUR)"; AND Time >= DATE_SUB(NOW(),INTERVAL 1 HOUR)";
$lasthourtable = $mysqli->query($sql3); $lasthourtable = $mysqli->query($sql3);
$lasthourcount=mysqli_num_rows($lasthourtable); $lasthourcount=mysqli_num_rows($lasthourtable);
$sql4 = "SELECT Com_Name, Date, Time, MAX(Confidence) $sql4 = "SELECT Com_Name, Date, Time, MAX(Confidence)
FROM detections FROM detections
GROUP BY Com_Name GROUP BY Com_Name
ORDER BY MAX(Confidence) DESC"; ORDER BY MAX(Confidence) DESC";
$specieslist = $mysqli->query($sql4); $specieslist = $mysqli->query($sql4);
$speciescount=mysqli_num_rows($specieslist); $speciescount=mysqli_num_rows($specieslist);
$sql5 = "SELECT Com_Name,COUNT(*) $sql5 = "SELECT Com_Name,COUNT(*)
AS Total AS Total
FROM detections FROM detections
GROUP BY Com_Name GROUP BY Com_Name
ORDER BY Total DESC"; ORDER BY Total DESC";
$speciestally = $mysqli->query($sql5); $speciestally = $mysqli->query($sql5);
$mysqli->close(); $mysqli->close();
@@ -58,122 +58,117 @@ $mysqli->close();
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<!-- <meta name="viewport" content="width=device-width, initial-scale=1"> --> <meta name="viewport" content="width=device-width, initial-scale=1">
<title>BirdNET-Pi DB</title> <title>BirdNET-Pi DB</title>
<!-- CSS FOR STYLING THE PAGE --> <link rel="stylesheet" href="style.css">
<link rel="stylesheet" href="style.css">
<style>
</style>
</head> </head>
<body style="background-color: rgb(119, 196, 135);background-image: linear-gradient(to top, rgb(119, 196, 135),black;"> <body style="background-color: rgb(119, 196, 135);">
<section> <section>
<h2>Number of Detections</h2>
<div class="row"> <div class="row">
<div cladd="column" style="width: 75%;padding-left: 15%;"> <div class="column2">
<h2>Number of Detections</h2> <table>
<table> <tr>
<tr> <th>Total</th>
<th>Total</th> <th>Today</th>
<th>Today</th> <th>Last Hour</th>
<th>Last Hour</th> <th>Number of Unique Species</th>
<th>Number of Unique Species</th> </tr>
</tr> <tr>
<tr> <td><?php echo $totalcount;?></td>
<td><?php echo $totalcount;?></td> <td><?php echo $todayscount;?></td>
<td><?php echo $todayscount;?></td> <td><?php echo $lasthourcount;?></td>
<td><?php echo $lasthourcount;?></td> <td><?php echo $speciescount;?></td>
<td><?php echo $speciescount;?></td> </tr>
</tr> </table>
</table>
</div> </div>
</div> </div>
<div class="row"> <h2>Today's Detections</h2>
<div class="column"> <!-- TABLE CONSTRUCTION-->
<h2>Detected Species</h2> <table>
<table> <tr>
<tr> <th>Time</th>
<th>Species</th> <th>Scientific Name</th>
<th>Date</th> <th>Common Name</th>
<th>Time</th> <th>Confidence</th>
<th>Max Confidence Score</th> <th>Lat</th>
</tr> <th>Lon</th>
<?php // LOOP TILL END OF DATA <th>Cutoff</th>
while($rows=$specieslist ->fetch_assoc()) <th>Week</th>
{ <th>Sens</th>
?> <th>Overlap</th>
<tr> </tr>
<td><?php echo $rows['Com_Name'];?></td> <!-- PHP CODE TO FETCH DATA FROM ROWS-->
<td><?php echo $rows['Date'];?></td>
<td><?php echo $rows['Time'];?></td>
<td><?php echo $rows['MAX(Confidence)'];?></td>
</tr>
<?php
}
?>
</table>
</div>
<div class="column">
<h2>Species Statistics</h2>
<table>
<tr>
<th>Species</th>
<th>Detections</th>
</tr>
<?php // LOOP TILL END OF DATA
while($rows=$speciestally ->fetch_assoc())
{
?>
<tr>
<td><?php echo $rows['Com_Name'];?></td>
<td><?php echo $rows['Total'];?></td>
</tr>
<?php
}
?>
</table>
</div>
</div>
<h2>Today's Detections</h2>
<!-- TABLE CONSTRUCTION-->
<table>
<tr>
<th>Time</th>
<th>Scientific Name</th>
<th>Common Name</th>
<th>Confidence</th>
<th>Lat</th>
<th>Lon</th>
<th>Cutoff</th>
<th>Week</th>
<th>Sens</th>
<th>Overlap</th>
</tr>
<!-- PHP CODE TO FETCH DATA FROM ROWS-->
<?php // LOOP TILL END OF DATA <?php // LOOP TILL END OF DATA
while($rows=$mosttable ->fetch_assoc()) while($rows=$mosttable ->fetch_assoc())
{ {
?> ?>
<tr> <tr>
<!--FETCHING DATA FROM EACH <!--FETCHING DATA FROM EACH
ROW OF EVERY COLUMN--> ROW OF EVERY COLUMN-->
<td><?php echo $rows['Time'];?></td> <td><?php echo $rows['Time'];?></td>
<td><?php echo $rows['Sci_Name'];?></td> <td><?php echo $rows['Sci_Name'];?></td>
<td><?php echo $rows['Com_Name'];?></td> <td><?php echo $rows['Com_Name'];?></td>
<td><?php echo $rows['Confidence'];?></td> <td><?php echo $rows['Confidence'];?></td>
<td><?php echo $rows['Lat'];?></td> <td><?php echo $rows['Lat'];?></td>
<td><?php echo $rows['Lon'];?></td> <td><?php echo $rows['Lon'];?></td>
<td><?php echo $rows['Cutoff'];?></td> <td><?php echo $rows['Cutoff'];?></td>
<td><?php echo $rows['Week'];?></td> <td><?php echo $rows['Week'];?></td>
<td><?php echo $rows['Sens'];?></td> <td><?php echo $rows['Sens'];?></td>
<td><?php echo $rows['Overlap'];?></td> <td><?php echo $rows['Overlap'];?></td>
</tr> </tr>
<?php <?php
} }
?> ?>
</table> </table>
</section> <div class="row">
<div class="column">
<h3>Detected Species</h3>
<table>
<tr>
<th>Species</th>
<th>Date</th>
<th>Time</th>
<th>Max Confidence Score</th>
</tr>
<?php // LOOP TILL END OF DATA
while($rows=$specieslist ->fetch_assoc())
{
?>
<tr>
<td><?php echo $rows['Com_Name'];?></td>
<td><?php echo $rows['Date'];?></td>
<td><?php echo $rows['Time'];?></td>
<td><?php echo $rows['MAX(Confidence)'];?></td>
</tr>
<?php
}
?>
</table>
</div>
<div class="column">
<h3>Species Statistics</h3>
<table>
<tr>
<th>Species</th>
<th>Detections</th>
</tr>
<?php // LOOP TILL END OF DATA
while($rows=$speciestally ->fetch_assoc())
{
?>
<tr>
<td><?php echo $rows['Com_Name'];?></td>
<td><?php echo $rows['Total'];?></td>
</tr>
<?php
}
?>
</div> </div>
</section>
</html> </html>
+1 -1
View File
@@ -28,7 +28,7 @@ overview() {
6) Updating the system to use your new birdnet.conf file" --no-wrap --icon-name=red-cardinal 6) Updating the system to use your new birdnet.conf file" --no-wrap --icon-name=red-cardinal
if [ $? -eq 0 ];then if [ $? -eq 0 ];then
exit 1 exit 0
elif [ $? -eq 1 ];then elif [ $? -eq 1 ];then
open_rpi_configuration && change_password open_rpi_configuration && change_password
fi fi
+10 -9
View File
@@ -57,8 +57,7 @@ SUDO_COMMANDS=false
; Example : BLOCKS="vitals,hardware,memory,filesystem,network,voltage,current,temperature,fans,power,other,ups" or BLOCKS=true //default order ; Example : BLOCKS="vitals,hardware,memory,filesystem,network,voltage,current,temperature,fans,power,other,ups" or BLOCKS=true //default order
; BLOCKS=false //hide all blocks ; BLOCKS=false //hide all blocks
; ;
BLOCKS=true BLOCKS="filesystem,memory,vitals,hardware,network,temperature,voltage,current,fans,power,other,ups"
; Maximum time in seconds a script is allowed to run before it is terminated by the parser ; Maximum time in seconds a script is allowed to run before it is terminated by the parser
; ;
;MAX_TIMEOUT=30 ;MAX_TIMEOUT=30
@@ -105,7 +104,7 @@ BLOCKS=true
; - Docker - show docker stats ; - Docker - show docker stats
; - Viewer - show output of any command or file viewer.tmp contents ; - Viewer - show output of any command or file viewer.tmp contents
; ;
PLUGINS=false PLUGINS="Viewer,PSStatus"
; ******************************** ; ********************************
@@ -248,7 +247,7 @@ SHOW_DEVICES_SERIAL=false
; - "UTC" shown as UTC string ; - "UTC" shown as UTC string
; - "locale" shown as Locale string ; - "locale" shown as Locale string
; ;
DATETIME_FORMAT="UTC" DATETIME_FORMAT="locale"
; ******************************** ; ********************************
@@ -336,7 +335,7 @@ SHOW_INODES=true
; Hide mounts ; Hide mounts
; Example : HIDE_MOUNTS="/home,/usr" ; Example : HIDE_MOUNTS="/home,/usr"
; ;
HIDE_MOUNTS="" HIDE_MOUNTS="/boot,/run,/run/lock,/run/user/1000,/dev/shm"
; Filesystem usage warning threshold in percent ; Filesystem usage warning threshold in percent
@@ -398,7 +397,7 @@ HIDE_TOTALS=false
; Example : HIDE_NETWORK_INTERFACE="eth0,sit0" ; Example : HIDE_NETWORK_INTERFACE="eth0,sit0"
; HIDE_NETWORK_INTERFACE=true //hide all network interfaces ; HIDE_NETWORK_INTERFACE=true //hide all network interfaces
; ;
HIDE_NETWORK_INTERFACE="" HIDE_NETWORK_INTERFACE="lo"
; Use a regular expression in the name of a hidden network interface (e.g. HIDE_NETWORK_INTERFACE="docker.*") ; Use a regular expression in the name of a hidden network interface (e.g. HIDE_NETWORK_INTERFACE="docker.*")
@@ -786,7 +785,7 @@ USE_REGEX=false
; ;
; string contains a list of process names that are checked, names are seperated by a comma (on WinNT names must end with '.exe') ; string contains a list of process names that are checked, names are seperated by a comma (on WinNT names must end with '.exe')
; ;
PROCESSES="mysqld, sshd, explorer.exe" PROCESSES="avahi-daemon,gotty,sshd,mariadbd,ffmpeg,vncserver-x11-serviced,nxd,bash"
[quotas] [quotas]
@@ -929,11 +928,13 @@ ACCESS="command"
; - "systeminfo" systeminfo command is run everytime the block gets refreshed or build (WinNT) ; - "systeminfo" systeminfo command is run everytime the block gets refreshed or build (WinNT)
; ;
COMMAND="" COMMAND="curl"
#COMMAND="cat"
; define COMMAND parameters (for command access) ; define COMMAND parameters (for command access)
; ;
PARAMS="" PARAMS="-s4 ifconfig.co"
#PARAMS="/home/pi/BirdNET-Pi/thisrun.txt"
[pingtest] [pingtest]
; PingTest Plugin configuration ; PingTest Plugin configuration
+10
View File
@@ -1,3 +1,13 @@
# main v.10 & pre-installed image notes
- New "BirdWeather" Chromium App (Pre-install image)
- New Infographics _chart_viewer.service_ (courtesy of @CaiusX)
- New "Overview"
- BirdWeather Support
- Bug Fix for systemd-networkd-wait-online.service
- Bug Fix for `install_noip2.sh` for NoIP DUC Support
- New `disk_check.sh` utitlity/crontab entry to `stop_core_services.sh`
when disk space is greater than 95%
# main v0.9 -- pre-installed image # main v0.9 -- pre-installed image
- Bug fix for Auto Access Point - Bug fix for Auto Access Point
- Improved Welcome Wizard - Improved Welcome Wizard