remove obsolete services

This commit is contained in:
frederik
2024-01-02 14:47:31 +01:00
parent 87e694ec14
commit da80128436
10 changed files with 13 additions and 901 deletions
-8
View File
@@ -297,14 +297,6 @@ if(isset($_GET['view'])){
'sudo systemctl restart birdnet_log.service',
'sudo systemctl disable --now birdnet_log.service',
'sudo systemctl enable --now birdnet_log.service',
'sudo systemctl stop extraction.service',
'sudo systemctl restart extraction.service',
'sudo systemctl disable --now extraction.service',
'sudo systemctl enable --now extraction.service',
'sudo systemctl stop birdnet_server.service',
'sudo systemctl restart birdnet_server.service',
'sudo systemctl disable --now birdnet_server.service',
'sudo systemctl enable --now birdnet_server.service',
'sudo systemctl stop birdnet_analysis.service',
'sudo systemctl restart birdnet_analysis.service',
'sudo systemctl disable --now birdnet_analysis.service',
-123
View File
@@ -1,123 +0,0 @@
import argparse
import socket
HEADER = 64
PORT = 5050
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = "!DISCONNECT"
SERVER = "localhost"
ADDR = (SERVER, PORT)
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(ADDR)
def send(msg):
message = msg.encode(FORMAT)
msg_length = len(message)
send_length = str(msg_length).encode(FORMAT)
send_length += b' ' * (HEADER - len(send_length))
client.send(send_length)
client.send(message)
print(client.recv(2048).decode(FORMAT))
def main():
global INCLUDE_LIST
global EXCLUDE_LIST
# Parse passed arguments
parser = argparse.ArgumentParser()
parser.add_argument('--i', help='Path to input file.')
parser.add_argument(
'--o',
default='result.csv',
help='Path to output file. Defaults to result.csv.')
parser.add_argument(
'--lat',
type=float,
default=-1,
help='Recording location latitude. Set -1 to ignore.')
parser.add_argument(
'--lon',
type=float,
default=-1,
help='Recording location longitude. Set -1 to ignore.')
parser.add_argument(
'--week',
type=int,
default=-1,
help='Week of the year when the recording was made. Values in [1, 48] (4 weeks per month). Set -1 to ignore.')
parser.add_argument(
'--overlap',
type=float,
default=0.0,
help='Overlap in seconds between extracted spectrograms. Values in [0.0, 2.9]. Defaults tp 0.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(
'--include_list',
default='null',
help='Path to text file containing a list of included species. Not used if not provided.')
parser.add_argument(
'--exclude_list',
default='null',
help='Path to text file containing a list of excluded species. Not used if not provided.')
parser.add_argument(
'--birdweather_id',
default='99999',
help='Private Station ID for BirdWeather.')
args = parser.parse_args()
sockParams = ''
if args.i:
sockParams += 'i=' + args.i + '||'
if args.o:
sockParams += 'o=' + args.o + '||'
if args.birdweather_id:
sockParams += 'birdweather_id=' + args.birdweather_id + '||'
if args.include_list:
sockParams += 'include_list=' + args.include_list + '||'
if args.exclude_list:
sockParams += 'exclude_list=' + args.exclude_list + '||'
if args.overlap:
sockParams += 'overlap=' + str(args.overlap) + '||'
if args.week:
sockParams += 'week=' + str(args.week) + '||'
if args.sensitivity:
sockParams += 'sensitivity=' + str(args.sensitivity) + '||'
if args.min_conf:
sockParams += 'min_conf=' + str(args.min_conf) + '||'
if args.lat:
sockParams += 'lat=' + str(args.lat) + '||'
if args.lon:
sockParams += 'lon=' + str(args.lon) + '||'
send(sockParams)
send(DISCONNECT_MESSAGE)
# time.sleep(3)
###############################################################################
###############################################################################
if __name__ == '__main__':
main()
# Example calls
# python3 analyze.py --i 'example/XC558716 - Soundscape.mp3' --lat 35.4244 --lon -120.7463 --week 18
# python3 analyze.py --i 'example/XC563936 - Soundscape.mp3' --lat 47.6766
# --lon -122.294 --week 11 --overlap 1.5 --min_conf 0.25 --sensitivity
# 1.25 --custom_list 'example/custom_species_list.txt'
-196
View File
@@ -1,196 +0,0 @@
#!/usr/bin/env -S --default-signal=PIPE bash
# Runs BirdNET-Lite
#set -x
source /etc/birdnet/birdnet.conf
# Document this run's birdnet.conf settings
# Make a temporary file to compare the current birdnet.conf with
# the birdnet.conf as it was the last time this script was called
my_dir=$HOME/BirdNET-Pi/scripts
if [ -z ${THIS_RUN} ];then THIS_RUN=$my_dir/thisrun.txt;fi
[ -f ${THIS_RUN} ] || touch ${THIS_RUN} && chmod g+w ${THIS_RUN}
if [ -z ${LAST_RUN} ];then LAST_RUN=$my_dir/lastrun.txt;fi
[ -z ${LATITUDE} ] && echo "LATITUDE not set, exiting 1" && exit 1
[ -z ${LONGITUDE} ] && echo "LONGITUDE not set, exiting 1" && exit 1
make_thisrun() {
sleep .4
awk '!/#/ && !/^$/ {print}' /etc/birdnet/birdnet.conf \
> >(tee "${THIS_RUN}")
sleep .5
}
make_thisrun &> /dev/null
if ! diff ${LAST_RUN} ${THIS_RUN};then
echo "The birdnet.conf file has changed"
if grep REC <(diff $LAST_RUN $THIS_RUN);then
echo "Recording element changed -- restarting 'birdnet_recording.service'"
sudo systemctl stop birdnet_recording.service
sudo rm -rf ${RECS_DIR}/$(date +%B-%Y/%d-%A)/*
sudo systemctl start birdnet_recording.service
fi
cat ${THIS_RUN} > ${LAST_RUN}
fi
INCLUDE_LIST="$HOME/BirdNET-Pi/include_species_list.txt"
EXCLUDE_LIST="$HOME/BirdNET-Pi/exclude_species_list.txt"
if [ ! -f ${INCLUDE_LIST} ];then
touch ${INCLUDE_LIST} &&
chmod g+rw ${INCLUDE_LIST}
fi
if [ ! -f ${EXCLUDE_LIST} ];then
touch ${EXCLUDE_LIST} &&
chmod g+rw ${EXCLUDE_LIST}
fi
if [ "$(du ${INCLUDE_LIST} | awk '{print $1}')" -lt 4 ];then
INCLUDE_LIST=null
fi
if [ "$(du ${EXCLUDE_LIST} | awk '{print $1}')" -lt 4 ];then
EXCLUDE_LIST=null
fi
# Create an array of the audio files
# Takes one argument:
# - {DIRECTORY}
get_files() {
files=($( find ${1} -maxdepth 1 -name '*wav' ! -size 0\
| sort \
| head -n 20 \
| awk -F "/" '{print $NF}' ))
[ -n "${files[1]}" ] && echo "Files loaded"
}
# Move all files that have been analyzed already into newly created "Analyzed"
# directory
# Takes one argument:
# - {DIRECTORY}
move_analyzed() {
for i in "${files[@]}";do
j="${i}.csv"
if [ -f "${1}/${j}" ];then
if [ ! -d "${1}-Analyzed" ];then
mkdir -p "${1}-Analyzed" && echo "'Analyzed' directory created"
fi
mv "${1}/${i}" "${1}-Analyzed/"
mv "${1}/${j}" "${1}-Analyzed/"
fi
done
}
# Run BirdNET-Lite on the WAVE files from get_files()
# Uses one argument:
# - {DIRECTORY}
run_analysis() {
PYTHON_VIRTUAL_ENV="$HOME/BirdNET-Pi/birdnet/bin/python3"
DIR="$HOME/BirdNET-Pi/scripts"
sleep .5
### TESTING NEW WEEK CALCULATION
WEEK_OF_YEAR="$(echo "($(date +%m)-1) * 4" | bc -l)"
DAY_OF_MONTH="$(date +%d)"
if [ ${DAY_OF_MONTH} -le 7 ];then
WEEK="$(echo "${WEEK_OF_YEAR} + 1" |bc -l)"
elif [ ${DAY_OF_MONTH} -le 14 ];then
WEEK="$(echo "${WEEK_OF_YEAR} + 2" |bc -l)"
elif [ ${DAY_OF_MONTH} -le 21 ];then
WEEK="$(echo "${WEEK_OF_YEAR} + 3" |bc -l)"
elif [ ${DAY_OF_MONTH} -ge 22 ];then
WEEK="$(echo "${WEEK_OF_YEAR} + 4" |bc -l)"
fi
for i in "${files[@]}";do
[ ! -f ${1}/${i} ] && continue
echo "${1}/${i}" > $HOME/BirdNET-Pi/analyzing_now.txt
[ -z ${RECORDING_LENGTH} ] && RECORDING_LENGTH=15
echo "RECORDING_LENGTH set to ${RECORDING_LENGTH}"
itr=0
until [ -z "$(lsof -t ${1}/${i})" ];do
itr=$((itr+1))
if [ $itr -eq $(($RECORDING_LENGTH * 3)) ]; then
echo "Maximum number of attempts exceeded. Exiting & restarting service."
exit
fi
sleep 2
done
if ! grep 5050 <(netstat -tulpn 2>&1) &> /dev/null 2>&1;then
echo "Waiting for socket"
until grep 5050 <(netstat -tulpn 2>&1) &> /dev/null 2>&1;do
sleep 1
done
fi
# prepare optional parameters for analyze.py
if [ -f ${INCLUDE_LIST} ]; then
INCLUDEPARAM="--include_list ${INCLUDE_LIST}"
else
INCLUDEPARAM=""
fi
if [ -f ${EXCLUDE_LIST} ]; then
EXCLUDEPARAM="--exclude_list ${EXCLUDE_LIST}"
else
EXCLUDEPARAM=""
fi
if [ ! -z $BIRDWEATHER_ID ]; then
BIRDWEATHER_ID_PARAM="--birdweather_id ${BIRDWEATHER_ID}"
BIRDWEATHER_ID_LOG="--birdweather_id \"IN_USE\""
else
BIRDWEATHER_ID_PARAM=""
BIRDWEATHER_ID_LOG=""
fi
echo $PYTHON_VIRTUAL_ENV "$DIR/analyze.py" \
--i "${1}/${i}" \
--o "${1}/${i}.csv" \
--lat $(echo "${LATITUDE}" | awk '{print int($1+0.5)}').XX \
--lon $(echo "${LONGITUDE}" | awk '{print int($1+0.5)}').XX \
--week "${WEEK}" \
--overlap "${OVERLAP}" \
--sensitivity "${SENSITIVITY}" \
--min_conf "${CONFIDENCE}" \
${INCLUDEPARAM} \
${EXCLUDEPARAM} \
${BIRDWEATHER_ID_LOG}
$PYTHON_VIRTUAL_ENV $DIR/analyze.py \
--i "${1}/${i}" \
--o "${1}/${i}.csv" \
--lat "${LATITUDE}" \
--lon "${LONGITUDE}" \
--week "${WEEK}" \
--overlap "${OVERLAP}" \
--sensitivity "${SENSITIVITY}" \
--min_conf "${CONFIDENCE}" \
${INCLUDEPARAM} \
${EXCLUDEPARAM} \
${BIRDWEATHER_ID_PARAM}
if [ ! -z $HEARTBEAT_URL ]; then
echo "Performing Heartbeat"
IP=`curl -s ${HEARTBEAT_URL}`
echo "Heartbeat: $IP"
fi
done
}
# The three main functions
# Takes one argument:
# - {DIRECTORY}
run_birdnet() {
get_files "${1}"
move_analyzed "${1}"
run_analysis "${1}"
}
until grep 5050 <(netstat -tulpn 2>&1) &> /dev/null 2>&1;do
sleep 1
done
if [ $(find ${RECS_DIR}/StreamData -maxdepth 1 -name '*wav' 2>/dev/null| wc -l) -gt 0 ];then
find $RECS_DIR -maxdepth 1 -name '*wav' -type f -size 0 -delete
run_birdnet "${RECS_DIR}/StreamData"
fi
YESTERDAY="$RECS_DIR/$(date --date="yesterday" "+%B-%Y/%d-%A")"
TODAY="$RECS_DIR/$(date "+%B-%Y/%d-%A")"
if [ $(find ${YESTERDAY} -name '*wav' 2>/dev/null | wc -l) -gt 0 ];then
find $YESTERDAY -name '*wav' -type f -size 0 -delete
run_birdnet "${YESTERDAY}"
elif [ $(find ${TODAY} -name '*wav' 2>/dev/null | wc -l) -gt 0 ];then
find $TODAY -name '*wav' -type f -size 0 -delete
run_birdnet "${TODAY}"
fi
+1 -1
View File
@@ -1,2 +1,2 @@
#!/usr/bin/env bash
journalctl --no-hostname -q -o short -fu birdnet_analysis -ubirdnet_server -uextraction | sed "s/$(date "+%b %d ")//g;s/${HOME//\//\\/}\///g;/Line/d;/find/d;/systemd/d;s/ .*\[.*\]: /---/"
journalctl --no-hostname -q -o short -fu birdnet_analysis | sed "s/$(date "+%b %d ")//g;s/${HOME//\//\\/}\///g;/Line/d;/find/d;/systemd/d;s/ .*\[.*\]: /---/"
-1
View File
@@ -11,7 +11,6 @@ my_dir=${HOME}/BirdNET-Pi/scripts
echo "Stopping services"
sudo systemctl stop birdnet_recording.service
sudo systemctl stop birdnet_analysis.service
sudo systemctl stop birdnet_server.service
echo "Removing all data . . . "
sudo rm -drf "${RECS_DIR}"
sudo rm -f "${IDFILE}"
-163
View File
@@ -1,163 +0,0 @@
#!/usr/bin/env bash
# Exit when any command fails
#set -x
set -e
# Keep track of the last executed command
#trap 'last_command=$current_command; current_command=$BASH_COMMAND' DEBUG
## Echo an error message before exiting
#trap 'echo "\"${last_command}\" command exited with code $?."' EXIT
# Remove temporary file
trap 'rm -f $TMPFILE' EXIT
source /etc/birdnet/birdnet.conf
[ -z ${RECORDING_LENGTH} ] && RECORDING_LENGTH=15
# Set Variables
TMPFILE=$(mktemp)
#SCAN_DIRS are all directories marked "Analyzed"
SCAN_DIRS=($(find $RECS_DIR -type d -name '*Analyzed' 2>/dev/null | sort ))
for h in "${SCAN_DIRS[@]}";do
# The TMPFILE is created from each .csv file BirdNET creates
# within each "Analyzed" directory
# Field 1: Start (s)
# Field 2: End (s)
# Field 3: Scientific name
# Field 4: Common name
# Field 5: Confidence
# Iterates over each "Analyzed" directory
for i in $(find ${h} -name '*csv' 2>/dev/null | sort );do
# Iterates over each '.csv' file found in each "Analyzed" directory
# to create the TMPFILE
echo "$(basename ${i})" >> ${TMPFILE}
sort -k1n -t\; "${i}" | awk '!/Start/{print}' >> ${TMPFILE}
done
# The extraction reads each line of the TMPFILE and sets the variables ffmpeg
# will use.
while read -r line;do
echo "Line = $line"
DATE="$(echo "${line}" \
| awk -F- '/birdnet/{print $1"-"$2"-"$3}')"
if [ ! -z ${DATE} ];then
OLDFILE="$(echo "${line}" | awk -F. '/birdnet/{print $1"."$2}')" ; continue
fi
if [ -z ${DATE} ];then
DATE=$(date "+%F")
fi
START="$(echo "${line}" | awk -F\; '!/birdnet/{print $1}')"
END="$(echo "${line}" | awk -F\; '!/birdnet/{print $2}')"
COMMON_NAME=""$(echo ${line} \
| awk -F\; '!/birdnet/{print $4}'|tr -d "'")""
SCIENTIFIC_NAME=""$(echo ${line} \
| awk -F\; '!/birdnet/{print $3}')""
CONFIDENCE=""$(echo ${line} \
| awk -F\; '{print $5}')""
#CONFIDENCE_SCORE="${CONFIDENCE:0:2}%"
locale_decimal=$(locale decimal_point)
if [[ $locale_decimal == "." ]]; then
CONFIDENCE_SCORE="$(printf %.0f "$(echo "scale=2; ${CONFIDENCE} * 100" | bc)")"
else
CONFIDENCE_SCORE="$(printf %.0f "$(echo "scale=2; "${CONFIDENCE}" * 100" | bc | tr '.' ',')")"
fi
NEWFILE="${COMMON_NAME// /_}-${CONFIDENCE_SCORE}-${OLDFILE//.wav/.${AUDIOFMT}}"
echo "NEWFILE=$NEWFILE"
NEWSPECIES_BYDATE="${EXTRACTED}/By_Date/${DATE}/${COMMON_NAME// /_}"
# If the extracted file already exists, move on
if [[ -f "${NEWSPECIES_BYDATE}/${NEWFILE}" ]];then
echo "Extraction exists. Moving on"
continue
fi
# Before extracting the "Selection," the script checks to be sure the
# original WAVE file still exists.
[[ -f "${h}/${OLDFILE}" ]] || continue
# If a directory does not already exist for the species (by date),
# it is created
[[ -d "${NEWSPECIES_BYDATE}" ]] || mkdir -p "${NEWSPECIES_BYDATE}"
# If there are already 20 extracted entries for a given species
# for today, remove the oldest file and create the new one.
# if [[ "$(find ${NEWSPECIES_BYDATE} | wc -l)" -ge 20 ]];then
# echo "20 ${SPECIES}s, already! Removing the oldest by-date and making a new one"
# cd ${NEWSPECIES_BYDATE} || exit 1
# ls -1t . | tail -n +20 | xargs -r rm -vv
# fi
# If the above tests have passed, then the extraction happens.
# After creating the extracted files by-date, and a directory tree
# structured by-species, symbolic links are made to populate the new
# directory.
# This section sets the SPACER that will be used to pad the audio clip with
# context. If EXTRACTION_LENGTH is 10, for instance, 3 seconds are removed
# from that value and divided by 2, so that the 3 seconds of the call are
# within 3.5 seconds of audio context before and after.
[ -z ${EXTRACTION_LENGTH} ] && EXTRACTION_LENGTH=6
SPACER=$(echo "scale=1;(${EXTRACTION_LENGTH} - 3 )/2" |bc -l)
START=$(echo "scale=1;${START} - ${SPACER}"|bc -l)
END=$(echo "scale=1;${END} + ${SPACER}"|bc -l)
# If the SPACER would have the START value less that 0, start at the
# beginning of the audio file. If the SPACER would make the END value
# exceed the end of the audio file, end the extraction at the end of the
# audio file.
if (( $(echo "${START} < 1" | bc -l) ));then START=0;fi
if (( $(echo "${END} > ${RECORDING_LENGTH}" | bc -l) ));then END=${RECORDING_LENGTH};fi
if [ "${RECORDING_LENGTH}" == "${EXTRACTION_LENGTH}" ];then
START=0
END=${RECORDING_LENGTH}
fi
sox -V1 "${h}/${OLDFILE}" "${NEWSPECIES_BYDATE}/${NEWFILE}" \
trim ="${START}" ="${END}"
RAW_SPECTROGRAM=${RAW_SPECTROGRAM}
# Check if RAW_SPECTROGRAM is 1
if [ "$RAW_SPECTROGRAM" == "1" ]; then
# If it is, add "-r" as an argument to the SOX command
sox -V1 "${NEWSPECIES_BYDATE}/${NEWFILE}" -n remix 1 rate 24k spectrogram \
-t "${COMMON_NAME}" \
-c "${NEWSPECIES_BYDATE//$HOME\/}/${NEWFILE}" \
-o "${NEWSPECIES_BYDATE}/${NEWFILE}.png" \
-r
else
# If it's not, run the SOX command without the "-r" argument
sox -V1 "${NEWSPECIES_BYDATE}/${NEWFILE}" -n remix 1 rate 24k spectrogram \
-t "$(echo "${COMMON_NAME}" | iconv -f utf8 -t ascii//TRANSLIT)" \
-c "${NEWSPECIES_BYDATE//$HOME\/}/${NEWFILE}" \
-o "${NEWSPECIES_BYDATE}/${NEWFILE}.png"
fi
done < "${TMPFILE}"
# Once each line of the TMPFILE has been processed, the TMPFILE is emptied
# for the next iteration of the for loop.
>"${TMPFILE}"
# Rename files that have been processed so that they are not processed on the
# next extraction.
[[ -d "${PROCESSED}" ]] || mkdir "${PROCESSED}"
#echo "Moving processed files to ${PROCESSED}"
mv ${h}/* ${PROCESSED} &> /dev/null || true
# Removes old directories
if echo "${h}" | grep $(date --date="-2 day" "+%A") &> /dev/null;then
echo "Removing old directories"
rm -drf "${h}"
rm -drf "$(echo ${h} | cut -d'-' -f1-3)"
fi
done
#echo "Linking Processed files to "${EXTRACTED}/Processed" web directory"
# After all audio extractions have taken place, a directory is created to house
# the original WAVE and .txt files used for this extraction processs.
if [[ ! -L ${EXTRACTED}/Processed ]] || [[ ! -e ${EXTRACTED}/Processed ]];then
ln -sf ${PROCESSED} ${EXTRACTED}/Processed
fi
+4 -25
View File
@@ -5,14 +5,13 @@ set -x
my_dir=$HOME/BirdNET-Pi/scripts
sudo systemctl stop birdnet_server.service
sudo systemctl stop birdnet_recording.service
services=(chart_viewer.service
spectrogram_viewer.service
icecast2.service
extraction.service
birdnet_recording.service
birdnet_analysis.service
birdnet_log.service
birdnet_stats.service)
@@ -20,31 +19,11 @@ for i in "${services[@]}";do
sudo systemctl restart "${i}"
done
sudo systemctl start birdnet_server.service
sleep 5
for i in {1..5}; do
# We want to loop here (5*5seconds) until the server is running and listening on its port
systemctl is-active --quiet birdnet_server.service \
&& grep 5050 <(netstat -tulpn 2>&1) \
&& logger "[$0] birdnet_server.service is running" \
# We want to loop here (5*5seconds) until the birdnet_analysis.service is running
systemctl is-active --quiet birdnet_analysis.service \
&& logger "[$0] birdnet_analysis.service is running" \
&& break
sleep 5
done
# Let's check a final time to ensure the server is running
systemctl is-active --quiet birdnet_server.service && grep 5050 <(netstat -tulpn 2>&1)
status=$?
if (( status != 0 )); then
logger "[$0] Unable to start birdnet_server.service... Looping until it start properly"
until grep 5050 <(netstat -tulpn 2>&1);do
sudo systemctl restart birdnet_server.service
sleep 45
done
fi
# Finally start the birdnet_analysis.service
sudo systemctl restart birdnet_analysis.service
+4 -364
View File
@@ -1,23 +1,13 @@
import re
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 librosa
import operator
import socket
import threading
import os
import gzip
import time
import librosa
import numpy as np
from utils.helpers import get_settings, Detection
from utils.notifications import sendAppriseNotifications
from utils.parse_settings import config_to_settings
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
os.environ['CUDA_VISIBLE_DEVICES'] = ''
@@ -27,47 +17,13 @@ try:
except BaseException:
from tensorflow import lite as tflite
HEADER = 64
PORT = 5050
SERVER = "localhost"
ADDR = (SERVER, PORT)
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = "!DISCONNECT"
userDir = os.path.expanduser('~')
DB_PATH = userDir + '/BirdNET-Pi/scripts/birds.db'
INTERPRETER, INCLUDE_LIST, EXCLUDE_LIST = (None, None, None)
PREDICTED_SPECIES_LIST = []
model, priv_thresh, sf_thresh = (None, None, None)
mdata, mdata_params = (None, None)
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
def bind_port():
try:
server.bind(ADDR)
except BaseException:
print("Waiting on socket")
time.sleep(5)
# Open most recent Configuration and grab DB_PWD as a python variable
with open(userDir + '/BirdNET-Pi/scripts/thisrun.txt', 'r') as f:
this_run = f.readlines()
audiofmt = "." + str(str(str([i for i in this_run if i.startswith('AUDIOFMT')]).split('=')[1]).split('\\')[0])
priv_thresh = float("." + str(str(str([i for i in this_run if i.startswith('PRIVACY_THRESHOLD')]).split('=')[1]).split('\\')[0])) / 10
try:
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])
except Exception:
model = "BirdNET_6K_GLOBAL_MODEL"
sf_thresh = 0.03
def loadModel():
@@ -336,303 +292,6 @@ def get_metadata(lat, lon, week):
return mdata
def writeResultsToFile(detections, min_conf, path):
print('WRITING RESULTS TO', path, '...', end=' ')
rcnt = 0
with open(path, 'w') as rfile:
rfile.write('Start (s);End (s);Scientific name;Common name;Confidence\n')
for d in detections:
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)):
rfile.write(d + ';' + entry[0].replace('_', ';').split("/")[0] + ';' + str(entry[1]) + '\n')
rcnt += 1
print('DONE! WROTE', rcnt, 'RESULTS.')
return
def handle_client(conn, addr):
global INCLUDE_LIST
global EXCLUDE_LIST
# print(f"[NEW CONNECTION] {addr} connected.")
while True:
msg_length = conn.recv(HEADER).decode(FORMAT)
if not msg_length:
break
msg_length = int(msg_length)
msg = conn.recv(msg_length).decode(FORMAT)
if not msg:
break
if msg == DISCONNECT_MESSAGE:
break
# print(f"[{addr}] {msg}")
args = type('', (), {})()
args.i = ''
args.o = ''
args.birdweather_id = '99999'
args.include_list = 'null'
args.exclude_list = 'null'
args.overlap = 0.0
args.week = -1
args.sensitivity = 1.25
args.min_conf = 0.70
args.lat = -1
args.lon = -1
for line in msg.split('||'):
inputvars = line.split('=')
if inputvars[0] == 'i':
args.i = inputvars[1]
elif inputvars[0] == 'o':
args.o = inputvars[1]
elif inputvars[0] == 'birdweather_id':
args.birdweather_id = inputvars[1]
elif inputvars[0] == 'include_list':
args.include_list = inputvars[1]
elif inputvars[0] == 'exclude_list':
args.exclude_list = inputvars[1]
elif inputvars[0] == 'overlap':
args.overlap = float(inputvars[1])
elif inputvars[0] == 'week':
args.week = int(inputvars[1])
elif inputvars[0] == 'sensitivity':
args.sensitivity = float(inputvars[1])
elif inputvars[0] == 'min_conf':
args.min_conf = float(inputvars[1])
elif inputvars[0] == 'lat':
args.lat = float(inputvars[1])
elif inputvars[0] == 'lon':
args.lon = float(inputvars[1])
# Load custom species lists - INCLUDED and EXCLUDED
if not args.include_list == 'null':
INCLUDE_LIST = loadCustomSpeciesList(args.include_list)
else:
INCLUDE_LIST = []
if not args.exclude_list == 'null':
EXCLUDE_LIST = loadCustomSpeciesList(args.exclude_list)
else:
EXCLUDE_LIST = []
birdweather_id = args.birdweather_id
# Read audio data & handle errors
try:
audioData = readAudioData(args.i, args.overlap)
except (NameError, TypeError) as e:
print(f"Error with the following info: {e}")
open('~/BirdNET-Pi/analyzing_now.txt', 'w').close()
finally:
pass
# Get Date/Time from filename in case Pi gets behind
# now = datetime.now()
full_file_name = args.i
# print('FULL FILENAME: -' + full_file_name + '-')
file_name = Path(full_file_name).stem
# Get the RSTP stream identifier from the filename if it exists
RTSP_ident_for_fn = ""
RTSP_ident = re.search("RTSP_[0-9]+-", file_name)
if RTSP_ident is not None:
RTSP_ident_for_fn = RTSP_ident.group()
# Find and remove the identifier for the RSTP stream url it was from that is added when more than one
# RSTP stream is recorded simultaneously, in order to make the filenames unique as filenames are all
# generated at the same time
file_name = re.sub("RTSP_[0-9]+-", "", file_name)
# Now we can read the date and time as normal
# First portion of the filename contaning the date in Y m d
file_date = file_name.split('-birdnet-')[0]
# Second portion of the filename containing the time in H:M:S
file_time = file_name.split('-birdnet-')[1]
# Join the date and time together to get a complete string representing when the audio was recorded
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))
# Process audio data and get detections
detections = analyzeAudioData(audioData, args.lat, args.lon, week, args.sensitivity, args.overlap)
# Write detections to output file
min_conf = max(0.01, min(args.min_conf, 0.99))
writeResultsToFile(detections, min_conf, args.o)
###############################################################################
###############################################################################
soundscape_uploaded = False
# Write detections to Database
myReturn = ''
for i in detections:
myReturn += str(i) + '-' + str(detections[i][0]) + '\n'
with open(userDir + '/BirdNET-Pi/BirdDB.txt', 'a') as rfile:
for d in detections:
species_apprised_this_run = []
for entry in detections[d]:
if entry[1] >= min_conf and ((entry[0] in INCLUDE_LIST or len(INCLUDE_LIST) == 0)
and (entry[0] not in EXCLUDE_LIST or len(EXCLUDE_LIST) == 0)
and (entry[0] in PREDICTED_SPECIES_LIST or len(PREDICTED_SPECIES_LIST) == 0)):
# Write to text file.
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(args.sensitivity) + ';' + str(args.overlap) + '\n')
# Write to database
Date = str(current_date)
Time = str(current_time)
species = entry[0].split("/")[0]
Sci_Name, Com_Name = species.split('_')
score = entry[1]
Confidence = str(round(score * 100))
Lat = str(args.lat)
Lon = str(args.lon)
Cutoff = str(args.min_conf)
Week = str(args.week)
Sens = str(args.sensitivity)
Overlap = str(args.overlap)
Com_Name = Com_Name.replace("'", "")
File_Name = Com_Name.replace(" ", "_") + '-' + Confidence + '-' + \
Date.replace("/", "-") + '-birdnet-' + RTSP_ident_for_fn + Time + audiofmt
# Connect to SQLite Database
for attempt_number in range(3):
try:
con = sqlite3.connect(DB_PATH)
cur = con.cursor()
cur.execute("INSERT INTO detections VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", (Date, Time,
Sci_Name, Com_Name, str(score), Lat, Lon, Cutoff, Week, Sens, Overlap, File_Name))
con.commit()
con.close()
break
except BaseException:
print("Database busy")
time.sleep(2)
# Apprise of detection if not already alerted this run.
if not entry[0] in species_apprised_this_run:
settings_dict = config_to_settings(userDir + '/BirdNET-Pi/scripts/thisrun.txt')
sendAppriseNotifications(species,
str(score),
str(round(score * 100)),
File_Name,
Date,
Time,
Week,
Lat,
Lon,
Cutoff,
Sens,
Overlap,
settings_dict,
DB_PATH)
species_apprised_this_run.append(entry[0])
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) +
';' +
File_Name +
'\n')
if birdweather_id != "99999":
try:
if soundscape_uploaded is False:
# POST soundscape to server
soundscape_url = 'https://app.birdweather.com/api/v1/stations/' + \
birdweather_id + \
'/soundscapes' + \
'?timestamp=' + \
current_iso8601
with open(args.i, 'rb') as f:
wav_data = f.read()
gzip_wav_data = gzip.compress(wav_data)
response = requests.post(url=soundscape_url, data=gzip_wav_data, headers={'Content-Type': 'application/octet-stream',
'Content-Encoding': 'gzip'})
print("Soundscape POST Response Status - ", response.status_code)
sdata = response.json()
soundscape_id = sdata['soundscape']['id']
soundscape_uploaded = True
# 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].split("/")[0] + "\","
post_scientificName = "\"scientificName\": \"" + entry[0].split('_')[0] + "\","
if model == "BirdNET_GLOBAL_6K_V2.4_Model_FP16":
post_algorithm = "\"algorithm\": " + "\"2p4\"" + ","
else:
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)
except BaseException:
print("Cannot POST right now")
conn.send(myReturn.encode(FORMAT))
# time.sleep(3)
conn.close()
def load_global_model():
global INTERPRETER
global model, priv_thresh, sf_thresh
@@ -671,22 +330,3 @@ def run_analysis(file):
d = Detection(time_slot.split(';')[0], time_slot.split(';')[1], entry[0], entry[1])
confident_detections.append(d)
return confident_detections
def start():
bind_port()
# Load model
global INTERPRETER
INTERPRETER = loadModel()
server.listen()
# print(f"[LISTENING] Server is listening on {SERVER}")
while True:
conn, addr = server.accept()
thread = threading.Thread(target=handle_client, args=(conn, addr))
thread.start()
# print(f"[ACTIVE CONNECTIONS] {threading.activeCount() - 1}")
# print("[STARTING] server is starting...")
if __name__ == '__main__':
start()
+4 -18
View File
@@ -4,10 +4,10 @@ function service_status($name) {
$home = shell_exec("awk -F: '/1000/{print $6}' /etc/passwd");
$home = trim($home);
if($name == "birdnet_server.service") {
$filesinproc=trim(shell_exec("ls ".$home."/BirdSongs/Processed | wc -l"));
if($name == "birdnet_analysis.service") {
$filesinproc=trim(shell_exec("ls ".$home."/BirdSongs/StreamData | wc -l"));
if($filesinproc > 200) {
echo "<span style='color:#fc6603'>(stalled - backlog of ".$filesinproc." files in ~/BirdSongs/Processed/)</span>";
echo "<span style='color:#fc6603'>(stalled - backlog of ".$filesinproc." files in ~/BirdSongs/StreamData/)</span>";
return;
}
}
@@ -45,21 +45,7 @@ function service_status($name) {
<button type="submit" name="submit" value="sudo systemctl enable --now birdnet_log.service">Enable</button>
</form>
<form action="" method="GET">
<h3>Extraction Service <?php echo service_status("extraction.service");?></h3>
<button type="submit" name="submit" value="sudo systemctl stop extraction.service">Stop</button>
<button type="submit" name="submit" value="sudo systemctl restart extraction.service">Restart </button>
<button type="submit" name="submit" value="sudo systemctl disable --now extraction.service">Disable</button>
<button type="submit" name="submit" value="sudo systemctl enable --now extraction.service">Enable</button>
</form>
<form action="" method="GET">
<h3>BirdNET Analysis Server <?php echo service_status("birdnet_server.service");?></h3>
<button type="submit" name="submit" value="sudo systemctl stop birdnet_server.service">Stop</button>
<button type="submit" name="submit" value="sudo systemctl restart birdnet_server.service">Restart</button>
<button type="submit" name="submit" value="sudo systemctl disable --now birdnet_server.service">Disable</button>
<button type="submit" name="submit" value="sudo systemctl enable --now birdnet_server.service">Enable</button>
</form>
<form action="" method="GET">
<h3>BirdNET Analysis Client <?php echo service_status("birdnet_analysis.service");?></h3>
<h3>BirdNET Analysis <?php echo service_status("birdnet_analysis.service");?></h3>
<button type="submit" name="submit" value="sudo systemctl stop birdnet_analysis.service">Stop</button>
<button type="submit" name="submit" value="sudo systemctl restart birdnet_analysis.service">Restart</button>
<button type="submit" name="submit" value="sudo systemctl disable --now birdnet_analysis.service">Disable</button>
-2
View File
@@ -5,9 +5,7 @@
services=(birdnet_recording.service
custom_recording.service
birdnet_analysis.service
birdnet_server.service
chart_viewer.service
extraction.service
spectrogram_viewer.service)
for i in "${services[@]}";do