From da52b55f27daa9df5e429a6789ab3448887420ef Mon Sep 17 00:00:00 2001 From: Alexandre <44178713+alexbelgium@users.noreply.github.com> Date: Wed, 9 Oct 2024 10:09:20 +0200 Subject: [PATCH] Update --- battybirdnet-pi/config.json | 2 +- .../rootfs/custom-services.d/30-monitoring.sh | 129 +++++++++-------- .../etc/cont-finish.d/savestreamdata.sh | 27 +++- .../rootfs/etc/cont-init.d/01-structure.sh | 101 +++++++------- .../etc/cont-init.d/02-restorestreamdata.sh | 46 +++--- .../rootfs/etc/cont-init.d/31-checks.sh | 52 ++++--- .../rootfs/etc/cont-init.d/33-mqtt.sh | 70 ---------- .../rootfs/etc/cont-init.d/71-newfeatures.sh | 63 --------- .../etc/cont-init.d/81-modifications.sh | 92 +++++++----- .../etc/cont-init.d/91-nginx_ingress.sh | 55 +++++--- .../rootfs/etc/cont-init.d/92-ssl.sh | 33 ++++- .../rootfs/etc/cont-init.d/99-run.sh | 105 +++++++------- battybirdnet-pi/rootfs/helpers/systemctl3.py | 6 +- battybirdnet-pi/rootfs/helpers/timedatectl | 131 +++++++++++------- 14 files changed, 452 insertions(+), 460 deletions(-) delete mode 100755 battybirdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh delete mode 100755 battybirdnet-pi/rootfs/etc/cont-init.d/71-newfeatures.sh diff --git a/battybirdnet-pi/config.json b/battybirdnet-pi/config.json index 17fdd9800..9fe5dc9f9 100644 --- a/battybirdnet-pi/config.json +++ b/battybirdnet-pi/config.json @@ -119,6 +119,6 @@ "udev": true, "url": "https://github.com/alexbelgium/hassio-addons/tree/master/battybirdnet-pi", "usb": true, - "version": "0.6", + "version": "0.7", "video": true } diff --git a/battybirdnet-pi/rootfs/custom-services.d/30-monitoring.sh b/battybirdnet-pi/rootfs/custom-services.d/30-monitoring.sh index 3d90d004a..19f72b544 100755 --- a/battybirdnet-pi/rootfs/custom-services.d/30-monitoring.sh +++ b/battybirdnet-pi/rootfs/custom-services.d/30-monitoring.sh @@ -1,93 +1,100 @@ -#!/usr/bin/with-contenv bashio +#!/usr/bin/env bash # shellcheck shell=bash +# Adapted from https://github.com/mcguirepr89/BirdNET-Pi/issues/393#issuecomment-1166445710 -sleep infinity +# Define logging functions +log_green() { echo -e "\033[32m$1\033[0m" } -echo "Starting service: throttlerecording" -touch "$HOME"/BirdSongs/StreamData/analyzing_now.txt +log_red() { echo -e "\033[31m$1\033[0m" } -# variables for readability -srv="birdnet_recording" -analyzing_now="." -counter=10 -set +u -# shellcheck disable=SC1091 +log_yellow() { echo -e "\033[33m$1\033[0m" } + +log_info() { echo -e "\033[34m$1\033[0m" } + +echo "$(log_green "Starting service: throttlerecording")" +touch "$HOME/BirdSongs/StreamData/analyzing_now.txt" + +# Read configuration source /config/birdnet.conf 2>/dev/null -# Ensure folder exists +# Set constants +srv="birdnet_recording" +srv2="birdnet_analysis" ingest_dir="$RECS_DIR/StreamData" +counter=10 -# Check permissions -mkdir -p "$ingest_dir" -chown -R pi:pi "$ingest_dir" -chmod -R 755 "$ingest_dir" -ingest_dir="$(readlink -f "$ingest_dir")" || true +# Ensure directories and permissions mkdir -p "$ingest_dir" chown -R pi:pi "$ingest_dir" chmod -R 755 "$ingest_dir" -function apprisealert() { - # Set failed check so it only runs once - touch "$HOME"/BirdNET-Pi/failed_servicescheck - NOTIFICATION="" - STOPPEDSERVICE="
Stopped services: " - services=(birdnet_analysis - chart_viewer - spectrogram_viewer - icecast2 - birdnet_recording - birdnet_log - birdnet_stats) - for i in "${services[@]}"; do - if [[ "$(sudo systemctl is-active "${i}".service)" == "inactive" ]]; then - STOPPEDSERVICE+="${i}; " +# Function to send notifications using Apprise +apprisealert() { + local notification="" + local stopped_service="
Stopped services: " + + # Check for stopped services + services=(birdnet_analysis chart_viewer spectrogram_viewer icecast2 birdnet_recording birdnet_log birdnet_stats) + for service in "${services[@]}"; do + if [[ "$(systemctl is-active "$service")" == "inactive" ]]; then + stopped_service+="$service; " fi done - NOTIFICATION+="$STOPPEDSERVICE" - NOTIFICATION+="
Additional informations: " - NOTIFICATION+="
Since: ${LASTCHECK:-unknown}" - NOTIFICATION+="
System: ${SITE_NAME:-$(hostname)}" - NOTIFICATION+="
Available disk space: $(df -h "$(readlink -f "$HOME/BirdSongs")" | awk 'NR==2 {print $4}')" - if [ -n "$BIRDNETPI_URL" ]; then - NOTIFICATION+="
Access your BirdNET-Pi" - fi + + # Build notification message + notification+="$stopped_service" + notification+="
Additional information: " + notification+="
Since: ${LASTCHECK:-unknown}" + notification+="
System: ${SITE_NAME:-$(hostname)}" + notification+="
Available disk space: $(df -h "$HOME/BirdSongs" | awk 'NR==2 {print $4}')" + [[ -n "$BIRDNETPI_URL" ]] && notification+="
Access your BirdNET-Pi" + + # Send notification TITLE="BirdNET-Analyzer stopped" - "$HOME"/BirdNET-Pi/birdnet/bin/apprise -vv -t "$TITLE" -b "${NOTIFICATION}" --input-format=html --config="$HOME/BirdNET-Pi/apprise.txt" + "$HOME/BirdNET-Pi/birdnet/bin/apprise" -vv -t "$TITLE" -b "$notification" --input-format=html --config="$HOME/BirdNET-Pi/apprise.txt" } +# Main loop while true; do sleep 61 # Restart analysis if clogged - ############################ - if ((counter <= 0)); then - latest="$(cat "$ingest_dir"/analyzing_now.txt)" - if [[ "$latest" == "$analyzing_now" ]]; then - echo "$(date) WARNING no change in analyzing_now for 10 iterations, restarting services" - /."$HOME"/BirdNET-Pi/scripts/restart_services.sh + current_file="$(cat "$ingest_dir/analyzing_now.txt")" + if [[ "$current_file" == "$analyzing_now" ]]; then + log_yellow "$(date) WARNING: no change in analyzing_now for 10 iterations, restarting services" + "$HOME/BirdNET-Pi/scripts/restart_services.sh" fi counter=10 - analyzing_now=$(cat "$ingest_dir"/analyzing_now.txt) + analyzing_now="$current_file" fi - # Pause recorder to catch-up - ############################ + # Check recorder state and queue length + wav_count=$(find "$ingest_dir" -maxdepth 1 -name '*.wav' | wc -l) + service_state=$(systemctl is-active "$srv") + analysis_state=$(systemctl is-active "$srv2") - wavs="$(find "$ingest_dir" -maxdepth 1 -name '*.wav' | wc -l)" - state="$(systemctl is-active "$srv")" + log_green "$(date) INFO: $wav_count wav files waiting in $ingest_dir, $srv state is $service_state, $srv2 state is $analysis_state" - bashio::log.green "$(date) INFO ${wavs} wav files waiting in $ingest_dir, $srv state is $state" - - if ((wavs > 100)); then - bashio::log.red "$(date) WARNING too many files in queue, pausing $srv" + # Pause recorder if queue is too large + if ((wav_count > 50)); then + log_red "$(date) WARNING: Too many files in queue, pausing $srv and restarting $srv2" sudo systemctl stop "$srv" - sudo systemctl restart birdnet_analysis - if [ -s "$HOME/BirdNET-Pi/apprise.txt" ]; then apprisealert; fi - elif [[ "$state" != "active" ]]; then - bashio::log.yellow "$(date) INFO started $srv service" - sudo systemctl start $srv - sudo systemctl restart birdnet_analysis + sudo systemctl restart "$srv2" + [[ -s "$HOME/BirdNET-Pi/apprise.txt" ]] && apprisealert + elif ((wav_count > 30)); then + log_red "$(date) WARNING: Too many files in queue, restarting $srv2" + sudo systemctl restart "$srv2" + [[ -s "$HOME/BirdNET-Pi/apprise.txt" ]] && apprisealert + else + if [[ "$service_state" != "active" ]]; then + log_yellow "$(date) INFO: Restarting $srv service" + sudo systemctl restart "$srv" + fi + if [[ "$analysis_state" != "active" ]]; then + log_yellow "$(date) INFO: Restarting $srv2 service" + sudo systemctl restart "$srv2" + fi fi ((counter--)) diff --git a/battybirdnet-pi/rootfs/etc/cont-finish.d/savestreamdata.sh b/battybirdnet-pi/rootfs/etc/cont-finish.d/savestreamdata.sh index 215b7f9fd..de9eaae80 100755 --- a/battybirdnet-pi/rootfs/etc/cont-finish.d/savestreamdata.sh +++ b/battybirdnet-pi/rootfs/etc/cont-finish.d/savestreamdata.sh @@ -2,17 +2,34 @@ # shellcheck shell=bash if [ -d "$HOME"/BirdSongs/StreamData ]; then - bashio::log.fatal "Container stopping, saving temporary files" + bashio::log.fatal "Container stopping, saving temporary files." # Stop the services in parallel - systemctl stop birdnet_analysis & - systemctl stop birdnet_recording + if systemctl is-active --quiet birdnet_analysis; then + bashio::log.info "Stopping birdnet_analysis service." + systemctl stop birdnet_analysis & + fi + + if systemctl is-active --quiet birdnet_recording; then + bashio::log.info "Stopping birdnet_recording service." + systemctl stop birdnet_recording & + fi + + # Wait for both services to stop + wait # Check if there are files in StreamData and move them to /data/StreamData mkdir -p /data/StreamData if [ "$(ls -A "$HOME"/BirdSongs/StreamData)" ]; then - mv -v "$HOME"/BirdSongs/StreamData/* /data/StreamData/ + if mv -v "$HOME"/BirdSongs/StreamData/* /data/StreamData/; then + bashio::log.info "Files successfully moved to /data/StreamData." + else + bashio::log.error "Failed to move files to /data/StreamData." + exit 1 + fi fi - bashio::log.fatal "... files safe, allowing container to stop" + bashio::log.info "... files safe, allowing container to stop." +else + bashio::log.info "No StreamData directory to process." fi diff --git a/battybirdnet-pi/rootfs/etc/cont-init.d/01-structure.sh b/battybirdnet-pi/rootfs/etc/cont-init.d/01-structure.sh index 1496113b0..46e86e191 100755 --- a/battybirdnet-pi/rootfs/etc/cont-init.d/01-structure.sh +++ b/battybirdnet-pi/rootfs/etc/cont-init.d/01-structure.sh @@ -6,20 +6,19 @@ set -e # SET /CONFIG # ############### -echo " " -bashio::log.info "Ensuring the file structure is correct :" +bashio::log.info "Ensuring the file structure is correct:" -# Define structure +# Create default configuration files if not present echo "... creating default files" -touch /config/include_species_list.txt # Should be null -touch /home/pi/BirdNET-Pi/scripts/thisrun.txt -for files in apprise.txt exclude_species_list.txt IdentifiedSoFar.txt disk_check_exclude.txt confirmed_species_list.txt blacklisted_images.txt whitelist_species_list.txt; do - if [ ! -f /config/"$files" ]; then - echo "" > /config/"$files" +DEFAULT_FILES=("apprise.txt" "exclude_species_list.txt" "IdentifiedSoFar.txt" "disk_check_exclude.txt" "confirmed_species_list.txt" "blacklisted_images.txt" "whitelist_species_list.txt") +for file in "${DEFAULT_FILES[@]}"; do + if [ ! -f "/config/$file" ]; then + echo "" > "/config/$file" fi done +touch /config/include_species_list.txt # Ensure this is always created -# Get BirdSongs folder locations +# Set BirdSongs folder location from configuration if specified BIRDSONGS_FOLDER="/config/BirdSongs" if bashio::config.has_value "BIRDSONGS_FOLDER"; then BIRDSONGS_FOLDER_OPTION="$(bashio::config "BIRDSONGS_FOLDER")" @@ -29,65 +28,61 @@ if bashio::config.has_value "BIRDSONGS_FOLDER"; then if [ -d "$BIRDSONGS_FOLDER_OPTION" ] && [ "$(stat -c '%u:%g' "$BIRDSONGS_FOLDER_OPTION")" == "1000:1000" ]; then BIRDSONGS_FOLDER="$BIRDSONGS_FOLDER_OPTION" else - bashio::log.yellow "BIRDSONGS_FOLDER reverted to /config/BirdSongs" + bashio::log.warning "BIRDSONGS_FOLDER reverted to /config/BirdSongs" fi fi -# Create BirdSongs folder -echo "... creating default folders ; it is highly recommended to store those on a ssd" -mkdir -p "$BIRDSONGS_FOLDER"/By_Date -mkdir -p "$BIRDSONGS_FOLDER"/Charts +# Create default folders +echo "... creating default folders; it is highly recommended to store these on an SSD" +mkdir -p "$BIRDSONGS_FOLDER/By_Date" "$BIRDSONGS_FOLDER/Charts" -# If tmpfs is installed, use it +# Use tmpfs if installed if df -T /tmp | grep -q "tmpfs"; then echo "... tmpfs detected, using it for StreamData and Processed to reduce disk wear" - mkdir -p /tmp/StreamData - mkdir -p /tmp/Processed - if [ -d "$HOME"/BirdSongs/StreamData ]; then - rm -r "$HOME"/BirdSongs/StreamData - fi - if [ -d "$HOME"/BirdSongs/Processed ]; then - rm -r "$HOME"/BirdSongs/Processed - fi - sudo -u pi ln -fs /tmp/StreamData "$HOME"/BirdSongs/StreamData - sudo -u pi ln -fs /tmp/Processed "$HOME"/BirdSongs/Processed + mkdir -p /tmp/StreamData /tmp/Processed + [ -d "$HOME/BirdSongs/StreamData" ] && rm -r "$HOME/BirdSongs/StreamData" + [ -d "$HOME/BirdSongs/Processed" ] && rm -r "$HOME/BirdSongs/Processed" + sudo -u pi ln -fs /tmp/StreamData "$HOME/BirdSongs/StreamData" + sudo -u pi ln -fs /tmp/Processed "$HOME/BirdSongs/Processed" fi -# Permissions for created files and folders -echo "... set permissions to user pi" +# Set permissions for created files and folders +echo "... setting permissions for user pi" chown -R pi:pi /config /etc/birdnet "$BIRDSONGS_FOLDER" /tmp -chmod -R 755 /config /config /etc/birdnet "$BIRDSONGS_FOLDER" /tmp +chmod -R 755 /config /etc/birdnet "$BIRDSONGS_FOLDER" /tmp -# Save default birdnet.conf to perform sanity check -cp "$HOME"/BirdNET-Pi/birdnet.conf "$HOME"/BirdNET-Pi/birdnet.bak +# Backup default birdnet.conf for sanity check +cp "$HOME/BirdNET-Pi/birdnet.conf" "$HOME/BirdNET-Pi/birdnet.bak" -# Symlink files -echo "... creating symlink" -for files in "$HOME/BirdNET-Pi/birdnet.conf" "$HOME/BirdNET-Pi/scripts/whitelist_species_list.txt" "$HOME/BirdNET-Pi/blacklisted_images.txt" "$HOME/BirdNET-Pi/scripts/birds.db" "$HOME/BirdNET-Pi/BirdDB.txt" "$HOME/BirdNET-Pi/scripts/disk_check_exclude.txt" "$HOME/BirdNET-Pi/apprise.txt" "$HOME/BirdNET-Pi/exclude_species_list.txt" "$HOME/BirdNET-Pi/include_species_list.txt" "$HOME/BirdNET-Pi/IdentifiedSoFar.txt" "$HOME/BirdNET-Pi/scripts/confirmed_species_list.txt"; do - filename="${files##*/}" - if [ ! -f /config/"$filename" ]; then - if [ -f "$files" ]; then - echo "... copying $filename" && sudo -u pi mv "$files" /config/ - else - touch /config/"$filename" - fi - fi - if [ -e "$files" ]; then rm "$files"; fi - sudo -u pi ln -fs /config/"$filename" "$HOME/BirdNET-Pi/$filename" || bashio::log.fatal "Symlink creation failed for $filename" - sudo -u pi ln -fs /config/"$filename" "$HOME/BirdNET-Pi/scripts/$filename" || bashio::log.fatal "Symlink creation failed for $filename" - sudo -u pi ln -fs /config/"$filename" /etc/birdnet/"$filename" || bashio::log.fatal "Symlink creation failed for $filename" +# Symlink configuration files +echo "... creating symlinks for configuration files" +CONFIG_FILES=("$HOME/BirdNET-Pi/birdnet.conf" "$HOME/BirdNET-Pi/scripts/whitelist_species_list.txt" "$HOME/BirdNET-Pi/blacklisted_images.txt" "$HOME/BirdNET-Pi/scripts/birds.db" "$HOME/BirdNET-Pi/BirdDB.txt" "$HOME/BirdNET-Pi/scripts/disk_check_exclude.txt" "$HOME/BirdNET-Pi/apprise.txt" "$HOME/BirdNET-Pi/exclude_species_list.txt" "$HOME/BirdNET-Pi/include_species_list.txt" "$HOME/BirdNET-Pi/IdentifiedSoFar.txt" "$HOME/BirdNET-Pi/scripts/confirmed_species_list.txt") + +for file in "${CONFIG_FILES[@]}"; do + filename="${file##*/}" + [ ! -f "/config/$filename" ] && touch "/config/$filename" + [ -e "$file" ] && rm "$file" + sudo -u pi ln -fs "/config/$filename" "$file" + sudo -u pi ln -fs "/config/$filename" "$HOME/BirdNET-Pi/scripts/$filename" + sudo -u pi ln -fs "/config/$filename" "/etc/birdnet/$filename" done -# Symlink folders -for folders in By_Date Charts; do - echo "... creating symlink for $BIRDSONGS_FOLDER/$folders" - rm -r "$HOME/BirdSongs/Extracted/${folders:?}" - sudo -u pi ln -fs "$BIRDSONGS_FOLDER"/"$folders" "$HOME/BirdSongs/Extracted/$folders" +# Symlink BirdSongs folders +for folder in By_Date Charts; do + echo "... creating symlink for $BIRDSONGS_FOLDER/$folder" + [ -d "$HOME/BirdSongs/Extracted/${folder:?}" ] && rm -r "$HOME/BirdSongs/Extracted/$folder" + sudo -u pi ln -fs "$BIRDSONGS_FOLDER/$folder" "$HOME/BirdSongs/Extracted/$folder" done -# Permissions for created files and folders -echo "... check permissions" +# Set permissions for newly created files and folders +echo "... checking and setting permissions" chmod -R 755 /config/* chmod 777 /config -echo " " +# Create Matplotlib configuration directory +echo "... setting up Matplotlabdir" +MPLCONFIGDIR="${MPLCONFIGDIR:-$HOME/.config/matplotlib}" +mkdir -p "$MPLCONFIGDIR" +chown pi:pi "$MPLCONFIGDIR" +chmod 777 "$MPLCONFIGDIR" + diff --git a/battybirdnet-pi/rootfs/etc/cont-init.d/02-restorestreamdata.sh b/battybirdnet-pi/rootfs/etc/cont-init.d/02-restorestreamdata.sh index 61fca2bc6..8ab4ae674 100755 --- a/battybirdnet-pi/rootfs/etc/cont-init.d/02-restorestreamdata.sh +++ b/battybirdnet-pi/rootfs/etc/cont-init.d/02-restorestreamdata.sh @@ -1,24 +1,36 @@ -#!/usr/bin/with-contenv bashio +#!/command/with-contenv bashio # shellcheck shell=bash +set -e -# Check if there are files in "$HOME"/BirdSongs/StreamData and move them to /data/StreamData -if [ -d /data/StreamData ] && [ "$(ls -A /data/StreamData/)" ]; then +if [ -d /data/StreamData ]; then + bashio::log.fatal "Container was stopped while files were still being analyzed." - bashio::log.warning "Container was stopped while files were still being analysed, restoring them" + # Check if there are .wav files in /data/StreamData + if find /data/StreamData -type f -name "*.wav" | grep -q .; then + bashio::log.warning "Restoring .wav files from /data/StreamData to $HOME/BirdSongs/StreamData." - # Copy files - if [ "$(ls -A /data/StreamData)" ]; then - mv -v /data/StreamData/* "$HOME"/BirdSongs/StreamData/ + # Create the destination directory if it does not exist + mkdir -p "$HOME"/BirdSongs/StreamData + + # Count the number of .wav files to be moved + file_count=$(find /data/StreamData -type f -name "*.wav" | wc -l) + echo "... found $file_count .wav files to restore." + + # Move the .wav files using `mv` to avoid double log entries + mv -v /data/StreamData/*.wav "$HOME"/BirdSongs/StreamData/ + + # Update permissions only if files were moved successfully + if [ "$file_count" -gt 0 ]; then + chown -R pi:pi "$HOME"/BirdSongs/StreamData + fi + + echo "... $file_count files restored successfully." + else + echo "... no .wav files found to restore." fi - echo "... done" - echo "" - - # Setting permissions - chown -R pi:pi "$HOME"/BirdSongs - chmod -R 755 "$HOME"/BirdSongs - - # Cleaning folder - rm -r /data/StreamData + # Clean up the source folder if it is empty + if [ -z "$(ls -A /data/StreamData)" ]; then + rm -r /data/StreamData + fi fi - diff --git a/battybirdnet-pi/rootfs/etc/cont-init.d/31-checks.sh b/battybirdnet-pi/rootfs/etc/cont-init.d/31-checks.sh index 47ffa5b77..48b727e3e 100755 --- a/battybirdnet-pi/rootfs/etc/cont-init.d/31-checks.sh +++ b/battybirdnet-pi/rootfs/etc/cont-init.d/31-checks.sh @@ -6,49 +6,55 @@ set -e # CHECK BIRDNET.CONF # ###################### -echo " " -bashio::log.info "Checking your birndet.conf file integrity" +bashio::log.info "Checking your birdnet.conf file integrity" # Set variables configcurrent="$HOME"/BirdNET-Pi/birdnet.conf configtemplate="$HOME"/BirdNET-Pi/birdnet.bak +# Ensure both files exist before proceeding +if [ ! -f "$configcurrent" ] || [ ! -f "$configtemplate" ]; then + bashio::log.fatal "Missing required birdnet.conf or birdnet.bak file. Please ensure both are present." + exit 1 +fi + # Extract variable names from config template and read each one grep -o '^[^#=]*=' "$configtemplate" | sed 's/=//' | while read -r var; do # Check if the variable is in configcurrent, if not, append it if ! grep -q "^$var=" "$configcurrent"; then - # At which line was the variable in the initial file - bashio::log.yellow "...$var was missing from your birdnet.conf file, it was re-added" + bashio::log.warning "...$var was missing from your birdnet.conf file, it was re-added" grep "^$var=" "$configtemplate" >> "$configcurrent" fi # Check for duplicates if [ "$(grep -c "^$var=" "$configcurrent")" -gt 1 ]; then - bashio::log.error "Duplicate variable $var found in $configcurrent, all were commented out expect for the first one" - awk -v var="$var" '{ if ($0 ~ "^[[:blank:]]*"var && c++ > 0) print "#" $0; else print $0; }' "$configcurrent" > temp && mv temp "$configcurrent" + bashio::log.error "Duplicate variable $var found in $configcurrent, all were commented out except for the first one" + sed -i "0,/^$var=/!s/^$var=/#$var=/" "$configcurrent" fi done -################ -# CHECK AMIXER # -################ - -# If default capture is set at 0%, increase it to 50% -# current_volume="$(amixer sget Capture | grep -oP '\[\d+%]' | tr -d '[]%' | head -1)" 2>/dev/null || true -# current_volume="${current_volume:-100}" - -# Set the default microphone volume to 50% if it's currently at 0% -# if [[ "$current_volume" -eq 0 ]]; then -# amixer sset Capture 70% -# bashio::log.warning "Microphone was off, volume set to 70%." -# fi - ############## # CHECK PORT # ############## if [[ "$(bashio::addon.port "80")" == 3000 ]]; then - bashio::log.fatal "This is crazy but your port is set to 3000 and streamlit doesn't accept this port! You need to change it from the addon options and restart. Thanks" - sleep infinity + bashio::log.fatal "This is crazy but your port is set to 3000 and streamlit doesn't accept this port! You need to change it from the addon options and restart. Thanks" + sleep infinity fi -echo " " +################## +# PERFORM UPDATE # +################## + +bashio::log.info "Performing potential updates" + +# Adapt update_birdnet_snippets +sed -i "s|systemctl list-unit-files|false \&\& echo|g" "$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh +sed -i "/systemctl /d" "$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh +sed -i "/find /d" "$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh +sed -i "/set -x/d" "$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh +sed -i "/restart_services/d" "$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh +sed -i "s|/etc/birdnet/birdnet.conf|/config/birdnet.conf|g" "$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh + +# Execute update_birdnet_snippets +"$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh + diff --git a/battybirdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh b/battybirdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh deleted file mode 100755 index ed1585c99..000000000 --- a/battybirdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/with-contenv bashio -# shellcheck shell=bash -set -e - -# Function to perform common setup steps -common_steps () { - # Attempt to connect to the MQTT broker - TOPIC="birdnet" - if mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" -t "$TOPIC" -m "test" -u "$MQTT_USER" -P "$MQTT_PASS" -q 1 -d --will-topic "$TOPIC" --will-payload "Disconnected" --will-qos 1 --will-retain > /dev/null 2>&1; then - # Adapt script with MQTT settings - sed -i "s|%%mqtt_server%%|$MQTT_HOST|g" /helpers/birdnet_to_mqtt.py - sed -i "s|%%mqtt_port%%|$MQTT_PORT|g" /helpers/birdnet_to_mqtt.py - sed -i "s|%%mqtt_user%%|$MQTT_USER|g" /helpers/birdnet_to_mqtt.py - sed -i "s|%%mqtt_pass%%|$MQTT_PASS|g" /helpers/birdnet_to_mqtt.py - - # Copy script to the appropriate directory - cp /helpers/birdnet_to_mqtt.py "$HOME"/BirdNET-Pi/scripts/utils/birdnet_to_mqtt.py - chown pi:pi "$HOME"/BirdNET-Pi/scripts/utils/birdnet_to_mqtt.py - chmod +x "$HOME"/BirdNET-Pi/scripts/utils/birdnet_to_mqtt.py - - # Add hooks to the main analysis script - sed -i "/load_global_model, run_analysis/a from utils.birdnet_to_mqtt import automatic_mqtt_publish" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i '/write_to_db(/a\ automatic_mqtt_publish(file, detection, os.path.basename(detection.file_name_extr))' "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - else - bashio::log.fatal "MQTT connection failed, it will not be configured. Error message :" - mosquitto_pub -h "$MQTT_HOST" -p "$MQTT_PORT" -t "$TOPIC" -m "test" -u "$MQTT_USER" -P "$MQTT_PASS" -q 1 -d --will-topic "$TOPIC" --will-payload "Disconnected" --will-qos 1 --will-retain - fi -} - -# Check if MQTT service is available and not disabled -if bashio::services.available 'mqtt' && ! bashio::config.true 'MQTT_DISABLED'; then - bashio::log.green "---" - bashio::log.blue "MQTT addon is active on your system! BirdNET-Pi is now automatically configured to send its output to MQTT" - bashio::log.blue "MQTT user : $(bashio::services "mqtt" "username")" - bashio::log.blue "MQTT password : $(bashio::services "mqtt" "password")" - bashio::log.blue "MQTT broker : tcp://$(bashio::services "mqtt" "host"):$(bashio::services "mqtt" "port")" - bashio::log.green "---" - bashio::log.blue "Data will be posted to the topic : 'birdnet'" - bashio::log.blue "Json data : {'Date', 'Time', 'ScientificName', 'CommonName', 'Confidence', 'SpeciesCode', 'ClipName', 'url'}" - bashio::log.blue "---" - - # Apply MQTT settings - MQTT_HOST="$(bashio::services "mqtt" "host")" - MQTT_PORT="$(bashio::services "mqtt" "port")" - MQTT_USER="$(bashio::services "mqtt" "username")" - MQTT_PASS="$(bashio::services "mqtt" "password")" - - # Perform common setup steps - common_steps - -# Check if manual MQTT configuration is provided -elif bashio::config.has_value "MQTT_HOST_manual" && bashio::config.has_value "MQTT_PORT_manual"; then - bashio::log.green "---" - bashio::log.blue "MQTT is manually configured in the addon options" - bashio::log.blue "BirdNET-Pi is now automatically configured to send its output to MQTT" - bashio::log.green "---" - bashio::log.blue "Data will be posted to the topic : 'birdnet'" - bashio::log.blue "Json data : {'Date', 'Time', 'ScientificName', 'CommonName', 'Confidence', 'SpeciesCode', 'ClipName', 'url'}" - bashio::log.blue "---" - - # Apply manual MQTT settings - MQTT_HOST="$(bashio::config "MQTT_HOST_manual")" - MQTT_PORT="$(bashio::config "MQTT_PORT_manual")" - MQTT_USER="$(bashio::config "MQTT_USER_manual")" - MQTT_PASS="$(bashio::config "MQTT_PASSWORD_manual")" - - # Perform common setup steps - common_steps - -fi diff --git a/battybirdnet-pi/rootfs/etc/cont-init.d/71-newfeatures.sh b/battybirdnet-pi/rootfs/etc/cont-init.d/71-newfeatures.sh deleted file mode 100755 index b4fbae83a..000000000 --- a/battybirdnet-pi/rootfs/etc/cont-init.d/71-newfeatures.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/command/with-contenv bashio -# shellcheck shell=bash -set -e - -################ -# ADD FEATURES # -################ - -echo " " -bashio::log.info "Adding optional features" - -# Denoiser -#if bashio::config.true "DENOISER_ANALYSIS_ENABLED"; then -# sed -i "s|ar 48000|ar 48000 -af \"arnndn=m=sample.rnnn\"|g" "$HOME"/BirdNET-Pi/scripts/birdnet_recording.sh -# sed -i "s|ar 48000|ar 48000 -af afftdn=nr=30:nt=w:om=o|g" "$HOME"/BirdNET-Pi/scripts/birdnet_recording.sh -#fi - -# Enable the Processed folder -############################# - -if bashio::config.true "PROCESSED_FOLDER_ENABLED" && ! grep -q "processed_size" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py; then - echo "... Enabling the Processed folder : the last 15 wav files will be stored there" - # Adapt config.php - sed -i "/GET\[\"info_site\"\]/a\ \$processed_size = \$_GET\[\"processed_size\"\];" "$HOME"/BirdNET-Pi/scripts/config.php - sed -i "/\$contents = file_get_contents/a\ \$contents = preg_replace\(\"/PROCESSED_SIZE=\.\*/\", \"PROCESSED_SIZE=\$processed_size\", \$contents\);" "$HOME"/BirdNET-Pi/scripts/config.php - sed -i "/\"success\"/i
" "$HOME"/BirdNET-Pi/scripts/config.php - sed -i "/\"success\"/i

Processed folder management

" "$HOME"/BirdNET-Pi/scripts/config.php - sed -i "/\"success\"/i " "$HOME"/BirdNET-Pi/scripts/config.php - sed -i "/\"success\"/i \"/>" "$HOME"/BirdNET-Pi/scripts/config.php - sed -i "/\"success\"/i
" "$HOME"/BirdNET-Pi/scripts/config.php - sed -i "/\"success\"/i Processed is the directory where the formerly 'Analyzed' files are moved after extractions, mostly for troubleshooting purposes.
" "$HOME"/BirdNET-Pi/scripts/config.php - sed -i "/\"success\"/i This value defines the maximum amount of files that are kept before replacement with new files.
" "$HOME"/BirdNET-Pi/scripts/config.php - sed -i "/\"success\"/i
" "$HOME"/BirdNET-Pi/scripts/config.php - sed -i "/\"success\"/i\
" "$HOME"/BirdNET-Pi/scripts/config.php - # Adapt birdnet_analysis.py - move_to_processed - sed -i "/log.info('handle_reporting_queue done')/a\ os.remove(files.pop(0))" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/log.info('handle_reporting_queue done')/a\ while len(files) > processed_size:" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/log.info('handle_reporting_queue done')/a\ files.sort(key=os.path.getmtime)" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/log.info('handle_reporting_queue done')/a\ files = glob.glob(os.path.join(processed_dir, '*'))" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/log.info('handle_reporting_queue done')/a\ os.rename(file_name, os.path.join(processed_dir, os.path.basename(file_name)))" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/log.info('handle_reporting_queue done')/a\ processed_dir = os.path.join(get_settings()['RECS_DIR'], 'Processed')" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/log.info('handle_reporting_queue done')/a\def move_to_processed(file_name, processed_size):" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/log.info('handle_reporting_queue done')/a\ " "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - # Adapt birdnet_analysis.py - get_processed_size - sed -i "/log.info('handle_reporting_queue done')/a\ return 0" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/log.info('handle_reporting_queue done')/a\ except (ValueError, TypeError):" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/log.info('handle_reporting_queue done')/a\ return processed_size if isinstance(processed_size, int) else 0" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/log.info('handle_reporting_queue done')/a\ processed_size = get_settings().getint('PROCESSED_SIZE')" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/log.info('handle_reporting_queue done')/a\ try:" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/log.info('handle_reporting_queue done')/a\def get_processed_size():" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/log.info('handle_reporting_queue done')/a\ " "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - # Modify calls - sed -i "/from subprocess import CalledProcessError/a\import glob" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/from subprocess import CalledProcessError/a\import time" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - # Modify main code - sed -i "/os.remove(file.file_name)/i\ processed_size = get_processed_size()" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/os.remove(file.file_name)/i\ if processed_size > 0:" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/os.remove(file.file_name)/i\ move_to_processed(file.file_name, processed_size)" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/os.remove(file.file_name)/i\ else:" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py - sed -i "/os.remove(file.file_name)/c\ os.remove(file.file_name)" "$HOME"/BirdNET-Pi/scripts/birdnet_analysis.py -fi || true - -echo " " diff --git a/battybirdnet-pi/rootfs/etc/cont-init.d/81-modifications.sh b/battybirdnet-pi/rootfs/etc/cont-init.d/81-modifications.sh index 0b8372cfc..5747bb856 100755 --- a/battybirdnet-pi/rootfs/etc/cont-init.d/81-modifications.sh +++ b/battybirdnet-pi/rootfs/etc/cont-init.d/81-modifications.sh @@ -6,61 +6,81 @@ set -e # MODIFY WEBUI # ################ -echo " " bashio::log.info "Adapting webui" -# Remove services tab +# Remove services tab from webui echo "... removing System Controls from webui as should be used from HA" -sed -i '/>System Controls/d' "$HOME"/BirdNET-Pi/homepage/views.php +sed -i '/>System Controls/d' "$HOME/BirdNET-Pi/homepage/views.php" -# Remove services tab +# Remove Ram drive option from webui echo "... removing Ram drive from webui as it is handled from HA" -sed -i '/Ram drive/{n;s/center"/center" style="display: none;"/;}' "$HOME"/BirdNET-Pi/scripts/service_controls.php -sed -i '/Ram drive/d' "$HOME"/BirdNET-Pi/scripts/service_controls.php +sed -i '/Ram drive/{n;s/center"/center" style="display: none;"/;}' "$HOME/BirdNET-Pi/scripts/service_controls.php" +sed -i '/Ram drive/d' "$HOME/BirdNET-Pi/scripts/service_controls.php" # Correct services to start as user pi -echo "... correct services to start as pi" -for file in $(find "$HOME"/BirdNET-Pi/templates/birdnet*.service -print0 | xargs -0 basename -a) livestream.service chart_viewer.service chart_viewer.service spectrogram_viewer.service; do - if [[ "$file" != "birdnet_log.service" ]]; then - sed -i "s|ExecStart=|ExecStart=/usr/bin/sudo -u pi |g" "$HOME/BirdNET-Pi/templates/$file" +echo "... updating services to start as user pi" +while IFS= read -r file; do + if [[ "$(basename "$file")" != "birdnet_log.service" ]]; then + sed -i "s|ExecStart=|ExecStart=/usr/bin/sudo -u pi |g" "$file" fi -done +done < <(find "$HOME/BirdNET-Pi/templates/" -name "birdnet*.service" -print) # Send services log to container logs -echo "... send services log to container logs" -for file in $(find "$HOME"/BirdNET-Pi/templates/birdnet*.service -print0 | xargs -0 basename -a) livestream.service chart_viewer.service chart_viewer.service spectrogram_viewer.service; do - sed -i "/Service/a StandardError=append:/proc/1/fd/1" "$HOME/BirdNET-Pi/templates/$file" - sed -i "/Service/a StandardOutput=append:/proc/1/fd/1" "$HOME/BirdNET-Pi/templates/$file" -done +echo "... redirecting services logs to container logs" +while IFS= read -r file; do + sed -i "/Service/a StandardError=append:/proc/1/fd/1" "$file" + sed -i "/Service/a StandardOutput=append:/proc/1/fd/1" "$file" +done < <(find "$HOME/BirdNET-Pi/templates/" -name "birdnet*.service" -print) # Avoid preselection in include and exclude lists -echo "... avoid preselecting options in include and exclude lists" -sed -i "s|option selected|option disabled|g" "$HOME"/BirdNET-Pi/scripts/include_list.php -sed -i "s|option selected|option disabled|g" "$HOME"/BirdNET-Pi/scripts/exclude_list.php +echo "... disabling preselecting options in include and exclude lists" +sed -i "s|option selected|option disabled|g" "$HOME/BirdNET-Pi/scripts/include_list.php" +sed -i "s|option selected|option disabled|g" "$HOME/BirdNET-Pi/scripts/exclude_list.php" # Correct log services to show /proc/1/fd/1 -echo "... show container logs in /logs" +echo "... redirecting birdnet_log service output to /logs" sed -i "/User=pi/d" "$HOME/BirdNET-Pi/templates/birdnet_log.service" sed -i "s|birdnet_log.sh|cat /proc/1/fd/1|g" "$HOME/BirdNET-Pi/templates/birdnet_log.service" -# Make sure config is correctly formatted. -echo "... caddyfile modifications" -#Correct instructions +# Caddyfile modifications +echo "... modifying Caddyfile configurations" caddy fmt --overwrite /etc/caddy/Caddyfile #Change port to leave 80 free for certificate requests sed -i "s|http://|http://:8081|g" /etc/caddy/Caddyfile -sed -i "s|http://|http://:8081|g" "$HOME"/BirdNET-Pi/scripts/update_caddyfile.sh -#Remove default file that blocks 80 -if [ -f /etc/caddy/Caddyfile.original ]; then rm /etc/caddy/Caddyfile.original; fi - -# Improve webui paths to facilitate ingress -echo "... correcting webui paths" -sed -i "s|/stats|/stats/|g" "$HOME"/BirdNET-Pi/homepage/views.php -sed -i "s|/log|/log/|g" "$HOME"/BirdNET-Pi/homepage/views.php - -# If port 80 is enabled, make sure it is still 80 -if [ -n "$(bashio::addon.port 80)" ] && [ "$(bashio::addon.port 80)" != 80 ]; then - bashio::log.fatal "The port 80 is enabled, but should still be 80 if you want the automatic ssl certificates generation to work" +sed -i "s|http://|http://:8081|g" "$HOME/BirdNET-Pi/scripts/update_caddyfile.sh" +if [ -f /etc/caddy/Caddyfile.original ]; then + rm /etc/caddy/Caddyfile.original fi -echo " " +# Correct webui paths +echo "... correcting webui paths" +sed -i "s|/stats|/stats/|g" "$HOME/BirdNET-Pi/homepage/views.php" +sed -i "s|/log|/log/|g" "$HOME/BirdNET-Pi/homepage/views.php" + +# Check if port 80 is correctly configured +if [ -n "$(bashio::addon.port 80)" ] && [ "$(bashio::addon.port 80)" != 80 ]; then + bashio::log.fatal "The port 80 is enabled, but should still be 80 if you want automatic SSL certificates generation to work." +fi + +# Correct systemctl path +echo "... updating systemctl path" +mv /helpers/systemctl3.py /bin/systemctl +chmod a+x /bin/systemctl + +# Correct timedatectl path +echo "updating timedatectl path" +mv /helpers/timedatectl /usr/bin/timedatectl +chown pi:pi /usr/bin/timedatectl +chmod a+x /usr/bin/timedatectl + +# Correct timezone showing in config.php +sed -i -e '/