diff --git a/Birders_Guide_Installer.sh b/Birders_Guide_Installer.sh deleted file mode 100755 index 01b4d68..0000000 --- a/Birders_Guide_Installer.sh +++ /dev/null @@ -1,300 +0,0 @@ -#!/usr/bin/env bash -set -e -USER=pi -HOME=/home/pi -my_dir=${HOME}/BirdNET-Pi -branch=main -trap '${my_dir}/scripts/dump_logs.sh && exit' EXIT SIGHUP SIGINT - -if [ "$(uname -m)" != "aarch64" ];then - echo "BirdNET-Pi requires a 64-bit OS. -It looks like your operating system is using $(uname -m), -but would need to be aarch64. -Please take a look at https://birdnetwiki.pmcgui.xyz for more -information" - exit 1 -fi - -stage_1() { - echo - echo "Beginning Stage 1" - echo - echo "Ensuring the system is up-to-date." - sudo apt -qq update - sudo apt -qqy full-upgrade - sudo apt -y autoremove --purge - echo "System Updated!" - if ! which git &> /dev/null; then - echo "Installing git" - sudo apt install -qqy git - fi - touch ${HOME}/stage_1_complete - echo "Stage 1 complete" -} - -stage_2() { - echo - echo "Beginning stage 2" - echo - echo "Checking for an internet connection to continue . . ." - until ping -c 1 8.8.8.8 &> /dev/null; do - sleep 1 - done - echo "Connected!" - echo - if [ ! -d ${my_dir} ];then - cd ${HOME} || exit 1 - echo "Cloning the BirdNET-Pi repository $branch branch into your home directory" - git clone -b ${branch} https://github.com/mcguirepr89/BirdNET-Pi.git ${HOME}/BirdNET-Pi - else - cd ${my_dir} && git checkout ${branch} - fi - - source ${my_dir}/Birders_Guide_Installer_Configuration.txt - if [ -z ${LATITUDE} ] || [ -z ${LONGITUDE} ] || [ -z ${CADDY_PWD} ] || [ -z ${ICE_PWD} ] || [ -z ${DB_PWD} ];then - echo - echo "Follow the instructions to fill out the LATITUDE and LONGITUDE variables -and set the passwords for the live audio stream. Save the file after editing -and then close the Mouse Pad editing window to continue." - echo - if [ -z "$SSH_CONNECTION" ];then - EDITOR=mousepad - else - EDITOR=nano - fi - $EDITOR ${my_dir}/Birders_Guide_Installer_Configuration.txt - while pgrep $EDITOR &> /dev/null;do - sleep 1 - done - source ${my_dir}/Birders_Guide_Installer_Configuration.txt || exit 1 - fi - echo "Installing the BirdNET-Pi configuration file." - install_birdnet_config || exit 1 - echo "Installing BirdNET-Lite" - if ${my_dir}/scripts/install_birdnet.sh;then -echo "The next time you power on the raspberry pi, all of the services will start up automatically. - -The installation has finished. Press Enter to close this window." - read - else - echo "Something went wrong during installation. Open a github issue or email mcguirepr89@gmail.com" - fi -} - -install_birdnet_config() { - cat << EOF > ${my_dir}/birdnet.conf -################################################################################ -# Configuration settings for BirdNET-Pi # -################################################################################ - -############ CHANGE THE LATITUDE AND LONGITUDE TO STATIC VALUES ################ - - -## LATITUDE and LONGITUDE are self-explanatroy. Find them easily at -## maps.google.com. -## Example: these coordinates would indicate the Eiffel Tower in Paris, France. -## LATITUDE=48.858 -## LONGITUDE=2.294 - -## These are input as shell substitutions so that this will work out of the box. -## It guesses your latitude and longitude based off of your network information. -## THESE SHOULD BE CHANGED TO STATIC NUMBERS!!!! -LATITUDE=${LATITUDE} -LONGITUDE=${LONGITUDE} - -## RECS_DIR is the location birdnet_analysis.service will look for the data-set -## it needs to analyze. Be sure this directory is readable and writable for -## the BIRDNET_USER. If you are going to be accessing a remote data-set, you -## still need to set this, as this will be where the remote directory gets -## mounted locally. - -RECS_DIR=/home/pi/BirdSongs - -#----------------------- Web Interface User Password ------------------------# -#____________________The variable below sets the 'birdnet'_____________________# -#___________________user password for the live audio stream,___________________# -#_________________web tools, system info, and processed files__________________# - -## CADDY_PWD is the plaintext password (that will be hashed) and used to access -## certain parts of the web interface - -CADDY_PWD=changeme - -#------------------------- MariaDB User Passwords ---------------------------# -#_____________The variable below sets the password for the_____________________# -#_______________________'birder' user on the MariaDB___________________________# - -## DB_PWD is for the 'birder' user -DB_PWD=changeme - -#------------------------- Live Audio Stream --------------------------------# -#_____________The variable below configures/enables the live___________________# -#_____________________________audio stream.____________________________________# - - -## ICE_PWD is the password that icecast2 will use to authenticate ffmpeg as a -## trusted source for the stream. You will never need to enter this manually -## anywhere other than here. - -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 -----------------------# -#________The four variables below can be set to enable internet access_________# -#____________to your data,(e.g., extractions, raw data, live___________________# -#______________audio stream, BirdNET.selection.txt files)______________________# - - -## BIRDNETPI_URL is the URL where the extractions, data-set, and live-stream -## will be web-hosted. If you do not own a domain, or would just prefer to keep -## the BirdNET-Pi on your local network, keep this EMPTY. - -BIRDNETPI_URL=${BIRDNETPI_URL} -EXTRACTIONLOG_URL=${EXTRACTIONLOG_URL} -BIRDNETLOG_URL=${BIRDNETLOG_URL} - - -#------------------- Mobile Notifications via Pushed.co ---------------------# -#____________The two variables below enable mobile notifications_______________# -#_____________See https://pushed.co/quick-start-guide to get___________________# -#_________________________these values for your app.___________________________# - -# Keep these EMPTY if haven't setup a Pushed.co App yet. # - -## Pushed.co App Key and App Secret - -PUSHED_APP_KEY=${PUSHED_APP_KEY} -PUSHED_APP_SECRET=${PUSHED_APP_SECRET} - -################################################################################ -#-------------------------------- Defaults ----------------------------------# -################################################################################ - -#------------------------------- NoMachine ----------------------------------# -#_____________The variable below can be set include NoMachine__________________# -#_________________remote desktop software to be installed._____________________# - -# Keep this EMPTY if you do not want to install NoMachine. # - -## INSTALL_NOMACHINE is simply a setting that can be enabled to install -## NoMachine alongside the BirdNET-Pi for remote desktop access. This in- -## staller assumes personal use. Please reference the LICENSE file included -## in this repository for more information. -## Set this to Y or y to install NoMachine alongside the BirdNET-Lite - -INSTALL_NOMACHINE=y - -# -#------------------------------ Extraction Service ---------------------------# - -## DO_EXTRACTIONS is simply a setting for enabling the extraction.service. -## Set this to Y or y to enable extractions. - -DO_EXTRACTIONS=y - -#----------------------------- Recording Service ----------------------------# -#____________________The variable below can be set to enable __________________# -#________________________the birdnet_recording.service ________________________# - -## DO_RECORDING is simply a setting for enabling the 24/7 -## birdnet_recording.service. -## Set this to Y or y to enable recording. - -DO_RECORDING=y - -## REC_CARD is the sound card you would want the birdnet_recording.service to -## use. This setting is irrelevant if you are not planning on doing data -## collection via recording on this machine. The command substitution below -## looks for a USB microphone's dsnoop alsa device. The dsnoop device lets -## birdnet_recording.service and livestream.service share the raw audio stream -## from the microphone. If you would like to use a different microphone than -## what this produces, or if your microphone does not support creating a -## dsnoop device, you can set this explicitly from a list of the available -## devices from the output of running 'aplay -L' - -REC_CARD=default - -## PROCESSED is the directory where the formerly 'Analyzed' files are moved -## after extractions have been made from them. This includes both WAVE and -## BirdNET.selection.txt files. - -PROCESSED=/home/pi/BirdSongs/Processed - -## EXTRACTED is the directory where the extracted audio selections are moved. - -EXTRACTED=/home/pi/BirdSongs/Extracted - -## IDFILE is the file that keeps a complete list of every spececies that -## BirdNET has identified from your data-set. It is persistent across -## data-sets, so would need to be whiped clean through deleting or renaming -## it. A backup is automatically made from this variable each time it is -## updated (structure: ${IDFILE}.bak), and would also need to be removed -## or renamed to start a new file between data-sets. Alternately, you can -## change this variable between data-sets to preserve records of disparate -## data-sets according to name. - -IDFILE=${HOME}/BirdNET-Pi/IdentifiedSoFar.txt - -## OVERLAP is the value in seconds which BirdNET should use when analyzing -## the data. The values must be between 0.0-2.9. - -OVERLAP=0.0 - -## CONFIDENCE is the minimum confidence level from 0.0-1.0 BirdNET's analysis -## should reach before creating an entry in the BirdNET.selection.txt file. -## Don't set this to 1.0 or you won't have any results. - -CONFIDENCE=0.7 - -## SENSITIVITY is the detection sensitivity from 0.5-1.5. - -SENSITIVITY=1.25 - -## CHANNELS holds the variabel that corresponds to the number of channels the -## sound card supports. - -CHANNELS=2 - -## FULL_DISK can be set to configure how the system reacts to a full disk -## 0 = Remove the oldest day's worth of recordings -## 1 = Keep all data and 'stop_core_services.sh' - -FULL_DISK=0 - -## VENV is the virtual environment where the the BirdNET python build is found, -## i.e, VENV is the virtual environment miniforge built for BirdNET. - -VENV=/home/pi/BirdNET-Pi/birdnet - -## RECORDING_LENGTH sets the length of the recording that BirdNET-Lite will analyze. -RECORDING_LENGTH= - -## EXTRACTION_LENGTH sets the length of the audio extractions that will be made -## from each BirdNET-Lite detection. -EXTRACTION_LENGTH= - -## BIRDNET_USER should be the non-root user systemd should use to execute each -## service. - -BIRDNET_USER=pi - - -## These are just for debugging -LAST_RUN= -THIS_RUN= -EOF - [ -d /etc/birdnet ] || sudo mkdir /etc/birdnet - sudo ln -sf ${my_dir}/birdnet.conf /etc/birdnet/birdnet.conf -} -if [ ! -f ${HOME}/stage_1_complete ] ;then - stage_1 - stage_2 -else - stage_2 -fi - diff --git a/Birders_Guide_Installer_Configuration.txt b/Birders_Guide_Installer_Configuration.txt deleted file mode 100644 index 1bbf484..0000000 --- a/Birders_Guide_Installer_Configuration.txt +++ /dev/null @@ -1,59 +0,0 @@ -# Birders Guide Installer Configuration File - -################################################################################ -# Fill this out in order to install BirdNET-Lite -# Follow the instructions for each section. -################################################################################ - - -# 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 -# 1b. Right-click the location to view the latitude and longitude and click -# them to copy them to your clip-board. -# 2. Enter the latitude and longitude here. Be certain not to mix them up. -# The first number is the latitude, and the second is longitude. See the -# example below. -# -# Example: these coordinates would indicate the Eiffel Tower in Paris, France. -# LATITUDE=48.858 -# LONGITUDE=2.294 - -LATITUDE= -LONGITUDE= - -# 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. -# You will probably also want to write this one down if you ever plan to -# listen to the live stream. -# 2. ICE_PWD is the password that IceCast2 will use to authenticate the stream -# source.You can set this to anything also, but keep it alpha-numeric. You -# will never use this again, so just set it to your favorite word. - -CADDY_PWD= -ICE_PWD= - -# DB_PWD is the password that the system will use to access the database. Set -# this to anything you want. - -DB_PWD= - -# This section can be left alone. If you setup a Pushed.co -# mobile application, you can enter the App secret and secret -# key in order to enable phone notifications for new species -# detections. -PUSHED_APP_SECRET= -PUSHED_APP_KEY= - -# If you own your own domain, you can input that here to have caddy register -# TLS certificates for the web interface - -BIRDNETPI_URL= -BIRDNETLOG_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= diff --git a/README.md b/README.md index 03ec43c..1db3c57 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
A realtime acoustic bird classification system for the Raspberry Pi 4B
@@ -37,6 +37,9 @@ If your installation isn't in one of the countries listed above, please let me k
* 24/7 recording and BirdNET-Lite analysis
* [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))
* Web interface access to all data and logs
+* Web Terminal
+* [Tiny File Manager](https://tinyfilemanager.github.io/)
+* FTP server included
* Automatic extraction of detected data (creating audio clips of detected bird sounds)
* Spectrograms available for all extractions
* MariaDB integration
@@ -47,27 +50,25 @@ If your installation isn't in one of the countries listed above, please let me k
* Localization supported
## Requirements
-* A Raspberry Pi 4B
-* An SD Card with the 64-bit version of RaspiOS installed (please use Bullseye) [(download the latest here)](https://downloads.raspberrypi.org/raspios_arm64/images/)
+* A Raspberry Pi 4B or Raspberry Pi 3B[+] (must run on RaspiOS-ARM64-Lite)
+* An SD Card with the 64-bit version of RaspiOS installed (please use Bullseye) -- Lite is recommended, but the installation works on RaspiOS-ARM64-Full as well. [(Download the latest here)](https://downloads.raspberrypi.org/raspios_lite_arm64/images/)
* A USB Microphone or Sound Card
## Installation
-Headless installation guide available [HERE](https://github.com/mcguirepr89/BirdNET-Pi/wiki/%22Headless%22-installation-using-VNC)
-Pre-installeld beta image available for testing [HERE](https://github.com/mcguirepr89/BirdNET-Pi/discussions/11#discussioncomment-1751201)
+[An installation guide is available here](https://github.com/mcguirepr89/BirdNET-Pi/wiki/Installation-Guide).
The system can be installed with:
```
-curl -s https://raw.githubusercontent.com/mcguirepr89/BirdNET-Pi/main/newinstaller.sh | bash
+curl -s https://raw.githubusercontent.com/mcguirepr89/BirdNET-Pi/main/newinstaller.sh | bash | tee -a installation.log 2>&1 && sudo reboot
```
+The installer takes care of any and all necessary updates, so you can run that as the very first command upon the first boot, if you'd like.
+
+The installation creates a log in `/home/pi/installation.log` that you can [email me](mailto:mcguirepr89@gmail.com) if you encounter any issues during installation.
## Access
The BirdNET-Pi system can be accessed from any web browser on the same network:
- http://birdnetpi.local
-#### Access Credentials:
-- Username:`birdnet`
-- Password: The "CADDY_PWD" password set during installation
-
## Uninstallation
```
/usr/local/bin/uninstall.sh && cd ~ && rm -drf BirdNET-Pi
@@ -87,7 +88,7 @@ I hope that if you find BirdNET-Pi has been worth your time, you will share your
## ToDo, Notes, and Coming Soon
### Internationalization:
-The bird names are in English by default, but other localized versions are available thanks to the wonderful efforts of [@patlevin](https://github.com/patlevin). Please unzip `model/labels_l18n.zip` and replace `model/labels.txt` with your corresponding language. For instance, if you want the Swedish labels, rename the current `labels.txt` to `labels_en.txt` and then rename `labels_sv.txt` to `labels.txt`. (I will make this more straightforward in the future.)
+The bird names are in English by default, but other localized versions are available thanks to the wonderful efforts of [@patlevin](https://github.com/patlevin). Use the web interface's "Tools" > "Settings" and select your "Database Language" to have the detections in your language.
### Realtime Analysis Predictions View
The pre-built TFLite binaries for this project also support [the BirdNET-Demo](https://github.com/kahst/BirdNET-Demo), which I am currently testing for integration into the BirdNET-Pi. If you know anything about JavaScript and are willing to help, please let me know in the [Live Analysis discussion](https://github.com/mcguirepr89/BirdNET-Pi/discussions/24).
@@ -101,7 +102,7 @@ Expect FULL internationalization options during installation (and available post
- French
- Spanish
-and detection/database localization for the following languages:
+Current database languages include the list below:
| Language | Missing Species out of 6,362 | Missing labels (%) |
| -------- | ------- | ------ |
| Afrikaans | 5774 | 90.76% |
diff --git a/analyze.py b/analyze.py
deleted file mode 100644
index b90038f..0000000
--- a/analyze.py
+++ /dev/null
@@ -1,353 +0,0 @@
-# BirdWeather edits by @timsterc
-# Other edits by @CaiusX and @mcguirepr89
-import os
-os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
-os.environ['CUDA_VISIBLE_DEVICES'] = ''
-
-try:
- import tflite_runtime.interpreter as tflite
-except:
- from tensorflow import lite as tflite
-
-import argparse
-import operator
-import librosa
-import numpy as np
-import math
-import time
-from decimal import Decimal
-import json
-###############################################################################
-import requests
-import mysql.connector
-###############################################################################
-import datetime
-import pytz
-from tzlocal import get_localzone
-from pathlib import Path
-
-def loadModel():
-
- global INPUT_LAYER_INDEX
- global OUTPUT_LAYER_INDEX
- global MDATA_INPUT_INDEX
- global CLASSES
-
- print('LOADING TF LITE MODEL...', end=' ')
-
- # Load TFLite model and allocate tensors.
- interpreter = tflite.Interpreter(model_path='model/BirdNET_6K_GLOBAL_MODEL.tflite',num_threads=2)
- interpreter.allocate_tensors()
-
- # Get input and output tensors.
- input_details = interpreter.get_input_details()
- output_details = interpreter.get_output_details()
-
- # Get input tensor index
- INPUT_LAYER_INDEX = input_details[0]['index']
- MDATA_INPUT_INDEX = input_details[1]['index']
- OUTPUT_LAYER_INDEX = output_details[0]['index']
-
- # Load labels
- CLASSES = []
- with open('model/labels.txt', 'r') as lfile:
- for line in lfile.readlines():
- CLASSES.append(line.replace('\n', ''))
-
- print('DONE!')
-
- return interpreter
-
-def loadCustomSpeciesList(path):
-
- slist = []
- if os.path.isfile(path):
- with open(path, 'r') as csfile:
- for line in csfile.readlines():
- slist.append(line.replace('\r', '').replace('\n', ''))
-
- return slist
-
-def splitSignal(sig, rate, overlap, seconds=3.0, minlen=1.5):
-
- # Split signal with overlap
- sig_splits = []
- for i in range(0, len(sig), int((seconds - overlap) * rate)):
- split = sig[i:i + int(seconds * rate)]
-
- # End of signal?
- if len(split) < int(minlen * rate):
- break
-
- # Signal chunk too short? Fill with zeros.
- if len(split) < int(rate * seconds):
- temp = np.zeros((int(rate * seconds)))
- temp[:len(split)] = split
- split = temp
-
- sig_splits.append(split)
-
- return sig_splits
-
-def readAudioData(path, overlap, sample_rate=48000):
-
- print('READING AUDIO DATA...', end=' ', flush=True)
-
- # Open file with librosa (uses ffmpeg or libav)
- sig, rate = librosa.load(path, sr=sample_rate, mono=True, res_type='kaiser_fast')
-
- # Split audio into 3-second chunks
- chunks = splitSignal(sig, rate, overlap)
-
- print('DONE! READ', str(len(chunks)), 'CHUNKS.')
-
- return chunks
-
-def convertMetadata(m):
-
- # Convert week to cosine
- if m[2] >= 1 and m[2] <= 48:
- m[2] = math.cos(math.radians(m[2] * 7.5)) + 1
- else:
- m[2] = -1
-
- # Add binary mask
- mask = np.ones((3,))
- if m[0] == -1 or m[1] == -1:
- mask = np.zeros((3,))
- if m[2] == -1:
- mask[2] = 0.0
-
- return np.concatenate([m, mask])
-
-def custom_sigmoid(x, sensitivity=1.0):
- return 1 / (1.0 + np.exp(-sensitivity * x))
-
-def predict(sample, interpreter, sensitivity):
-
- # Make a prediction
- interpreter.set_tensor(INPUT_LAYER_INDEX, np.array(sample[0], dtype='float32'))
- interpreter.set_tensor(MDATA_INPUT_INDEX, np.array(sample[1], dtype='float32'))
- interpreter.invoke()
- prediction = interpreter.get_tensor(OUTPUT_LAYER_INDEX)[0]
-
- # Apply custom sigmoid
- p_sigmoid = custom_sigmoid(prediction, sensitivity)
-
- # Get label and scores for pooled predictions
- p_labels = dict(zip(CLASSES, p_sigmoid))
-
- # Sort by score
- p_sorted = sorted(p_labels.items(), key=operator.itemgetter(1), reverse=True)
-
- # Remove species that are on blacklist
- for i in range(min(10, len(p_sorted))):
- if p_sorted[i][0] in ['Human_Human', 'Non-bird_Non-bird', 'Noise_Noise']:
- p_sorted[i] = (p_sorted[i][0], 0.0)
-
- # Only return first the top ten results
- return p_sorted[:10]
-
-def analyzeAudioData(chunks, lat, lon, week, sensitivity, overlap, interpreter):
-
- detections = {}
- start = time.time()
- print('ANALYZING AUDIO...', end=' ', flush=True)
-
- # Convert and prepare metadata
- mdata = convertMetadata(np.array([lat, lon, week]))
- mdata = np.expand_dims(mdata, 0)
-
- # Parse every chunk
- pred_start = 0.0
- for c in chunks:
-
- # Prepare as input signal
- sig = np.expand_dims(c, 0)
-
- # Make prediction
- p = predict([sig, mdata], interpreter, sensitivity)
-
- # Save result and timestamp
- pred_end = pred_start + 3.0
- detections[str(pred_start) + ';' + str(pred_end)] = p
- pred_start = pred_end - overlap
-
- print('DONE! Time', int((time.time() - start) * 10) / 10.0, 'SECONDS')
-
- return detections
-
-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 WHITE_LIST or len(WHITE_LIST) == 0):
- rfile.write(d + ';' + entry[0].replace('_', ';') + ';' + str(entry[1]) + '\n')
- rcnt += 1
- print('DONE! WROTE', rcnt, 'RESULTS.')
-
-def main():
-
- global WHITE_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('--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()
-
- # Load model
- interpreter = loadModel()
-
- # Load custom species list
- if not args.custom_list == '':
- WHITE_LIST = loadCustomSpeciesList(args.custom_list)
- else:
- WHITE_LIST = []
-
- birdweather_id = args.birdweather_id
-
- # Read audio data
- audioData = readAudioData(args.i, args.overlap)
-
- # Get Date/Time from filename in case Pi gets behind
- #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))
-
- # Process audio data and get detections
- detections = analyzeAudioData(audioData, args.lat, args.lon, week, sensitivity, args.overlap, interpreter)
-
- # 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
- for i in detections:
- print("\n", detections[i][0],"\n")
- with open('BirdDB.txt', 'a') as rfile:
- for d in detections:
- print("\n", "Database Entry", "\n")
- for entry in detections[d]:
- if entry[1] >= min_conf and (entry[0] in WHITE_LIST or len(WHITE_LIST) == 0):
- rfile.write(str(current_date) + ';' + str(current_time) + ';' + entry[0].replace('_', ';') + ';' \
- + str(entry[1]) +";" + str(args.lat) + ';' + str(args.lon) + ';' + str(min_conf) + ';' + str(week) + ';' \
- + str(sensitivity) +';' + str(args.overlap) + '\n')
-
- def insert_variables_into_table(Date, Time, Sci_Name, Com_Name, Confidence, Lat, Lon, Cutoff, Week, Sens, Overlap):
- try:
- connection = mysql.connector.connect(host='localhost',
- database='birds',
- user='birder',
- password='databasepassword')
- cursor = connection.cursor()
- 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) """
-
- 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))
-
- finally:
- if connection.is_connected():
- connection.close()
- print("MySQL connection is closed")
-
- species = entry[0]
- 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 birdweather_id != "99999":
-
- 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()
- 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
-
- # 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)
-
-###############################################################################
-###############################################################################
-
-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'
diff --git a/birdnet.conf-defaults b/birdnet.conf-defaults
index 57a2c99..c84d4ae 100644
--- a/birdnet.conf-defaults
+++ b/birdnet.conf-defaults
@@ -2,33 +2,26 @@
# Configuration settings for BirdNET-Pi #
################################################################################
-############ CHANGE THE LATITUDE AND LONGITUDE TO STATIC VALUES ################
+#--------------------- Required: Latitude, and Longitude ----------------------#
+## The shell substitution below guesses these based on your network. THESE NEED
+## TO BE CHANGED TO STATIC VALUES
+## Please only go to 4 decimal places. Example:43.3984
-## LATITUDE and LONGITUDE are self-explanatroy. Find them easily at
-## maps.google.com.
-## Example: these coordinates would indicate the Eiffel Tower in Paris, France.
-## LATITUDE=48.858
-## LONGITUDE=2.294
-
-## These are input as shell substitutions so that this will work out of the box.
-## It guesses your latitude and longitude based off of your network information.
-## THESE SHOULD BE CHANGED TO STATIC NUMBERS!!!!
LATITUDE="$(curl -s4 ifconfig.co/json | awk '/lat/ {print $2}' | tr -d ',')"
LONGITUDE="$(curl -s4 ifconfig.co/json | awk '/lon/ {print $2}' | tr -d ',')"
-## RECS_DIR is the location birdnet_analysis.service will look for the data-set
-## it needs to analyze. Be sure this directory is readable and writable for
-## the BIRDNET_USER. If you are going to be accessing a remote data-set, you
-## still need to set this, as this will be where the remote directory gets
-## mounted locally.
-RECS_DIR=/home/pi/BirdSongs
+#--------------------- BirdWeather Station Information -----------------------#
+#_____________The variable below can be set to have your BirdNET-Pi____________#
+#__________________also act as a BirdWeather listening station_________________#
+
+BIRDWEATHER_ID=
#----------------------- Web Interface User Password ------------------------#
#____________________The variable below sets the 'birdnet'_____________________#
-#___________________user password for the live audio stream,___________________#
-#_________________web tools, system info, and processed files__________________#
+#___________________user password for the Live Audio Stream,___________________#
+#_________________Tools, System Links, and the Processed files ________________#
## CADDY_PWD is the plaintext password (that will be hashed) and used to access
## certain parts of the web interface
@@ -39,7 +32,8 @@ CADDY_PWD=
#_____________The variable below sets the password for the_____________________#
#_______________________'birder' user on the MariaDB___________________________#
-## DB_PWD is for the 'birder' user
+## DB_PWD is for the 'birder' user. The shell substitution below sets a random
+## password for you during installation.
DB_PWD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo;)
#------------------------- Live Audio Stream --------------------------------#
@@ -49,16 +43,10 @@ DB_PWD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-32};echo;)
## ICE_PWD is the password that icecast2 will use to authenticate ffmpeg as a
## trusted source for the stream. You will never need to enter this manually
-## anywhere other than here.
+## anywhere other than here and it stays on 'localhost.'
ICE_PWD=birdnetpi
-#--------------------- 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 -----------------------#
#________The four variables below can be set to enable internet access_________#
#____________to your data,(e.g., extractions, raw data, live___________________#
@@ -70,8 +58,8 @@ BIRDWEATHER_ID=
## the BirdNET-Pi on your local network, keep this EMPTY.
BIRDNETPI_URL=
-EXTRACTIONLOG_URL=
BIRDNETLOG_URL=
+WEBTERMINAL_URL=
#------------------- Mobile Notifications via Pushed.co ---------------------#
@@ -90,19 +78,11 @@ PUSHED_APP_SECRET=
#-------------------------------- Defaults ----------------------------------#
################################################################################
-#------------------------------- NoMachine ----------------------------------#
-#_____________The variable below can be set include NoMachine__________________#
-#_________________remote desktop software to be installed._____________________#
+## RECS_DIR is the location birdnet_analysis.service will look for the data-set
+## it needs to analyze. Be sure this directory is readable and writable for
+## the BIRDNET_USER.
-# Keep this EMPTY if you do not want to install NoMachine. #
-
-## INSTALL_NOMACHINE is simply a setting that can be enabled to install
-## NoMachine alongside the BirdNET-Pi for remote desktop access. This in-
-## staller assumes personal use. Please reference the LICENSE file included
-## in this repository for more information.
-## Set this to Y or y to install NoMachine alongside the BirdNET-Lite
-
-INSTALL_NOMACHINE=y
+RECS_DIR=/home/pi/BirdSongs
#
#------------------------------ Extraction Service ---------------------------#
@@ -176,10 +156,10 @@ SENSITIVITY=1.25
CHANNELS=2
## FULL_DISK can be set to configure how the system reacts to a full disk
-## 0 = Remove the oldest day's worth of recordings
-## 1 = Keep all data and `stop_core_services.sh`
+## purge = Remove the oldest day's worth of recordings
+## keep = Keep all data and 'stop_core_services.sh'
-FULL_DISK=0
+FULL_DISK=purge
## VENV is the virtual environment where the the BirdNET python build is found,
## i.e, VENV is the virtual environment miniforge built for BirdNET.
@@ -187,7 +167,7 @@ FULL_DISK=0
VENV=/home/pi/BirdNET-Pi/birdnet
## RECORDING_LENGTH sets the length of the recording that BirdNET-Lite will analyze.
-RECORDING_LENGTH=
+RECORDING_LENGTH=15
## EXTRACTION_LENGTH sets the length of the audio extractions that will be made
## from each BirdNET-Lite detection.
@@ -202,3 +182,18 @@ BIRDNET_USER=pi
## These are just for debugging
LAST_RUN=
THIS_RUN=
+
+## DEPRECATED
+#------------------------------- NoMachine ----------------------------------#
+#_____________The variable below can be set include NoMachine__________________#
+#_________________remote desktop software to be installed._____________________#
+
+# Keep this EMPTY if you do not want to install NoMachine. #
+
+## INSTALL_NOMACHINE is simply a setting that can be enabled to install
+## NoMachine alongside the BirdNET-Pi for remote desktop access. This in-
+## staller assumes personal use. Please reference the LICENSE file included
+## in this repository for more information.
+## Set this to Y or y to install NoMachine alongside the BirdNET-Lite
+
+INSTALL_NOMACHINE=y
diff --git a/homepage/form.html b/homepage/form.html
deleted file mode 100644
index 2b3d2a6..0000000
--- a/homepage/form.html
+++ /dev/null
@@ -1,84 +0,0 @@
-
-