diff --git a/battybirdnet-pi/rootfs/rootfs b/battybirdnet-pi/rootfs similarity index 100% rename from battybirdnet-pi/rootfs/rootfs rename to battybirdnet-pi/rootfs diff --git a/battybirdnet-pi/rootfs/custom-services.d/00-php_pfm.sh b/battybirdnet-pi/rootfs/custom-services.d/00-php_pfm.sh deleted file mode 100755 index fcdd6e875..000000000 --- a/battybirdnet-pi/rootfs/custom-services.d/00-php_pfm.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/usr/bin/with-contenv bash -# shellcheck shell=bash - -# Correct /config permissions after startup -chown pi:pi /config - -# Waiting for dbus -until [[ -e /var/run/dbus/system_bus_socket ]]; do - sleep 1s -done -echo "Starting service: php pfm" -exec /usr/sbin/php-fpm* -F diff --git a/battybirdnet-pi/rootfs/custom-services.d/01-avahi.sh b/battybirdnet-pi/rootfs/custom-services.d/01-avahi.sh deleted file mode 100755 index 1963c3d25..000000000 --- a/battybirdnet-pi/rootfs/custom-services.d/01-avahi.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/with-contenv bashio -# Waiting for dbus -until [[ -e /var/run/dbus/system_bus_socket ]]; do - sleep 1s -done - -echo "Starting service: avahi daemon" -exec \ - avahi-daemon --no-chroot diff --git a/battybirdnet-pi/rootfs/custom-services.d/02-caddy.sh b/battybirdnet-pi/rootfs/custom-services.d/02-caddy.sh deleted file mode 100755 index 511299480..000000000 --- a/battybirdnet-pi/rootfs/custom-services.d/02-caddy.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/with-contenv bashio -# shellcheck shell=bash - -# Dependencies -sockfile="empty" -until [[ -e /var/run/dbus/system_bus_socket ]] && [[ -e "$sockfile" ]]; do - sleep 1s - sockfile="$(find /run/php -name "*.sock")" -done - -# Correct fpm.sock -chown caddy:caddy /run/php/php*-fpm.sock -sed -i "s|/run/php/php-fpm.sock|$sockfile|g" /helpers/caddy_ingress.sh -sed -i "s|/run/php/php-fpm.sock|$sockfile|g" /etc/caddy/Caddyfile -sed -i "s|/run/php/php-fpm.sock|$sockfile|g" "$HOME"/BirdNET-Pi/scripts/update_caddyfile.sh - -# Update caddyfile with password -/."$HOME"/BirdNET-Pi/scripts/update_caddyfile.sh &>/dev/null || true - -echo "Starting service: caddy" -/usr/bin/caddy run --config /etc/caddy/Caddyfile diff --git a/battybirdnet-pi/rootfs/custom-services.d/02-nginx.sh b/battybirdnet-pi/rootfs/custom-services.d/02-nginx.sh deleted file mode 100755 index 08b3e2bd2..000000000 --- a/battybirdnet-pi/rootfs/custom-services.d/02-nginx.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/usr/bin/with-contenv bashio -# shellcheck shell=bash -set -e - -echo "Starting service: nginx" -nginx diff --git a/battybirdnet-pi/rootfs/custom-services.d/30-monitoring.sh b/battybirdnet-pi/rootfs/custom-services.d/30-monitoring.sh deleted file mode 100755 index 3bfa9185b..000000000 --- a/battybirdnet-pi/rootfs/custom-services.d/30-monitoring.sh +++ /dev/null @@ -1,261 +0,0 @@ -#!/usr/bin/env bash -# shellcheck shell=bash -# Improved BirdNET-Pi Monitoring Script with Recovery Alerts and Condensed Logs - -HOME="/home/pi" - -######################################## -# Logging Functions (color-coded for terminal clarity) -######################################## -log_green() { echo -e "\033[32m$1\033[0m"; } -log_red() { echo -e "\033[31m$1\033[0m"; } -log_yellow() { echo -e "\033[33m$1\033[0m"; } -log_blue() { echo -e "\033[34m$1\033[0m"; } - -######################################## -# Read configuration -######################################## -set +u -# shellcheck disable=SC1091 -source /etc/birdnet/birdnet.conf - -######################################## -# Wait 5 minutes for system stabilization -######################################## -sleep 5m - -log_green "Starting service: throttlerecording" - -######################################## -# Define Directories, Files, and Constants -######################################## -INGEST_DIR="$(readlink -f "$HOME/BirdSongs/StreamData")" -ANALYZING_NOW_FILE="$INGEST_DIR/analyzing_now.txt" -touch "$ANALYZING_NOW_FILE" -BIRDSONGS_DIR="$(readlink -f "$HOME/BirdSongs/Extracted/By_Date")" - -# Ensure directories and set permissions -mkdir -p "$INGEST_DIR" || { log_red "Failed to create directory: $INGEST_DIR"; exit 1; } -chown -R pi:pi "$INGEST_DIR" || log_yellow "Could not change ownership for $INGEST_DIR" -chmod -R 755 "$INGEST_DIR" || log_yellow "Could not set permissions for $INGEST_DIR" - -# Services to monitor -SERVICES=(birdnet_analysis chart_viewer spectrogram_viewer birdnet_recording birdnet_log birdnet_stats) - -######################################## -# Notification settings -######################################## -NOTIFICATION_INTERVAL=1800 # 30 minutes in seconds -NOTIFICATION_INTERVAL_IN_MINUTES=$(( NOTIFICATION_INTERVAL / 60 )) -last_notification_time=0 -issue_reported=0 # 1 = an issue was reported, 0 = system is normal -declare -A SERVICE_INACTIVE_COUNT=() - -# Disk usage threshold (percentage) -DISK_USAGE_THRESHOLD=95 - -# "Analyzing" file check variables -same_file_counter=0 -SAME_FILE_THRESHOLD=2 -if [[ -f "$ANALYZING_NOW_FILE" ]]; then - analyzing_now=$(<"$ANALYZING_NOW_FILE") -else - analyzing_now="" -fi - -######################################## -# Notification Functions -######################################## -apprisealert() { - local issue_message="$1" - local current_time - current_time=$(date +%s) - - # Calculate time_diff in minutes since last notification - local time_diff=$(( (current_time - last_notification_time) / 60 )) - - # Throttle notifications - if (( time_diff < NOTIFICATION_INTERVAL_IN_MINUTES )); then - log_yellow "Notification suppressed (last sent ${time_diff} minutes ago)." - return - fi - - local stopped_service="
Stopped services: " - for service in "${SERVICES[@]}"; do - if [[ "$(systemctl is-active "$service")" != "active" ]]; then - stopped_service+="$service; " - fi - done - - local notification="Issue: $issue_message" - notification+="$stopped_service" - notification+="
System: ${SITE_NAME:-$(hostname)}" - notification+="
Available disk space: $(df -h "$BIRDSONGS_DIR" | awk 'NR==2 {print $4}')" - notification+="
----Last log lines----" - notification+="
$(timeout 15 cat /proc/1/fd/1 | head -n 5)" - notification+="
----------------------" - [[ -n "$BIRDNETPI_URL" ]] && notification+="
Access your BirdNET-Pi" - - local TITLE="BirdNET-Analyzer Alert" - if [[ -f "$HOME/BirdNET-Pi/birdnet/bin/apprise" && -s "$HOME/BirdNET-Pi/apprise.txt" ]]; then - "$HOME/BirdNET-Pi/birdnet/bin/apprise" -vv -t "$TITLE" -b "$notification" \ - --input-format=html --config="$HOME/BirdNET-Pi/apprise.txt" - last_notification_time=$current_time - issue_reported=1 - else - log_red "Apprise not configured or missing!" - fi -} - -apprisealert_recovery() { - # Only send a recovery message if we had previously reported an issue - if (( issue_reported == 1 )); then - log_green "$(date) INFO: System is back to normal. Sending recovery notification." - - local TITLE="BirdNET-Pi System Recovered" - local notification="All monitored services are back to normal.
" - notification+="System: ${SITE_NAME:-$(hostname)}
" - notification+="Available disk space: $(df -h "$BIRDSONGS_DIR" | awk 'NR==2 {print $4}')" - - if [[ -f "$HOME/BirdNET-Pi/birdnet/bin/apprise" && -s "$HOME/BirdNET-Pi/apprise.txt" ]]; then - "$HOME/BirdNET-Pi/birdnet/bin/apprise" -vv -t "$TITLE" -b "$notification" \ - --input-format=html --config="$HOME/BirdNET-Pi/apprise.txt" - fi - issue_reported=0 - fi -} - -######################################## -# Helper Checks -######################################## - -check_disk_space() { - local current_usage - current_usage=$(df -h "$BIRDSONGS_DIR" | awk 'NR==2 {print $5}' | sed 's/%//') - - if (( current_usage >= DISK_USAGE_THRESHOLD )); then - log_red "$(date) INFO: Disk usage is at ${current_usage}% (CRITICAL!)" - apprisealert "Disk usage critical: ${current_usage}%" - return 1 - else - log_green "$(date) INFO: Disk usage is within acceptable limits (${current_usage}%)." - return 0 - fi -} - -check_analyzing_now() { - local current_file - current_file=$(cat "$ANALYZING_NOW_FILE" 2>/dev/null) - if [[ "$current_file" == "$analyzing_now" ]]; then - (( same_file_counter++ )) - else - same_file_counter=0 - analyzing_now="$current_file" - fi - - if (( same_file_counter >= SAME_FILE_THRESHOLD )); then - log_red "$(date) INFO: 'analyzing_now' file unchanged for $SAME_FILE_THRESHOLD iterations." - apprisealert "No change in analyzing_now for ${SAME_FILE_THRESHOLD} iterations" - "$HOME/BirdNET-Pi/scripts/restart_services.sh" - same_file_counter=0 - return 1 - else - # Only log if it changed this iteration - if (( same_file_counter == 0 )); then - log_green "$(date) INFO: 'analyzing_now' file has been updated." - fi - return 0 - fi -} - -check_queue() { - local wav_count - wav_count=$(find -L "$INGEST_DIR" -maxdepth 1 -name '*.wav' | wc -l) - - log_green "$(date) INFO: Queue is at a manageable level (${wav_count} wav files)." - - if (( wav_count > 50 )); then - log_red "$(date) INFO: Queue >50. Stopping recorder + restarting analyzer." - apprisealert "Queue exceeded 50: stopping recorder, restarting analyzer." - sudo systemctl stop birdnet_recording - sudo systemctl restart birdnet_analysis - return 1 - elif (( wav_count > 30 )); then - log_red "$(date) INFO: Queue >30. Restarting analyzer." - apprisealert "Queue exceeded 30: restarting analyzer." - sudo systemctl restart birdnet_analysis - return 1 - fi - return 0 -} - -check_services() { - local any_inactive=0 - - for service in "${SERVICES[@]}"; do - if [[ "$(systemctl is-active "$service")" != "active" ]]; then - SERVICE_INACTIVE_COUNT["$service"]=$(( SERVICE_INACTIVE_COUNT["$service"] + 1 )) - - if (( SERVICE_INACTIVE_COUNT["$service"] == 1 )); then - # First time inactive => Try to start - log_yellow "$(date) INFO: Service '$service' is inactive. Attempting to start..." - systemctl start "$service" - any_inactive=1 - elif (( SERVICE_INACTIVE_COUNT["$service"] == 2 )); then - # Second consecutive time => Send an alert - log_red "$(date) INFO: Service '$service' is still inactive after restart attempt." - apprisealert "Service '$service' remains inactive after restart attempt." - any_inactive=1 - else - # Beyond second check => keep logging or do advanced actions - log_red "$(date) INFO: Service '$service' inactive for ${SERVICE_INACTIVE_COUNT["$service"]} checks in a row." - any_inactive=1 - fi - else - # Service is active => reset counter - if (( SERVICE_INACTIVE_COUNT["$service"] > 0 )); then - log_green "$(date) INFO: Service '$service' is back to active. Resetting counter." - fi - SERVICE_INACTIVE_COUNT["$service"]=0 - fi - done - - if (( any_inactive == 0 )); then - log_green "$(date) INFO: All services are active" - return 0 - else - log_red "$(date) INFO: One or more services are inactive" - return 1 - fi -} - -######################################## -# Main Monitoring Loop -######################################## -while true; do - sleep 61 - log_blue "----------------------------------------" - log_blue "$(date) INFO: Starting monitoring check" - any_issue=0 - - # 1) Disk usage - check_disk_space || any_issue=1 - - # 2) 'analyzing_now' file - check_analyzing_now || any_issue=1 - - # 3) Queue check - check_queue || any_issue=1 - - # 4) Services check - check_services || any_issue=1 - - # Final summary - if (( any_issue == 0 )); then - log_green "$(date) INFO: All systems are functioning normally" - apprisealert_recovery - else - log_red "$(date) INFO: Issues detected. System status is not fully operational." - fi - log_blue "----------------------------------------" -done diff --git a/battybirdnet-pi/rootfs/etc/cont-finish.d/savestreamdata.sh b/battybirdnet-pi/rootfs/etc/cont-finish.d/savestreamdata.sh deleted file mode 100755 index 662817120..000000000 --- a/battybirdnet-pi/rootfs/etc/cont-finish.d/savestreamdata.sh +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/with-contenv bashio -# shellcheck shell=bash - -# Maximum file size in bytes (50MB) -MAX_SIZE=$((50 * 1024 * 1024)) - -# Function to check if a file is a valid WAV -is_valid_wav() { - local file="$1" - # Check if the file contains a valid WAV header - file "$file" | grep -qE 'WAVE audio' -} - -if [ -d "$HOME"/BirdSongs/StreamData ]; then - bashio::log.fatal "Container stopping, saving temporary files." - - # Stop the services in parallel - 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 - - # Create the destination directory - mkdir -p /data/StreamData - - # Move only valid WAV files under 50MB - shopt -s nullglob # Prevent errors if no files match - for file in "$HOME"/BirdSongs/StreamData/*.wav; do - if [ -f "$file" ] && [ "$(stat --format="%s" "$file")" -lt "$MAX_SIZE" ] && is_valid_wav "$file"; then - if mv -v "$file" /data/StreamData/; then - bashio::log.info "Moved valid WAV file: $(basename "$file")" - else - bashio::log.error "Failed to move: $(basename "$file")" - fi - else - bashio::log.warning "Skipping invalid or large file: $(basename "$file")" - fi - done - - 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 deleted file mode 100755 index 549f4780c..000000000 --- a/battybirdnet-pi/rootfs/etc/cont-init.d/01-structure.sh +++ /dev/null @@ -1,115 +0,0 @@ -#!/command/with-contenv bashio -# shellcheck shell=bash -set -e - -################## -# ALLOW RESTARTS # -################## - -if [[ "${BASH_SOURCE[0]}" == /etc/cont-init.d/* ]]; then - mkdir -p /etc/scripts-init - sed -i "s|/etc/cont-init.d|/etc/scripts-init|g" /ha_entrypoint.sh - sed -i "/ rm/d" /ha_entrypoint.sh - cp "${BASH_SOURCE[0]}" /etc/scripts-init/ -fi - -############### -# SET /CONFIG # -############### - -bashio::log.info "Ensuring the file structure is correct:" - -# Create default configuration files if not present -echo "... creating default 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 - -# 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")" - echo "... BIRDSONGS_FOLDER set to $BIRDSONGS_FOLDER_OPTION" - mkdir -p "$BIRDSONGS_FOLDER_OPTION" || bashio::log.fatal "...... folder couldn't be created" - chown -R pi:pi "$BIRDSONGS_FOLDER_OPTION" || bashio::log.fatal "...... folder couldn't be given permissions for 1000:1000" - if [ -d "$BIRDSONGS_FOLDER_OPTION" ] && [ "$(stat -c '%u:%g' "$BIRDSONGS_FOLDER_OPTION")" == "1000:1000" ]; then - BIRDSONGS_FOLDER="$BIRDSONGS_FOLDER_OPTION" - else - bashio::log.warning "BIRDSONGS_FOLDER reverted to /config/BirdSongs" - fi -fi - -# 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" - -# 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 /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 - -# 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 /etc/birdnet "$BIRDSONGS_FOLDER" /tmp - -# Backup default birdnet.conf for sanity check -cp "$HOME/BirdNET-Pi/birdnet.conf" "$HOME/BirdNET-Pi/birdnet.bak" - -# Create default birdnet.conf if not existing -if [ ! -f /config/birdnet.conf ]; then - cp -f "$HOME/BirdNET-Pi/birdnet.conf" /config/ -fi - -# Create default birds.db -if [ ! -f /config/birds.db ]; then - echo "... creating initial db" - "$HOME/BirdNET-Pi/scripts/createdb.sh" - cp "$HOME/BirdNET-Pi/scripts/birds.db" /config/ -elif [ "$(stat -c%s /config/birds.db)" -lt 10240 ]; then - echo "... your db is corrupted, creating new one" - rm /config/birds.db - "$HOME/BirdNET-Pi/scripts/createdb.sh" - cp "$HOME/BirdNET-Pi/scripts/birds.db" /config/ -fi - -# 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 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 - -# Set permissions for newly created files and folders -echo "... checking and setting permissions" -chmod -R 755 /config/* -chmod 777 /config - -# Create folder for matplotlib -echo "... setting up Matplotlabdir" -mkdir -p "$HOME"/.cache/matplotlib -chown -R "pi:pi" "$HOME"/.cache/matplotlib -chmod 777 "$HOME"/.cache/matplotlib - diff --git a/battybirdnet-pi/rootfs/etc/cont-init.d/02-restorestreamdata.sh b/battybirdnet-pi/rootfs/etc/cont-init.d/02-restorestreamdata.sh deleted file mode 100755 index e51a2f8dc..000000000 --- a/battybirdnet-pi/rootfs/etc/cont-init.d/02-restorestreamdata.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/command/with-contenv bashio -# shellcheck shell=bash -set -e - -################## -# ALLOW RESTARTS # -################## - -if [[ "${BASH_SOURCE[0]}" == /etc/cont-init.d/* ]]; then - mkdir -p /etc/scripts-init - sed -i "s|/etc/cont-init.d|/etc/scripts-init|g" /ha_entrypoint.sh - sed -i "/ rm/d" /ha_entrypoint.sh - cp "${BASH_SOURCE[0]}" /etc/scripts-init/ -fi - -###################### -# RESTORE STREAMDATA # -###################### - -if [ -d /config/TemporaryFiles ]; then - - # Check if there are .wav files in /config/TemporaryFiles - if find /config/TemporaryFiles -type f -name "*.wav" | grep -q .; then - bashio::log.warning "Container was stopped while files were still being analyzed." - echo "... restoring .wav files from /config/TemporaryFiles to $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 /config/TemporaryFiles -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 /config/TemporaryFiles/*.wav "$HOME"/BirdSongs/StreamData/ - rm -r /config/TemporaryFiles - - # 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 - - # Clean up the source folder if it is empty - if [ -z "$(ls -A /config/TemporaryFiles)" ]; then - rm -r /config/TemporaryFiles - 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 deleted file mode 100755 index b76d3ded3..000000000 --- a/battybirdnet-pi/rootfs/etc/cont-init.d/31-checks.sh +++ /dev/null @@ -1,75 +0,0 @@ -#!/command/with-contenv bashio -# shellcheck shell=bash -set -e - -################## -# ALLOW RESTARTS # -################## - -if [[ "${BASH_SOURCE[0]}" == /etc/cont-init.d/* ]]; then - mkdir -p /etc/scripts-init - sed -i "s|/etc/cont-init.d|/etc/scripts-init|g" /ha_entrypoint.sh - sed -i "/ rm/d" /ha_entrypoint.sh - cp "${BASH_SOURCE[0]}" /etc/scripts-init/ -fi - -###################### -# CHECK BIRDNET.CONF # -###################### - -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 - 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 except for the first one" - sed -i "0,/^$var=/!s/^$var=/#$var=/" "$configcurrent" - fi -done - -############## -# 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 -fi - -################## -# 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 # Avoid systemctl -sed -i "/systemctl /d" "$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh # Avoid systemctl -sed -i "/install_tmp_mount/d" "$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh # Use HA tmp -sed -i "/find /d" "$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh # Not useful -sed -i "/set -x/d" "$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh # Not useful -sed -i "/restart_services/d" "$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh # Not useful -sed -i "s|/etc/birdnet/birdnet.conf|/config/birdnet.conf|g" "$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh -sed -i "/update_caddyfile/c echo \"yes\"" "$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh # Avoid systemctl - -# Execute update_birdnet_snippets -export RECS_DIR="$HOME/BirdSongs" -export EXTRACTED="$HOME/BirdSongs/Extracted" -chmod +x "$HOME"/BirdNET-Pi/scripts/update_birdnet_snippets.sh -"$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 100644 index c83248bf7..000000000 --- a/battybirdnet-pi/rootfs/etc/cont-init.d/33-mqtt.sh +++ /dev/null @@ -1,84 +0,0 @@ -#!/command/with-contenv bashio -# shellcheck shell=bash -set -e - -################## -# ALLOW RESTARTS # -################## - -if [[ "${BASH_SOURCE[0]}" == /etc/cont-init.d/* ]]; then - mkdir -p /etc/scripts-init - sed -i "s|/etc/cont-init.d|/etc/scripts-init|g" /ha_entrypoint.sh - sed -i "/ rm/d" /ha_entrypoint.sh - cp "${BASH_SOURCE[0]}" /etc/scripts-init/ -fi - -############ -# SET MQTT # -############ - -# 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" - 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 100644 index 2523d4c3e..000000000 --- a/battybirdnet-pi/rootfs/etc/cont-init.d/71-newfeatures.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/command/with-contenv bashio -# shellcheck shell=bash -set -e - -################## -# ALLOW RESTARTS # -################## - -if [[ "${BASH_SOURCE[0]}" == /etc/cont-init.d/* ]]; then - mkdir -p /etc/scripts-init - sed -i "s|/etc/cont-init.d|/etc/scripts-init|g" /ha_entrypoint.sh - sed -i "/ rm/d" /ha_entrypoint.sh - cp "${BASH_SOURCE[0]}" /etc/scripts-init/ -fi - -################ -# ADD FEATURES # -################ - -bashio::log.info "Adding optional features" - -# 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 - diff --git a/battybirdnet-pi/rootfs/etc/cont-init.d/81-modifications.sh b/battybirdnet-pi/rootfs/etc/cont-init.d/81-modifications.sh deleted file mode 100755 index f6edb33e6..000000000 --- a/battybirdnet-pi/rootfs/etc/cont-init.d/81-modifications.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/command/with-contenv bashio -# shellcheck shell=bash disable=SC2016 -set -e - -################## -# ALLOW RESTARTS # -################## - -if [[ "${BASH_SOURCE[0]}" == /etc/cont-init.d/* ]]; then - mkdir -p /etc/scripts-init - sed -i "s|/etc/cont-init.d|/etc/scripts-init|g" /ha_entrypoint.sh - sed -i "/ rm/d" /ha_entrypoint.sh - cp "${BASH_SOURCE[0]}" /etc/scripts-init/ -fi - -################ -# MODIFY WEBUI # -################ - -bashio::log.info "Adapting webui" - -# 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" - -# Remove Ram drive option from webui -echo "... removing Ram drive from webui as it is handled from HA" -if grep -q "Ram drive" "$HOME/BirdNET-Pi/scripts/service_controls.php"; then - 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" -fi - -# Correct services to start as user pi -echo "... updating services to start as user pi" -if ! grep -q "/usr/bin/sudo" "$HOME/BirdNET-Pi/templates/birdnet_log.service"; then - 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 < <(find "$HOME/BirdNET-Pi/templates/" -name "birdnet*.service" -print) -fi - -# Send services log to container logs -echo "... redirecting services logs to container logs" -while IFS= read -r file; do - sed -i "/StandardError/d" "$file" - sed -i "/StandardOutput/d" "$file" - 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 "*.service" -print) - -# Avoid preselection in include and exclude lists -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" - -# Preencode API key -if ! grep -q "221160312" "$HOME/BirdNET-Pi/scripts/common.php"; then - sed -i "/return \$_SESSION\['my_config'\];/i\ \ \ \ if (isset(\$_SESSION\['my_config'\]) \&\& empty(\$_SESSION\['my_config'\]\['FLICKR_API_KEY'\])) {\n\ \ \ \ \ \ \ \ \$_SESSION\['my_config'\]\['FLICKR_API_KEY'\] = \"221160312e1c22\";\n\ \ \ \ }" "$HOME"/BirdNET-Pi/scripts/common.php - sed -i "s|e1c22|e1c22ec60ecf336951b0e77|g" "$HOME"/BirdNET-Pi/scripts/common.php -fi - -# Correct log services to show /proc/1/fd/1 -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" - -# Correct backup script -echo "... correct backup script" -sed -i "/PHP_SERVICE=/c PHP_SERVICE=\$(systemctl list-unit-files -t service --no-pager | grep 'php' | grep 'fpm' | awk '{print \$1}')" "$HOME/BirdNET-Pi/scripts/backup_data.sh" - -# Caddyfile modifications -echo "... modifying Caddyfile configurations" -caddy fmt --overwrite /etc/caddy/Caddyfile -#Change port to leave 80 free for certificate requests -if ! grep -q "http://:8081" /etc/caddy/Caddyfile; then - sed -i "s|http://|http://:8081|g" /etc/caddy/Caddyfile - 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 -fi - -# Correct webui paths -echo "... correcting webui paths" -if ! grep -q "/stats/" "$HOME/BirdNET-Pi/homepage/views.php"; then - sed -i "s|/stats|/stats/|g" "$HOME/BirdNET-Pi/homepage/views.php" - sed -i "s|/log|/log/|g" "$HOME/BirdNET-Pi/homepage/views.php" -fi - -# 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" -#if [[ -f /helpers/systemctl3.py ]]; then -# mv /helpers/systemctl3.py /bin/systemctl -# chmod a+x /bin/systemctl -#fi - -# Improve streamlit cache -#echo "... add streamlit cache" -#sed -i "/def get_data/i \\@st\.cache_resource\(\)" "$HOME/BirdNET-Pi/scripts/plotly_streamlit.py" - -# Allow reverse proxy for streamlit -echo "... allow reverse proxy for streamlit" -sed -i "s|plotly_streamlit.py --browser.gatherUsageStats|plotly_streamlit.py --server.enableXsrfProtection=false --server.enableCORS=false --browser.gatherUsageStats|g" "$HOME/BirdNET-Pi/templates/birdnet_stats.service" - -# Clean saved mp3 files -echo ".. add highpass and lowpass to sox extracts" -sed -i "s|f'={stop}']|f'={stop}', 'highpass', '250', 'lowpass', '15000']|g" "$HOME/BirdNET-Pi/scripts/utils/reporting.py" -sed -i '/sox.*-V1/s/spectrogram/highpass 250 spectrogram/' "$HOME/BirdNET-Pi/scripts/spectrogram.sh" - -# Correct timedatectl path -echo "updating timedatectl path" -if [[ -f /helpers/timedatectl ]]; then - mv /helpers/timedatectl /usr/bin/timedatectl - chown pi:pi /usr/bin/timedatectl - chmod a+x /usr/bin/timedatectl -fi - -# Correct timezone showing in config.php -# shellcheck disable=SC2016 -echo "... updating timezone in config.php" -sed -i -e '/