diff --git a/scripts/advanced.php b/scripts/advanced.php index a0ddf28..deeca88 100644 --- a/scripts/advanced.php +++ b/scripts/advanced.php @@ -268,9 +268,10 @@ if (file_exists('./scripts/thisrun.txt')) { $newconfig = parse_ini_file('./scripts/firstrun.ini'); } ?> -

Advanced Settings

+

Advanced Settings


-
+
+

Privacy Threshold

Value: %

@@ -285,7 +286,6 @@ if (file_exists('./scripts/thisrun.txt')) { output.innerHTML = this.value; document.getElementById("predictionCount").innerHTML = parseInt((this.value * )/100); } - //Keep track of how many new input fields were added var number_of_new_rtsp_urls_added = 0; //Function to insert new input fields @@ -339,18 +339,43 @@ if (file_exists('./scripts/thisrun.txt')) { }

If a Human is predicted anywhere among the top predictions, the sample will be considered of human origin and no data will be collected. Start with 1% and move up as needed.

- +

+ +
+

Full Disk Behaviour

When the disk becomes full, you can choose to 'purge' old files to make room for new ones or 'keep' your data and stop all services instead.
Note: you can exclude specific files from 'purge' on the Recordings page.

+

+
+ +

Audio Settings


Set Audio Card to 'default' to use PulseAudio (always recommended), or an ALSA recognized sound card device from the output of `arecord -L`. Choose the `dsnoop` device if it is available


Set Channels to the number of channels supported by your sound card. 32 max.

+ +
+

Set Recording Length in seconds between 6 and 60. Multiples of 3 are recommended, as BirdNET analyzes in 3-second chunks.

+ +
+

Set Extraction Length to something less than your Recording Length. Min=3 Max=Recording Length

+ + +

+
@@ -379,34 +404,25 @@ if (file_exists('./scripts/thisrun.txt')) { ?>

- add
+ Add

If you place an RTSP stream URL here, BirdNET-Pi will use that as its audio source.
Multiple streams are allowed but may have a impact on rPi performance.
Analyze ffmpeg CPU/Memory usage with top or htop if necessary.
To remove all and use the soundcard again, just delete the RTSP entries and click Save at the bottom.

- -
-

Set Recording Length in seconds between 6 and 60. Multiples of 3 are recommended, as BirdNET analyzes in 3-second chunks.

- -
-

Set Extraction Length to something less than your Recording Length. Min=3 Max=Recording Length

- - -

BirdNET-Pi Password

+

+
+

BirdNET-Pi Password

This password will protect your "Tools" page and "Live Audio" stream.

show
-

Custom URL

+

+
+

Custom URL

When you update the URL below, the web server will reload, so be sure to wait at least 30 seconds and then go to your new URL.


The BirdNET-Pi URL is how the main page will be reached. If you want your installation to respond to an IP address, place that here, but be sure to indicate "http://".
Example for IP: http://192.168.0.109
Example if you own your own domain: https://virginia.birdnetpi.com

+

+
+

Options

>

This allows you to quiet the display of how many commits your installation is behind by relative to the Github repo. This number appears next to "Tools" when you're 50 or more commits behind.

@@ -414,9 +430,10 @@ foreach($formats as $format){ >

This allows you to remove the axes and labels of the spectrograms that are generated by Sox for each detection for a cleaner appearance.

+

-
- +
+

Custom Image


@@ -424,8 +441,10 @@ foreach($formats as $format){

These allow you to show a custom image on the Overview page of your BirdNET-Pi. This can be used to show a dynamically updating picture of your garden, for example.

+

-

BirdNET-Lite Settings

+
+

BirdNET-Lite Settings

@@ -442,15 +461,17 @@ foreach($formats as $format){
    Min=0.5, Max=1.5

+

-

Accessibility Settings

+
+

Accessibility Settings

Birdsongs Frequency shifting configuration:
- this can be useful for hearing impaired people. Note: audio files will only be pitch shifted when the "FREQ SHIFT" button is manually clicked for a detection on the "Recordings" page.
+ This can be useful for hearing impaired people. Note: audio files will only be pitch shifted when the "FREQ SHIFT" button is manually clicked for a detection on the "Recordings" page.

- + - Choose here the shifting tool.
+ Choose the shifting tool here.

- using ffmpeg: + Using ffmpeg: e.g. origin=6000, target=4000, performs a shift of 2000 Hz down.
- +
- +

- using sox: + Using sox: e.g. shiftPitch=-1200 performs a shift of 1 octave down. This value is in 100ths of a semitone.
- +

- +



diff --git a/scripts/automatic.sh b/scripts/automatic.sh new file mode 100755 index 0000000..c3e9f9b --- /dev/null +++ b/scripts/automatic.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +#List audio devices and find input device name +input_device=$(LANG=C pacmd list-sources | grep name: | grep input | awk -F'<|>' '{print $2}') + +#Add echo-cancel module code to the end of the file +echo ".ifexists module-echo-cancel.so +load-module module-echo-cancel source_master=$input_device aec_method=webrtc source_name=echocancel sink_name=echocancel1 +set-default-source echocancel +set-default-sink echocancel1 +.endif" | sudo tee -a /etc/pulse/default.pa >/dev/null + +#Reload pulseaudio +pulseaudio -k + +echo "Echo cancellation setup is complete." diff --git a/scripts/birdnet-pi-config.sh b/scripts/birdnet-pi-config.sh new file mode 100755 index 0000000..f037783 --- /dev/null +++ b/scripts/birdnet-pi-config.sh @@ -0,0 +1,997 @@ +#!/usr/bin/env -S sudo -E sh +# Altered from raspi-config tool below +# https://github.com/RPi-Distro/birdnet-pi-config +# +# See LICENSE file for copyright and license details +# Copyright (c) 2012 Alex Bradbury +set -x +birdnetpi_dir=/home/pi/BirdNET-Pi +birders_config=${birdnetpi_dir}/Birders_Guide_Installer_Configuration.txt +branch=forms +INTERACTIVE=True +ASK_TO_REBOOT=0 +BLACKLIST=/etc/modprobe.d/raspi-blacklist.conf +CONFIG=/boot/config.txt + +USER=${SUDO_USER:-$(who -m | awk '{ print $1 }')} + +is_pi () { + ARCH=$(dpkg --print-architecture) + if [ "$ARCH" = "armhf" ] || [ "$ARCH" = "arm64" ] ; then + return 0 + else + return 1 + fi +} + +if is_pi ; then + CMDLINE=/boot/cmdline.txt +else + CMDLINE=/proc/cmdline +fi + +is_pione() { + if grep -q "^Revision\s*:\s*00[0-9a-fA-F][0-9a-fA-F]$" /proc/cpuinfo; then + return 0 + elif grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]0[0-36][0-9a-fA-F]$" /proc/cpuinfo ; then + return 0 + else + return 1 + fi +} + +is_pitwo() { + grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]04[0-9a-fA-F]$" /proc/cpuinfo + return $? +} + +is_pizero() { + grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]0[9cC][0-9a-fA-F]$" /proc/cpuinfo + return $? +} + +is_pifour() { + grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F]3[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]$" /proc/cpuinfo + return $? +} + +get_pi_type() { + if is_pione; then + echo 1 + elif is_pitwo; then + echo 2 + else + echo 0 + fi +} + +is_live() { + grep -q "boot=live" $CMDLINE + return $? +} + +is_ssh() { + if pstree -p | egrep --quiet --extended-regexp ".*sshd.*\($$\)"; then + return 0 + else + return 1 + fi +} + +is_fkms() { + if grep -s -q okay /proc/device-tree/soc/v3d@7ec00000/status \ + /proc/device-tree/soc/firmwarekms@7e600000/status \ + /proc/device-tree/v3dbus/v3d@7ec04000/status; then + return 0 + else + return 1 + fi +} + +is_pulseaudio() { + PS=$(ps ax) + echo "$PS" | grep -q pulseaudio + return $? +} + +has_analog() { + if [ $(get_leds) -eq -1 ] ; then + return 0 + else + return 1 + fi +} + +is_installed() { + if [ "$(dpkg -l "$1" 2> /dev/null | tail -n 1 | cut -d ' ' -f 1)" != "ii" ]; then + return 1 + else + return 0 + fi +} + +deb_ver () { + ver=`cat /etc/debian_version | cut -d . -f 1` + echo $ver +} + +calc_wt_size() { + # NOTE: it's tempting to redirect stderr to /dev/null, so supress error + # output from tput. However in this case, tput detects neither stdout or + # stderr is a tty and so only gives default 80, 24 values + WT_HEIGHT=18 + WT_WIDTH=$(tput cols) + + if [ -z "$WT_WIDTH" ] || [ "$WT_WIDTH" -lt 60 ]; then + WT_WIDTH=80 + fi + if [ "$WT_WIDTH" -gt 178 ]; then + WT_WIDTH=120 + fi + WT_MENU_HEIGHT=$(($WT_HEIGHT-7)) +} + +do_change_pass() { + whiptail --msgbox "You will now be asked to enter a new password for the $USER user" 20 60 1 + passwd $USER && + whiptail --msgbox "Password changed successfully" 20 60 1 +} + +do_configure_keyboard() { + printf "Reloading keymap. This may take a short while\n" + if [ "$INTERACTIVE" = True ]; then + dpkg-reconfigure keyboard-configuration + else + local KEYMAP="$1" + sed -i /etc/default/keyboard -e "s/^XKBLAYOUT.*/XKBLAYOUT=\"$KEYMAP\"/" + dpkg-reconfigure -f noninteractive keyboard-configuration + fi + invoke-rc.d keyboard-setup start + setsid sh -c 'exec setupcon -k --force <> /dev/tty1 >&0 2>&1' + udevadm trigger --subsystem-match=input --action=change + return 0 +} + +do_change_locale() { + dpkg-reconfigure locales && \ + ASK_TO_REBOOT=2 && return 0 +} + +do_change_timezone() { + dpkg-reconfigure tzdata && \ + return 0 +} + +get_wifi_country() { + CODE=${1:-0} + IFACE="$(list_wlan_interfaces | head -n 1)" + if [ -z "$IFACE" ]; then + whiptail --msgbox "No wireless interface found" 20 60 + return 1 + fi + if ! wpa_cli -i "$IFACE" status > /dev/null 2>&1; then + whiptail --msgbox "Could not communicate with wpa_supplicant" 20 60 + return 1 + fi + wpa_cli -i "$IFACE" save_config > /dev/null 2>&1 + COUNTRY="$(wpa_cli -i "$IFACE" get country)" + if [ "$COUNTRY" = "FAIL" ]; then + return 1 + fi + if [ $CODE = 0 ]; then + echo "$COUNTRY" + fi + return 0 +} + +do_wifi_country() { + IFACE="$(list_wlan_interfaces | head -n 1)" + if [ -z "$IFACE" ]; then + whiptail --msgbox "No wireless interface found" 20 60 + return 1 + fi + + if ! wpa_cli -i "$IFACE" status > /dev/null 2>&1; then + whiptail --msgbox "Could not communicate with wpa_supplicant" 20 60 + return 1 + fi + + oIFS="$IFS" + value=$(cat /usr/share/zoneinfo/iso3166.tab | tail -n +26 | tr '\t' '/' | tr '\n' '/') + IFS="/" + COUNTRY=$(whiptail --menu "Select the country in which the Pi is to be used" 20 60 10 ${value} 3>&1 1>&2 2>&3) + if [ $? -eq 0 ];then + wpa_cli -i "$IFACE" set country "$COUNTRY" + wpa_cli -i "$IFACE" save_config > /dev/null 2>&1 + if iw reg set "$COUNTRY" 2> /dev/null; then + ASK_TO_REBOOT=1 + fi + if hash rfkill 2> /dev/null; then + rfkill unblock wifi + if is_pi ; then + for filename in /var/lib/systemd/rfkill/*:wlan ; do + echo 0 > $filename + done + fi + fi + whiptail --msgbox "Wireless LAN country set to $COUNTRY" 20 60 1 + fi + IFS=$oIFS +} + +get_labels_lang() { + oIFS="$IFS" + value=$(cat ${birdnetpi_dir}/model/labels_lang.txt | tr ',' ' ' | tr '\n' ' ') + IFS=" " + get_lang=$(whiptail --menu "Select the file that corresponds to your language" 20 60 10 ${value} 3>&1 1>&2 2>&3) + labels_lang=$(awk -F, "/$get_lang/{print \$2}" ${birdnetpi_dir}/model/labels_lang.txt) + if [ $? -eq 0 ];then + whiptail --msgbox "Your installation will now use $labels_lang" 20 60 1 + mv ${birdnetpi_dir}/model/labels.txt ${birdnetpi_dir}/model/labels.txt.old + unzip ${birdnetpi_dir}/model/labels_l18n.zip ${labels_lang} -d ${birdnetpi_dir}/model + mv ${birdnetpi_dir}/model/${labels_lang} ${birdnetpi_dir}/model/labels.txt + fi + IFS=$oIFS +} + +get_ssh() { + if service ssh status | grep -q inactive; then + echo 1 + else + echo 0 + fi +} + +do_ssh() { + if [ -e /var/log/regen_ssh_keys.log ] && ! grep -q "^finished" /var/log/regen_ssh_keys.log; then + whiptail --msgbox "Initial ssh key generation still running. Please wait and try again." 20 60 2 + return 1 + fi + DEFAULT=--defaultno + if [ $(get_ssh) -eq 0 ]; then + DEFAULT= + fi + whiptail --yesno \ + "Would you like the SSH server to be enabled?\n\nCaution: Default and weak passwords are a security risk when SSH is enabled!" $DEFAULT 20 60 2 + RET=$? + if [ $RET -eq 0 ]; then + ssh-keygen -A && + update-rc.d ssh enable && + invoke-rc.d ssh start && + STATUS=enabled + elif [ $RET -eq 1 ]; then + update-rc.d ssh disable && + invoke-rc.d ssh stop && + STATUS=disabled + else + return $RET + fi + whiptail --msgbox "The SSH server is $STATUS" 20 60 1 +} + +get_vnc() { + if systemctl status vncserver-x11-serviced.service | grep -q -w active; then + echo 0 + else + echo 1 + fi +} + +do_config_zram() { + if [ -e /etc/udev/rules.d/99-zram.rules ]; then + ## get current swap allocation from /etc/udev/rules.d/99-zram.rules + size="$(awk -F\" '{print $4}' /etc/udev/rules.d/99-zram.rules)" + else + size="4G" + fi + new_size=$(whiptail --inputbox "How much memory (G) should the zRAM swap partition have? Choose 1G, 2G, or 4G - 4G recommended" \ + 19 70 -- "$size" 3>&1 1>&2 2>&3) + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_install_zram() { + echo "Configuring zram.service" + touch /etc/modules-load.d/zram.conf + echo 'zram' > /etc/modules-load.d/zram.conf + touch /etc/modprobe.d/zram.conf + echo 'options zram num_devices=1' > /etc/modprobe.d/zram.conf + touch /etc/udev/rules.d/99-zram.rules + echo "KERNEL==\"zram0\", ATTR{disksize}=\"${new_size}\",TAG+=\"systemd\"" \ + > /etc/udev/rules.d/99-zram.rules + touch /etc/systemd/system/zram.service + echo "Installing zram.service" + cat << EOF > /etc/systemd/system/zram.service +[Unit] +Description=Swap with zram +After=multi-user.target + +[Service] +Type=oneshot +RemainAfterExit=true +ExecStartPre=/sbin/mkswap /dev/zram0 +ExecStart=/sbin/swapon /dev/zram0 +ExecStop=/sbin/swapoff /dev/zram0 + +[Install] +WantedBy=multi-user.target +EOF + systemctl enable zram + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_zram_menu() { + whiptail --yesno "Would like to enable the zram swapping kernel module?" --defaultno 20 60 2 + RET=$? + if [ $RET -eq 0 ]; then + do_config_zram + do_install_zram + STATUS=enabled + elif [ $RET -eq 1 ]; then + if [ -e /etc/udev/rules.d/99-zram.rules ];then + systemctl disable --now zram + fi + STATUS=disabled + fi + whiptail --msgbox "ZRAM swapping is $STATUS" 20 60 1 + return $RET +} + +do_vnc() { + DEFAULT=--defaultno + if [ $(get_vnc) -eq 0 ]; then + DEFAULT= + fi + whiptail --yesno "Would you like the VNC Server to be enabled?" $DEFAULT 20 60 2 + RET=$? + if [ $RET -eq 0 ]; then + if is_installed realvnc-vnc-server || apt-get install realvnc-vnc-server; then + systemctl enable vncserver-x11-serviced.service && + systemctl start vncserver-x11-serviced.service && + STATUS=enabled + else + return 1 + fi + elif [ $RET -eq 1 ]; then + if is_installed realvnc-vnc-server; then + systemctl disable vncserver-x11-serviced.service + systemctl stop vncserver-x11-serviced.service + fi + STATUS=disabled + else + return $RET + fi + whiptail --msgbox "The VNC Server is $STATUS" 20 60 1 +} + +do_audio() { + if is_pulseaudio ; then + oIFS="$IFS" + list=$(sudo -u $SUDO_USER XDG_RUNTIME_DIR=/run/user/$SUDO_UID pacmd list-sources | grep -B1 -e 'alsa.card_name' -e 'name.*input' | grep -A4 index | sed -e s/*//g | sed s/^[' '\\t]*//g | grep -e index -e card_name | sed s/'index: '//g | sed s/'alsa.card_name = '//g | sed s/\"//g | tr '\n' '\/') + if ! [ -z "$list" ] ; then + IFS="/" + AUDIO_IN=$(whiptail --menu "Choose the audio input" 20 60 10 ${list} 3>&1 1>&2 2>&3) + return 0 + else + whiptail --msgbox "No internal audio devices found" 20 60 1 + return 1 + fi + if [ $? -eq 0 ]; then + sudo -u $SUDO_USER XDG_RUNTIME_DIR=/run/user/$SUDO_UID pactl set-default-source "$AUDIO_IN" + fi + IFS=$oIFS + fi + sudo -u $SUDO_USER pulseaudio -k +} + +list_wlan_interfaces() { + for dir in /sys/class/net/*/wireless; do + if [ -d "$dir" ]; then + basename "$(dirname "$dir")" + fi + done +} + +do_wifi_ssid_passphrase() { + RET=0 + IFACE_LIST="$(list_wlan_interfaces)" + IFACE="$(echo "$IFACE_LIST" | head -n 1)" + + if [ -z "$IFACE" ]; then + whiptail --msgbox "No wireless interface found" 20 60 + return 1 + fi + + if ! wpa_cli -i "$IFACE" status > /dev/null 2>&1; then + whiptail --msgbox "Could not communicate with wpa_supplicant" 20 60 + return 1 + fi + + if [ -z "$(get_wifi_country)" ]; then + do_wifi_country + fi + + SSID="$1" + while [ -z "$SSID" ] ; do + SSID=$(whiptail --inputbox "Please enter SSID" 20 60 3>&1 1>&2 2>&3) + if [ $? -ne 0 ]; then + return 0 + elif [ -z "$SSID" ]; then + whiptail --msgbox "SSID cannot be empty. Please try again." 20 60 + fi + done + + PASSPHRASE="$2" + PASSPHRASE=$(whiptail --passwordbox "Please enter passphrase. Leave it empty if none." 20 60 3>&1 1>&2 2>&3) + if [ $? -ne 0 ]; then + return 0 + else + return 1 + fi + + # Escape special characters for embedding in regex below + local ssid="$(echo "$SSID" \ + | sed 's;\\;\\\\;g' \ + | sed -e 's;\.;\\\.;g' \ + -e 's;\*;\\\*;g' \ + -e 's;\+;\\\+;g' \ + -e 's;\?;\\\?;g' \ + -e 's;\^;\\\^;g' \ + -e 's;\$;\\\$;g' \ + -e 's;\/;\\\/;g' \ + -e 's;\[;\\\[;g' \ + -e 's;\];\\\];g' \ + -e 's;{;\\{;g' \ + -e 's;};\\};g' \ + -e 's;(;\\(;g' \ + -e 's;);\\);g' \ + -e 's;";\\\\\";g')" + + wpa_cli -i "$IFACE" list_networks \ + | tail -n +2 | cut -f -2 | grep -P "\t$ssid$" | cut -f1 \ + | while read ID; do + wpa_cli -i "$IFACE" remove_network "$ID" > /dev/null 2>&1 + done + + ID="$(wpa_cli -i "$IFACE" add_network)" + wpa_cli -i "$IFACE" set_network "$ID" ssid "\"$SSID\"" 2>&1 | grep -q "OK" + RET=$((RET + $?)) + + if [ -z "$PASSPHRASE" ]; then + wpa_cli -i "$IFACE" set_network "$ID" key_mgmt NONE 2>&1 | grep -q "OK" + RET=$((RET + $?)) + else + wpa_cli -i "$IFACE" set_network "$ID" psk "\"$PASSPHRASE\"" 2>&1 | grep -q "OK" + RET=$((RET + $?)) + fi + + if [ $RET -eq 0 ]; then + wpa_cli -i "$IFACE" enable_network "$ID" > /dev/null 2>&1 + else + wpa_cli -i "$IFACE" remove_network "$ID" > /dev/null 2>&1 + whiptail --msgbox "Failed to set SSID or passphrase" 20 60 + fi + wpa_cli -i "$IFACE" save_config > /dev/null 2>&1 + + echo "$IFACE_LIST" | while read IFACE; do + wpa_cli -i "$IFACE" reconfigure > /dev/null 2>&1 + done + + return $RET +} + +do_reget_birdnetpi_urls() { + birdnetpi_url=$(whiptail --inputbox "Put your domain here. Example: \"https://birdnetpi.pmcgui.xyz\"." \ + 19 70 -- "https://" 3>&1 1>&2 2>&3) extractionlog_url=$(whiptail --inputbox "Put your domain here. Example: \"https://extractionlog.pmcgui.xyz\"." 19 70 -- "https://" 3>&1 1>&2 2>&3) birdnetlog_url=$(whiptail --inputbox "Put your domain here. Example: \"https://birdnetlog.pmcgui.xyz\"." 19 70 -- "https://" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + else + return 1 + fi +} + +do_reget_db_pwd() { + db_pwd=$(whiptail --inputbox "Please set the password the 'birder' user will use to access the database." \ + 19 70 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_reget_birdweather_id() { + birdweather_id=$(whiptail --inputbox "Input your BirdWeather ID" \ + 19 70 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + + +do_reget_caddy_pwd() { + caddy_pwd=$(whiptail --inputbox "Please set the password for the web interface." \ + 19 70 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + + +do_reget_lon() { + lon="$(curl -s4 ifconfig.co/json | awk '/lon/ {print $2}' | tr -d ',')" + new_lon=$(whiptail --inputbox "Please set the longitude where recordings will take place." \ + 19 70 -- "$lon" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_reget_lat() { + lat="$(curl -s4 ifconfig.co/json | awk '/lat/ {print $2}' | tr -d ',')" + new_lat=$(whiptail --inputbox "Please set the latitude where recordings will take place." \ + 19 70 -- "$lat" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_confidence() { + confidence="$(awk -F= '/CONFIDENCE=/ {print $2}' ${birdnetpi_dir}/birdnet.conf)" + new_confidence=$(whiptail --inputbox "Please set the minimum confidence score BirdNET-Lite should use." \ + 19 70 -- "$confidence" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + + +do_get_overlap() { + overlap="$(awk -F= '/OVERLAP=/ {print $2}' ${birdnetpi_dir}/birdnet.conf)" + new_overlap=$(whiptail --inputbox "Please set the overlap BirdNET-Lite should use." \ + 19 70 -- "$overlap" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + + +do_get_sensitivity() { + sensitivity="$(awk -F= '/SENSITIVITY=/ {print $2}' ${birdnetpi_dir}/birdnet.conf)" + new_sensitivity=$(whiptail --inputbox "Please set the simoid sensitivty BirdNET-Lite should use." \ + 19 70 -- "$sensitivity" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_birdnetlog_url() { + birdnetlog_url=$(whiptail --inputbox "Put your domain here. Example: \"https://birdnetlog.pmcgui.xyz\"." \ + 19 70 -- "https://" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_extractionlog_url() { + extractionlog_url=$(whiptail --inputbox "Put your domain here. Example: \"https://extractionlog.pmcgui.xyz\"." \ + 19 70 -- "https://" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_birdnetpi_url() { + birdnetpi_url=$(whiptail --inputbox "Put your domain here. Example: \"https://birdnetpi.pmcgui.xyz\"." \ + 19 70 -- "https://" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_birdweather_id() { + birdweather_id=$(whiptail --inputbox "Input your BirdWeather ID" \ + 19 70 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_db_pwd() { + db_pwd=$(whiptail --inputbox "Please set the password the 'birder' user will use to access the database." \ + 19 70 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_ice_pwd() { + ice_pwd=$(whiptail --inputbox "Please set the password for the live stream." \ + 19 70 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_caddy_pwd() { + caddy_pwd=$(whiptail --inputbox "Please set the password for the web interface." \ + 19 70 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + + +do_get_lon() { + lon="$(curl -s4 ifconfig.co/json | awk '/lon/ {print $2}' | tr -d ',')" + new_lon=$(whiptail --inputbox "Please set the longitude where recordings will take place." \ + 19 70 -- "$lon" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_lat() { + lat="$(curl -s4 ifconfig.co/json | awk '/lat/ {print $2}' | tr -d ',')" + new_lat=$(whiptail --inputbox "Please set the latitude where recordings will take place." \ + 19 70 -- "$lat" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_update_os() { + apt update && apt -y full-upgrade && \ + ASK_TO_REBOOT=1 +} + +do_update_birdnet() { + sudo -E -upi ${birdnetpi_dir}/scripts/update_birdnet.sh +} + +do_install_birdnet() { + sudo -E -upi ${birdnetpi_dir}/Birders_Guide_Installer.sh && \ + ASK_TO_REBOOT=1 +} + +insist_on_reboot() { + if [ $ASK_TO_REBOOT -eq 2 ]; then + whiptail --yesno "You really should reboot. Do that now?" 20 60 2 + if [ $? -eq 0 ]; then # yes + sync + reboot + fi + fi +} + +do_finish() { + if [ $ASK_TO_REBOOT -eq 1 ]; then + whiptail --yesno "Would you like to reboot now?" 20 60 2 + if [ $? -eq 0 ]; then # yes + sync + reboot + fi + elif [ $ASK_TO_REBOOT -eq 2 ]; then + whiptail --yesno "You really should reboot. Do that now?" 20 60 2 + if [ $? -eq 0 ]; then # yes + sync + reboot + fi + fi + exit 0 +} + +# Everything else needs to be run as root +if [ $(id -u) -ne 0 ]; then + printf "Script must be run as root. Try 'sudo birdnet-pi-config'\n" + exit 1 +fi + +do_advanced_reconfig_menu() { + MENU=9 + while [ $MENU -eq 9 ];do + if is_pi ; then + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --menu "BirdNET-Pi Configuration Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ + "Sensitivity" "Set the sigmoid sensitivity" \ + "Confidence" "Set the minimum confidence score required for a detection" \ + "Overlap" "Set the analysis overlap in seconds" \ + "BirdNET-Pi URLs" "Set the URLs your installation should use" \ + 3>&1 1>&2 2>&3) + else + exit + fi + RET=$? + if [ $RET -eq 1 ]; then + return 0 + MENU=0 + elif [ $RET -eq 0 ]; then + case "$FUN" in + Sens*) do_get_sensitivity;; + Confi*) do_get_confidence;; + Overlap*) do_get_overlap;; + Bird*) do_reget_birdnetpi_urls;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi + done +} + +do_interface_menu() { + MENU=6 + while [ $MENU -eq 6 ];do + if is_pi ; then + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --menu "Interfacing Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ + "SSH" "Enable/disable remote command line access using SSH" \ + "VNC" "Enable/disable graphical remote access using RealVNC" \ + 3>&1 1>&2 2>&3) + else + exit + fi + RET=$? + if [ $RET -eq 1 ]; then + return 0 + MENU=0 + elif [ $RET -eq 0 ]; then + case "$FUN" in + SSH*) do_ssh ;; + VNC*) do_vnc ;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi + done +} + +do_advanced_config_menu() { + MENU=5 + while [ $MENU -eq 5 ];do + if is_pi ; then + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --menu "BirdNET-Pi Configuration Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ + "Sensitivity" "Set the sigmoid sensitivity" \ + "Confidence" "Set the minimum confidence score required for a detection" \ + "Overlap" "Set the analysis overlap in seconds" \ + "BirdNET-Pi URLs" "Set the URLs your installation should use" \ + 3>&1 1>&2 2>&3) + else + exit + fi + RET=$? + if [ $RET -eq 1 ]; then + return 0 + MENU=0 + elif [ $RET -eq 0 ]; then + case "$FUN" in + Sens*) do_get_sensitivity;; + Confi*) do_get_confidence;; + Overlap*) do_get_overlap;; + Bird*) do_get_birdnetpi_url; do_get_birdnetlog_url; do_get_extractionlog_url;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi + done +} + +do_system_menu() { + MENU=4 + while [ $MENU -eq 4 ];do + if is_pi ; then + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --menu "System Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ + "Password" "Change password for the '$USER' user" \ + "Audio" "Select audio device you'd like BirdNET-Pi to use" \ + "Wireless LAN" "Enter SSID and passphrase" \ + "Update the OS" "Update the underlying operating system" \ + "Interface Options" "Enable/Disable SSH and VNC" \ + "Configure zRAM" "Enable/Disable zRAM" \ + "Timezone" "Configure time zone" \ + "Keyboard" "Set keyboard layout to match your keyboard" \ + "WLAN Country" "Set legal wireless channels for your country" \ + 3>&1 1>&2 2>&3) + else + exit + fi + RET=$? + if [ $RET -eq 1 ]; then + return 0 + MENU=0 + elif [ $RET -eq 0 ]; then + case "$FUN" in + Password*) do_change_pass ;; + Audio*) do_audio ;; + Wireless*) do_wifi_ssid_passphrase ;; + Update*) do_update_os ;; + Interface*) do_interface_menu ;; + Configure*) do_zram_menu ;; + Time*) do_change_timezone; insist_on_reboot ;; + Key*) do_configure_keyboard ;; + WLAN*) do_wifi_country ;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi + done +} + + +do_reconfig_birdnet_menu() { + MENU=3 + while [ $MENU -eq 3 ];do + if is_pi ; then + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --menu "BirdNET-Pi Re-configuration Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ + "Latitude " "Set the latitude your system should use" \ + "Longitude" "Set the longitude your system should use" \ + "Caddy Password" "Set the web interface password" \ + "Database Password" "Set the password BirdNET-Pi will use to access the DB" \ + "BirdWeather ID" "Input your BirdWeather ID if you have one" \ + "Advanced Settings" "Sensitivity, Overlap, Confidence, URLs" \ + 3>&1 1>&2 2>&3) + else + exit + fi + RET=$? + if [ $RET -eq 1 ]; then + return 0 + MENU=0 + elif [ $RET -eq 0 ]; then + case "$FUN" in + Lat*) do_reget_lat;; + Lon*) do_reget_lon;; + Cad*) do_reget_caddy_pwd;; + Data*) do_reget_db_pwd;; + Bird*) do_reget_birdweather_id;; + Advanced*) do_advanced_reconfig_menu;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi + done +} + +do_config_birdnet_menu() { + MENU=2 + while [ $MENU -eq 2 ];do + if is_pi ; then + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --menu "BirdNET-Pi Configuration Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ + "Latitude " "Set the latitude your system should use" \ + "Longitude" "Set the longitude your system should use" \ + "Caddy Password" "Set the web interface password" \ + "IceCast2 Password" "Set the IceCast2 password" \ + "Database Password" "Set the password BirdNET-Pi will use to access the DB" \ + "BirdWeather ID" "Input your BirdWeather ID if you have one" \ + "Set Custom URLS" "Designate custom URLs for the web services if you've set that up" \ + 3>&1 1>&2 2>&3) + else + exit + fi + RET=$? + if [ $RET -eq 1 ]; then + return 0 + MENU=0 + elif [ $RET -eq 0 ]; then + case "$FUN" in + Lat*) do_get_lat;; + Lon*) do_get_lon;; + Cad*) do_get_caddy_pwd;; + Ice*) do_get_ice_pwd;; + Data*) do_get_db_pwd;; + Bird*) do_get_birdweather_id;; + Set*) do_get_birdnetpi_url; do_get_birdnetlog_url; do_get_extractionlog_url;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi + done +} + +do_internationalisation_menu() { + MENU=1 + while [ $MENU -eq 1 ];do + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --menu "Localisation Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ + "System Locale" "Configure the system language and regional settings" \ + "labels.txt" "Set the language to use for species detection" \ + "Time Zone" "Set the Time Zone" \ + 3>&1 1>&2 2>&3) + RET=$? + if [ $RET -eq 1 ]; then + return 0 + MENU=0 + elif [ $RET -eq 0 ]; then + case "$FUN" in + System*) do_change_locale;; + label*) get_labels_lang;; + Time*) do_change_timezone;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi + done +} + + + +# +# Interactive use loop +# +[ -e $CONFIG ] || touch $CONFIG +calc_wt_size +while [ "$USER" = "root" ] || [ -z "$USER" ]; do + if ! USER=$(whiptail --inputbox "birdnet-pi-config could not determine the default user.\\n\\nWhat user should these settings apply to?" 20 60 pi 3>&1 1>&2 2>&3); then + return 0 + fi +done +while true; do + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --backtitle "$(cat /proc/device-tree/model)" --menu "Setup Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Finish --ok-button Select \ + "Step 1" "Configure language and timezone" \ + "Step 2" "Configure BirdNET-Pi before installation" \ + "Step 3" "Install BirdNET-Pi" \ + "Step 4" "Reconfigure BirdNET-Pi AFTER installation" \ + "Step 5" "Update BirdNET-Pi (run this if you changed URLs)" \ + "System Options" "Configure system settings" \ + 3>&1 1>&2 2>&3) + RET=$? + if [ $RET -eq 1 ]; then + do_finish + elif [ $RET -eq 0 ]; then + case "$FUN" in + *1) do_internationalisation_menu ;; + *2) do_config_birdnet_menu ;; + *3) do_install_birdnet;; + *4) do_reconfig_birdnet_menu ;; + *5) do_update_birdnet;; + Sys*) do_system_menu ;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi +done diff --git a/scripts/birdnet-pi.config.sh b/scripts/birdnet-pi.config.sh new file mode 100755 index 0000000..f037783 --- /dev/null +++ b/scripts/birdnet-pi.config.sh @@ -0,0 +1,997 @@ +#!/usr/bin/env -S sudo -E sh +# Altered from raspi-config tool below +# https://github.com/RPi-Distro/birdnet-pi-config +# +# See LICENSE file for copyright and license details +# Copyright (c) 2012 Alex Bradbury +set -x +birdnetpi_dir=/home/pi/BirdNET-Pi +birders_config=${birdnetpi_dir}/Birders_Guide_Installer_Configuration.txt +branch=forms +INTERACTIVE=True +ASK_TO_REBOOT=0 +BLACKLIST=/etc/modprobe.d/raspi-blacklist.conf +CONFIG=/boot/config.txt + +USER=${SUDO_USER:-$(who -m | awk '{ print $1 }')} + +is_pi () { + ARCH=$(dpkg --print-architecture) + if [ "$ARCH" = "armhf" ] || [ "$ARCH" = "arm64" ] ; then + return 0 + else + return 1 + fi +} + +if is_pi ; then + CMDLINE=/boot/cmdline.txt +else + CMDLINE=/proc/cmdline +fi + +is_pione() { + if grep -q "^Revision\s*:\s*00[0-9a-fA-F][0-9a-fA-F]$" /proc/cpuinfo; then + return 0 + elif grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]0[0-36][0-9a-fA-F]$" /proc/cpuinfo ; then + return 0 + else + return 1 + fi +} + +is_pitwo() { + grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]04[0-9a-fA-F]$" /proc/cpuinfo + return $? +} + +is_pizero() { + grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]0[9cC][0-9a-fA-F]$" /proc/cpuinfo + return $? +} + +is_pifour() { + grep -q "^Revision\s*:\s*[ 123][0-9a-fA-F][0-9a-fA-F]3[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]$" /proc/cpuinfo + return $? +} + +get_pi_type() { + if is_pione; then + echo 1 + elif is_pitwo; then + echo 2 + else + echo 0 + fi +} + +is_live() { + grep -q "boot=live" $CMDLINE + return $? +} + +is_ssh() { + if pstree -p | egrep --quiet --extended-regexp ".*sshd.*\($$\)"; then + return 0 + else + return 1 + fi +} + +is_fkms() { + if grep -s -q okay /proc/device-tree/soc/v3d@7ec00000/status \ + /proc/device-tree/soc/firmwarekms@7e600000/status \ + /proc/device-tree/v3dbus/v3d@7ec04000/status; then + return 0 + else + return 1 + fi +} + +is_pulseaudio() { + PS=$(ps ax) + echo "$PS" | grep -q pulseaudio + return $? +} + +has_analog() { + if [ $(get_leds) -eq -1 ] ; then + return 0 + else + return 1 + fi +} + +is_installed() { + if [ "$(dpkg -l "$1" 2> /dev/null | tail -n 1 | cut -d ' ' -f 1)" != "ii" ]; then + return 1 + else + return 0 + fi +} + +deb_ver () { + ver=`cat /etc/debian_version | cut -d . -f 1` + echo $ver +} + +calc_wt_size() { + # NOTE: it's tempting to redirect stderr to /dev/null, so supress error + # output from tput. However in this case, tput detects neither stdout or + # stderr is a tty and so only gives default 80, 24 values + WT_HEIGHT=18 + WT_WIDTH=$(tput cols) + + if [ -z "$WT_WIDTH" ] || [ "$WT_WIDTH" -lt 60 ]; then + WT_WIDTH=80 + fi + if [ "$WT_WIDTH" -gt 178 ]; then + WT_WIDTH=120 + fi + WT_MENU_HEIGHT=$(($WT_HEIGHT-7)) +} + +do_change_pass() { + whiptail --msgbox "You will now be asked to enter a new password for the $USER user" 20 60 1 + passwd $USER && + whiptail --msgbox "Password changed successfully" 20 60 1 +} + +do_configure_keyboard() { + printf "Reloading keymap. This may take a short while\n" + if [ "$INTERACTIVE" = True ]; then + dpkg-reconfigure keyboard-configuration + else + local KEYMAP="$1" + sed -i /etc/default/keyboard -e "s/^XKBLAYOUT.*/XKBLAYOUT=\"$KEYMAP\"/" + dpkg-reconfigure -f noninteractive keyboard-configuration + fi + invoke-rc.d keyboard-setup start + setsid sh -c 'exec setupcon -k --force <> /dev/tty1 >&0 2>&1' + udevadm trigger --subsystem-match=input --action=change + return 0 +} + +do_change_locale() { + dpkg-reconfigure locales && \ + ASK_TO_REBOOT=2 && return 0 +} + +do_change_timezone() { + dpkg-reconfigure tzdata && \ + return 0 +} + +get_wifi_country() { + CODE=${1:-0} + IFACE="$(list_wlan_interfaces | head -n 1)" + if [ -z "$IFACE" ]; then + whiptail --msgbox "No wireless interface found" 20 60 + return 1 + fi + if ! wpa_cli -i "$IFACE" status > /dev/null 2>&1; then + whiptail --msgbox "Could not communicate with wpa_supplicant" 20 60 + return 1 + fi + wpa_cli -i "$IFACE" save_config > /dev/null 2>&1 + COUNTRY="$(wpa_cli -i "$IFACE" get country)" + if [ "$COUNTRY" = "FAIL" ]; then + return 1 + fi + if [ $CODE = 0 ]; then + echo "$COUNTRY" + fi + return 0 +} + +do_wifi_country() { + IFACE="$(list_wlan_interfaces | head -n 1)" + if [ -z "$IFACE" ]; then + whiptail --msgbox "No wireless interface found" 20 60 + return 1 + fi + + if ! wpa_cli -i "$IFACE" status > /dev/null 2>&1; then + whiptail --msgbox "Could not communicate with wpa_supplicant" 20 60 + return 1 + fi + + oIFS="$IFS" + value=$(cat /usr/share/zoneinfo/iso3166.tab | tail -n +26 | tr '\t' '/' | tr '\n' '/') + IFS="/" + COUNTRY=$(whiptail --menu "Select the country in which the Pi is to be used" 20 60 10 ${value} 3>&1 1>&2 2>&3) + if [ $? -eq 0 ];then + wpa_cli -i "$IFACE" set country "$COUNTRY" + wpa_cli -i "$IFACE" save_config > /dev/null 2>&1 + if iw reg set "$COUNTRY" 2> /dev/null; then + ASK_TO_REBOOT=1 + fi + if hash rfkill 2> /dev/null; then + rfkill unblock wifi + if is_pi ; then + for filename in /var/lib/systemd/rfkill/*:wlan ; do + echo 0 > $filename + done + fi + fi + whiptail --msgbox "Wireless LAN country set to $COUNTRY" 20 60 1 + fi + IFS=$oIFS +} + +get_labels_lang() { + oIFS="$IFS" + value=$(cat ${birdnetpi_dir}/model/labels_lang.txt | tr ',' ' ' | tr '\n' ' ') + IFS=" " + get_lang=$(whiptail --menu "Select the file that corresponds to your language" 20 60 10 ${value} 3>&1 1>&2 2>&3) + labels_lang=$(awk -F, "/$get_lang/{print \$2}" ${birdnetpi_dir}/model/labels_lang.txt) + if [ $? -eq 0 ];then + whiptail --msgbox "Your installation will now use $labels_lang" 20 60 1 + mv ${birdnetpi_dir}/model/labels.txt ${birdnetpi_dir}/model/labels.txt.old + unzip ${birdnetpi_dir}/model/labels_l18n.zip ${labels_lang} -d ${birdnetpi_dir}/model + mv ${birdnetpi_dir}/model/${labels_lang} ${birdnetpi_dir}/model/labels.txt + fi + IFS=$oIFS +} + +get_ssh() { + if service ssh status | grep -q inactive; then + echo 1 + else + echo 0 + fi +} + +do_ssh() { + if [ -e /var/log/regen_ssh_keys.log ] && ! grep -q "^finished" /var/log/regen_ssh_keys.log; then + whiptail --msgbox "Initial ssh key generation still running. Please wait and try again." 20 60 2 + return 1 + fi + DEFAULT=--defaultno + if [ $(get_ssh) -eq 0 ]; then + DEFAULT= + fi + whiptail --yesno \ + "Would you like the SSH server to be enabled?\n\nCaution: Default and weak passwords are a security risk when SSH is enabled!" $DEFAULT 20 60 2 + RET=$? + if [ $RET -eq 0 ]; then + ssh-keygen -A && + update-rc.d ssh enable && + invoke-rc.d ssh start && + STATUS=enabled + elif [ $RET -eq 1 ]; then + update-rc.d ssh disable && + invoke-rc.d ssh stop && + STATUS=disabled + else + return $RET + fi + whiptail --msgbox "The SSH server is $STATUS" 20 60 1 +} + +get_vnc() { + if systemctl status vncserver-x11-serviced.service | grep -q -w active; then + echo 0 + else + echo 1 + fi +} + +do_config_zram() { + if [ -e /etc/udev/rules.d/99-zram.rules ]; then + ## get current swap allocation from /etc/udev/rules.d/99-zram.rules + size="$(awk -F\" '{print $4}' /etc/udev/rules.d/99-zram.rules)" + else + size="4G" + fi + new_size=$(whiptail --inputbox "How much memory (G) should the zRAM swap partition have? Choose 1G, 2G, or 4G - 4G recommended" \ + 19 70 -- "$size" 3>&1 1>&2 2>&3) + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_install_zram() { + echo "Configuring zram.service" + touch /etc/modules-load.d/zram.conf + echo 'zram' > /etc/modules-load.d/zram.conf + touch /etc/modprobe.d/zram.conf + echo 'options zram num_devices=1' > /etc/modprobe.d/zram.conf + touch /etc/udev/rules.d/99-zram.rules + echo "KERNEL==\"zram0\", ATTR{disksize}=\"${new_size}\",TAG+=\"systemd\"" \ + > /etc/udev/rules.d/99-zram.rules + touch /etc/systemd/system/zram.service + echo "Installing zram.service" + cat << EOF > /etc/systemd/system/zram.service +[Unit] +Description=Swap with zram +After=multi-user.target + +[Service] +Type=oneshot +RemainAfterExit=true +ExecStartPre=/sbin/mkswap /dev/zram0 +ExecStart=/sbin/swapon /dev/zram0 +ExecStop=/sbin/swapoff /dev/zram0 + +[Install] +WantedBy=multi-user.target +EOF + systemctl enable zram + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_zram_menu() { + whiptail --yesno "Would like to enable the zram swapping kernel module?" --defaultno 20 60 2 + RET=$? + if [ $RET -eq 0 ]; then + do_config_zram + do_install_zram + STATUS=enabled + elif [ $RET -eq 1 ]; then + if [ -e /etc/udev/rules.d/99-zram.rules ];then + systemctl disable --now zram + fi + STATUS=disabled + fi + whiptail --msgbox "ZRAM swapping is $STATUS" 20 60 1 + return $RET +} + +do_vnc() { + DEFAULT=--defaultno + if [ $(get_vnc) -eq 0 ]; then + DEFAULT= + fi + whiptail --yesno "Would you like the VNC Server to be enabled?" $DEFAULT 20 60 2 + RET=$? + if [ $RET -eq 0 ]; then + if is_installed realvnc-vnc-server || apt-get install realvnc-vnc-server; then + systemctl enable vncserver-x11-serviced.service && + systemctl start vncserver-x11-serviced.service && + STATUS=enabled + else + return 1 + fi + elif [ $RET -eq 1 ]; then + if is_installed realvnc-vnc-server; then + systemctl disable vncserver-x11-serviced.service + systemctl stop vncserver-x11-serviced.service + fi + STATUS=disabled + else + return $RET + fi + whiptail --msgbox "The VNC Server is $STATUS" 20 60 1 +} + +do_audio() { + if is_pulseaudio ; then + oIFS="$IFS" + list=$(sudo -u $SUDO_USER XDG_RUNTIME_DIR=/run/user/$SUDO_UID pacmd list-sources | grep -B1 -e 'alsa.card_name' -e 'name.*input' | grep -A4 index | sed -e s/*//g | sed s/^[' '\\t]*//g | grep -e index -e card_name | sed s/'index: '//g | sed s/'alsa.card_name = '//g | sed s/\"//g | tr '\n' '\/') + if ! [ -z "$list" ] ; then + IFS="/" + AUDIO_IN=$(whiptail --menu "Choose the audio input" 20 60 10 ${list} 3>&1 1>&2 2>&3) + return 0 + else + whiptail --msgbox "No internal audio devices found" 20 60 1 + return 1 + fi + if [ $? -eq 0 ]; then + sudo -u $SUDO_USER XDG_RUNTIME_DIR=/run/user/$SUDO_UID pactl set-default-source "$AUDIO_IN" + fi + IFS=$oIFS + fi + sudo -u $SUDO_USER pulseaudio -k +} + +list_wlan_interfaces() { + for dir in /sys/class/net/*/wireless; do + if [ -d "$dir" ]; then + basename "$(dirname "$dir")" + fi + done +} + +do_wifi_ssid_passphrase() { + RET=0 + IFACE_LIST="$(list_wlan_interfaces)" + IFACE="$(echo "$IFACE_LIST" | head -n 1)" + + if [ -z "$IFACE" ]; then + whiptail --msgbox "No wireless interface found" 20 60 + return 1 + fi + + if ! wpa_cli -i "$IFACE" status > /dev/null 2>&1; then + whiptail --msgbox "Could not communicate with wpa_supplicant" 20 60 + return 1 + fi + + if [ -z "$(get_wifi_country)" ]; then + do_wifi_country + fi + + SSID="$1" + while [ -z "$SSID" ] ; do + SSID=$(whiptail --inputbox "Please enter SSID" 20 60 3>&1 1>&2 2>&3) + if [ $? -ne 0 ]; then + return 0 + elif [ -z "$SSID" ]; then + whiptail --msgbox "SSID cannot be empty. Please try again." 20 60 + fi + done + + PASSPHRASE="$2" + PASSPHRASE=$(whiptail --passwordbox "Please enter passphrase. Leave it empty if none." 20 60 3>&1 1>&2 2>&3) + if [ $? -ne 0 ]; then + return 0 + else + return 1 + fi + + # Escape special characters for embedding in regex below + local ssid="$(echo "$SSID" \ + | sed 's;\\;\\\\;g' \ + | sed -e 's;\.;\\\.;g' \ + -e 's;\*;\\\*;g' \ + -e 's;\+;\\\+;g' \ + -e 's;\?;\\\?;g' \ + -e 's;\^;\\\^;g' \ + -e 's;\$;\\\$;g' \ + -e 's;\/;\\\/;g' \ + -e 's;\[;\\\[;g' \ + -e 's;\];\\\];g' \ + -e 's;{;\\{;g' \ + -e 's;};\\};g' \ + -e 's;(;\\(;g' \ + -e 's;);\\);g' \ + -e 's;";\\\\\";g')" + + wpa_cli -i "$IFACE" list_networks \ + | tail -n +2 | cut -f -2 | grep -P "\t$ssid$" | cut -f1 \ + | while read ID; do + wpa_cli -i "$IFACE" remove_network "$ID" > /dev/null 2>&1 + done + + ID="$(wpa_cli -i "$IFACE" add_network)" + wpa_cli -i "$IFACE" set_network "$ID" ssid "\"$SSID\"" 2>&1 | grep -q "OK" + RET=$((RET + $?)) + + if [ -z "$PASSPHRASE" ]; then + wpa_cli -i "$IFACE" set_network "$ID" key_mgmt NONE 2>&1 | grep -q "OK" + RET=$((RET + $?)) + else + wpa_cli -i "$IFACE" set_network "$ID" psk "\"$PASSPHRASE\"" 2>&1 | grep -q "OK" + RET=$((RET + $?)) + fi + + if [ $RET -eq 0 ]; then + wpa_cli -i "$IFACE" enable_network "$ID" > /dev/null 2>&1 + else + wpa_cli -i "$IFACE" remove_network "$ID" > /dev/null 2>&1 + whiptail --msgbox "Failed to set SSID or passphrase" 20 60 + fi + wpa_cli -i "$IFACE" save_config > /dev/null 2>&1 + + echo "$IFACE_LIST" | while read IFACE; do + wpa_cli -i "$IFACE" reconfigure > /dev/null 2>&1 + done + + return $RET +} + +do_reget_birdnetpi_urls() { + birdnetpi_url=$(whiptail --inputbox "Put your domain here. Example: \"https://birdnetpi.pmcgui.xyz\"." \ + 19 70 -- "https://" 3>&1 1>&2 2>&3) extractionlog_url=$(whiptail --inputbox "Put your domain here. Example: \"https://extractionlog.pmcgui.xyz\"." 19 70 -- "https://" 3>&1 1>&2 2>&3) birdnetlog_url=$(whiptail --inputbox "Put your domain here. Example: \"https://birdnetlog.pmcgui.xyz\"." 19 70 -- "https://" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + else + return 1 + fi +} + +do_reget_db_pwd() { + db_pwd=$(whiptail --inputbox "Please set the password the 'birder' user will use to access the database." \ + 19 70 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_reget_birdweather_id() { + birdweather_id=$(whiptail --inputbox "Input your BirdWeather ID" \ + 19 70 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + + +do_reget_caddy_pwd() { + caddy_pwd=$(whiptail --inputbox "Please set the password for the web interface." \ + 19 70 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + + +do_reget_lon() { + lon="$(curl -s4 ifconfig.co/json | awk '/lon/ {print $2}' | tr -d ',')" + new_lon=$(whiptail --inputbox "Please set the longitude where recordings will take place." \ + 19 70 -- "$lon" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_reget_lat() { + lat="$(curl -s4 ifconfig.co/json | awk '/lat/ {print $2}' | tr -d ',')" + new_lat=$(whiptail --inputbox "Please set the latitude where recordings will take place." \ + 19 70 -- "$lat" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_confidence() { + confidence="$(awk -F= '/CONFIDENCE=/ {print $2}' ${birdnetpi_dir}/birdnet.conf)" + new_confidence=$(whiptail --inputbox "Please set the minimum confidence score BirdNET-Lite should use." \ + 19 70 -- "$confidence" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + + +do_get_overlap() { + overlap="$(awk -F= '/OVERLAP=/ {print $2}' ${birdnetpi_dir}/birdnet.conf)" + new_overlap=$(whiptail --inputbox "Please set the overlap BirdNET-Lite should use." \ + 19 70 -- "$overlap" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + + +do_get_sensitivity() { + sensitivity="$(awk -F= '/SENSITIVITY=/ {print $2}' ${birdnetpi_dir}/birdnet.conf)" + new_sensitivity=$(whiptail --inputbox "Please set the simoid sensitivty BirdNET-Lite should use." \ + 19 70 -- "$sensitivity" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/rewrite_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_birdnetlog_url() { + birdnetlog_url=$(whiptail --inputbox "Put your domain here. Example: \"https://birdnetlog.pmcgui.xyz\"." \ + 19 70 -- "https://" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_extractionlog_url() { + extractionlog_url=$(whiptail --inputbox "Put your domain here. Example: \"https://extractionlog.pmcgui.xyz\"." \ + 19 70 -- "https://" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_birdnetpi_url() { + birdnetpi_url=$(whiptail --inputbox "Put your domain here. Example: \"https://birdnetpi.pmcgui.xyz\"." \ + 19 70 -- "https://" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_birdweather_id() { + birdweather_id=$(whiptail --inputbox "Input your BirdWeather ID" \ + 19 70 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_db_pwd() { + db_pwd=$(whiptail --inputbox "Please set the password the 'birder' user will use to access the database." \ + 19 70 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_ice_pwd() { + ice_pwd=$(whiptail --inputbox "Please set the password for the live stream." \ + 19 70 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_caddy_pwd() { + caddy_pwd=$(whiptail --inputbox "Please set the password for the web interface." \ + 19 70 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + + +do_get_lon() { + lon="$(curl -s4 ifconfig.co/json | awk '/lon/ {print $2}' | tr -d ',')" + new_lon=$(whiptail --inputbox "Please set the longitude where recordings will take place." \ + 19 70 -- "$lon" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_get_lat() { + lat="$(curl -s4 ifconfig.co/json | awk '/lat/ {print $2}' | tr -d ',')" + new_lat=$(whiptail --inputbox "Please set the latitude where recordings will take place." \ + 19 70 -- "$lat" 3>&1 1>&2 2>&3) ${birdnetpi_dir}/scripts/write_config.sh + if [ $? -eq 0 ];then + return 0 + ASK_TO_REBOOT=2 + else + return 1 + fi +} + +do_update_os() { + apt update && apt -y full-upgrade && \ + ASK_TO_REBOOT=1 +} + +do_update_birdnet() { + sudo -E -upi ${birdnetpi_dir}/scripts/update_birdnet.sh +} + +do_install_birdnet() { + sudo -E -upi ${birdnetpi_dir}/Birders_Guide_Installer.sh && \ + ASK_TO_REBOOT=1 +} + +insist_on_reboot() { + if [ $ASK_TO_REBOOT -eq 2 ]; then + whiptail --yesno "You really should reboot. Do that now?" 20 60 2 + if [ $? -eq 0 ]; then # yes + sync + reboot + fi + fi +} + +do_finish() { + if [ $ASK_TO_REBOOT -eq 1 ]; then + whiptail --yesno "Would you like to reboot now?" 20 60 2 + if [ $? -eq 0 ]; then # yes + sync + reboot + fi + elif [ $ASK_TO_REBOOT -eq 2 ]; then + whiptail --yesno "You really should reboot. Do that now?" 20 60 2 + if [ $? -eq 0 ]; then # yes + sync + reboot + fi + fi + exit 0 +} + +# Everything else needs to be run as root +if [ $(id -u) -ne 0 ]; then + printf "Script must be run as root. Try 'sudo birdnet-pi-config'\n" + exit 1 +fi + +do_advanced_reconfig_menu() { + MENU=9 + while [ $MENU -eq 9 ];do + if is_pi ; then + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --menu "BirdNET-Pi Configuration Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ + "Sensitivity" "Set the sigmoid sensitivity" \ + "Confidence" "Set the minimum confidence score required for a detection" \ + "Overlap" "Set the analysis overlap in seconds" \ + "BirdNET-Pi URLs" "Set the URLs your installation should use" \ + 3>&1 1>&2 2>&3) + else + exit + fi + RET=$? + if [ $RET -eq 1 ]; then + return 0 + MENU=0 + elif [ $RET -eq 0 ]; then + case "$FUN" in + Sens*) do_get_sensitivity;; + Confi*) do_get_confidence;; + Overlap*) do_get_overlap;; + Bird*) do_reget_birdnetpi_urls;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi + done +} + +do_interface_menu() { + MENU=6 + while [ $MENU -eq 6 ];do + if is_pi ; then + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --menu "Interfacing Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ + "SSH" "Enable/disable remote command line access using SSH" \ + "VNC" "Enable/disable graphical remote access using RealVNC" \ + 3>&1 1>&2 2>&3) + else + exit + fi + RET=$? + if [ $RET -eq 1 ]; then + return 0 + MENU=0 + elif [ $RET -eq 0 ]; then + case "$FUN" in + SSH*) do_ssh ;; + VNC*) do_vnc ;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi + done +} + +do_advanced_config_menu() { + MENU=5 + while [ $MENU -eq 5 ];do + if is_pi ; then + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --menu "BirdNET-Pi Configuration Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ + "Sensitivity" "Set the sigmoid sensitivity" \ + "Confidence" "Set the minimum confidence score required for a detection" \ + "Overlap" "Set the analysis overlap in seconds" \ + "BirdNET-Pi URLs" "Set the URLs your installation should use" \ + 3>&1 1>&2 2>&3) + else + exit + fi + RET=$? + if [ $RET -eq 1 ]; then + return 0 + MENU=0 + elif [ $RET -eq 0 ]; then + case "$FUN" in + Sens*) do_get_sensitivity;; + Confi*) do_get_confidence;; + Overlap*) do_get_overlap;; + Bird*) do_get_birdnetpi_url; do_get_birdnetlog_url; do_get_extractionlog_url;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi + done +} + +do_system_menu() { + MENU=4 + while [ $MENU -eq 4 ];do + if is_pi ; then + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --menu "System Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ + "Password" "Change password for the '$USER' user" \ + "Audio" "Select audio device you'd like BirdNET-Pi to use" \ + "Wireless LAN" "Enter SSID and passphrase" \ + "Update the OS" "Update the underlying operating system" \ + "Interface Options" "Enable/Disable SSH and VNC" \ + "Configure zRAM" "Enable/Disable zRAM" \ + "Timezone" "Configure time zone" \ + "Keyboard" "Set keyboard layout to match your keyboard" \ + "WLAN Country" "Set legal wireless channels for your country" \ + 3>&1 1>&2 2>&3) + else + exit + fi + RET=$? + if [ $RET -eq 1 ]; then + return 0 + MENU=0 + elif [ $RET -eq 0 ]; then + case "$FUN" in + Password*) do_change_pass ;; + Audio*) do_audio ;; + Wireless*) do_wifi_ssid_passphrase ;; + Update*) do_update_os ;; + Interface*) do_interface_menu ;; + Configure*) do_zram_menu ;; + Time*) do_change_timezone; insist_on_reboot ;; + Key*) do_configure_keyboard ;; + WLAN*) do_wifi_country ;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi + done +} + + +do_reconfig_birdnet_menu() { + MENU=3 + while [ $MENU -eq 3 ];do + if is_pi ; then + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --menu "BirdNET-Pi Re-configuration Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ + "Latitude " "Set the latitude your system should use" \ + "Longitude" "Set the longitude your system should use" \ + "Caddy Password" "Set the web interface password" \ + "Database Password" "Set the password BirdNET-Pi will use to access the DB" \ + "BirdWeather ID" "Input your BirdWeather ID if you have one" \ + "Advanced Settings" "Sensitivity, Overlap, Confidence, URLs" \ + 3>&1 1>&2 2>&3) + else + exit + fi + RET=$? + if [ $RET -eq 1 ]; then + return 0 + MENU=0 + elif [ $RET -eq 0 ]; then + case "$FUN" in + Lat*) do_reget_lat;; + Lon*) do_reget_lon;; + Cad*) do_reget_caddy_pwd;; + Data*) do_reget_db_pwd;; + Bird*) do_reget_birdweather_id;; + Advanced*) do_advanced_reconfig_menu;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi + done +} + +do_config_birdnet_menu() { + MENU=2 + while [ $MENU -eq 2 ];do + if is_pi ; then + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --menu "BirdNET-Pi Configuration Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ + "Latitude " "Set the latitude your system should use" \ + "Longitude" "Set the longitude your system should use" \ + "Caddy Password" "Set the web interface password" \ + "IceCast2 Password" "Set the IceCast2 password" \ + "Database Password" "Set the password BirdNET-Pi will use to access the DB" \ + "BirdWeather ID" "Input your BirdWeather ID if you have one" \ + "Set Custom URLS" "Designate custom URLs for the web services if you've set that up" \ + 3>&1 1>&2 2>&3) + else + exit + fi + RET=$? + if [ $RET -eq 1 ]; then + return 0 + MENU=0 + elif [ $RET -eq 0 ]; then + case "$FUN" in + Lat*) do_get_lat;; + Lon*) do_get_lon;; + Cad*) do_get_caddy_pwd;; + Ice*) do_get_ice_pwd;; + Data*) do_get_db_pwd;; + Bird*) do_get_birdweather_id;; + Set*) do_get_birdnetpi_url; do_get_birdnetlog_url; do_get_extractionlog_url;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi + done +} + +do_internationalisation_menu() { + MENU=1 + while [ $MENU -eq 1 ];do + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --menu "Localisation Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Back --ok-button Select \ + "System Locale" "Configure the system language and regional settings" \ + "labels.txt" "Set the language to use for species detection" \ + "Time Zone" "Set the Time Zone" \ + 3>&1 1>&2 2>&3) + RET=$? + if [ $RET -eq 1 ]; then + return 0 + MENU=0 + elif [ $RET -eq 0 ]; then + case "$FUN" in + System*) do_change_locale;; + label*) get_labels_lang;; + Time*) do_change_timezone;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi + done +} + + + +# +# Interactive use loop +# +[ -e $CONFIG ] || touch $CONFIG +calc_wt_size +while [ "$USER" = "root" ] || [ -z "$USER" ]; do + if ! USER=$(whiptail --inputbox "birdnet-pi-config could not determine the default user.\\n\\nWhat user should these settings apply to?" 20 60 pi 3>&1 1>&2 2>&3); then + return 0 + fi +done +while true; do + FUN=$(whiptail --title "BirdNET-Pi Software Configuration Tool (birdnet-pi-config)" --backtitle "$(cat /proc/device-tree/model)" --menu "Setup Options" $WT_HEIGHT $WT_WIDTH $WT_MENU_HEIGHT --cancel-button Finish --ok-button Select \ + "Step 1" "Configure language and timezone" \ + "Step 2" "Configure BirdNET-Pi before installation" \ + "Step 3" "Install BirdNET-Pi" \ + "Step 4" "Reconfigure BirdNET-Pi AFTER installation" \ + "Step 5" "Update BirdNET-Pi (run this if you changed URLs)" \ + "System Options" "Configure system settings" \ + 3>&1 1>&2 2>&3) + RET=$? + if [ $RET -eq 1 ]; then + do_finish + elif [ $RET -eq 0 ]; then + case "$FUN" in + *1) do_internationalisation_menu ;; + *2) do_config_birdnet_menu ;; + *3) do_install_birdnet;; + *4) do_reconfig_birdnet_menu ;; + *5) do_update_birdnet;; + Sys*) do_system_menu ;; + *) whiptail --msgbox "Programmer error: unrecognized option" 20 60 1 ;; + esac || whiptail --msgbox "There was an error running option $FUN" 20 60 1 + fi +done diff --git a/scripts/config.php b/scripts/config.php index 1d782ec..fb5c79d 100644 --- a/scripts/config.php +++ b/scripts/config.php @@ -472,9 +472,10 @@ function runProcess() {
BirdNET_6K_GLOBAL_MODEL (2020)

This is the BirdNET-Lite model, with bird sound recognition for more than 6,000 species worldwide. This is the default option and will generally work very for people in most of the world.
+
BirdNET_GLOBAL_3K_V2.2_Model_FP16 (2022)

This is the BirdNET-Analyzer model, a newer work-in-progress project with aims to improve on the BirdNET-Lite model. Currently it only supports about 3,500 species worldwide, meaning for some regions (North America, Europe, Australia) it will usually outperform the BirdNET-Lite model, but for other regions it will be worse.

-
(in-depth technical write-up on the models here)
+
[ In-depth technical write-up on the models here ]

@@ -482,7 +483,7 @@ function runProcess() {

Location

(Optional)
- +

@@ -650,6 +651,7 @@ https://discordapp.com/api/webhooks/{WebhookID}/{WebhookToken} ?> > >
+