diff --git a/README.md b/README.md index 1e309cc3..0f5f127e 100644 --- a/README.md +++ b/README.md @@ -31,6 +31,7 @@ Changes include: - Fix: changing advanced settings was not updating on a fresh install ed. CHANNELS, RECORDING_LENGTH, ... simplify - Fix: PrivacyThreshold now works as intended - Support for 'Species range model V2.4 - V2' + - **Experimental support** for automatic updates of location utilizing gpsd service. It requires GPS device (USB looger, modem with GNSS capabilities) to be connected and configured in gpsd. !! note: see 'Migrating' on how to migrate from mcguirepr89 diff --git a/homepage/views.php b/homepage/views.php index cf48f304..2101acae 100644 --- a/homepage/views.php +++ b/homepage/views.php @@ -243,6 +243,10 @@ function copyOutput(elem) { 'sudo systemctl restart spectrogram_viewer.service', 'sudo systemctl disable --now spectrogram_viewer.service', 'sudo systemctl enable --now spectrogram_viewer.service', + 'sudo systemctl stop location_autoupdate.service', + 'sudo systemctl restart location_autoupdate.service', + 'sudo systemctl disable --now location_autoupdate.service', + 'sudo systemctl enable --now location_autoupdate.service', 'sudo systemctl enable '.get_service_mount_name().' && sudo reboot', 'sudo systemctl disable '.get_service_mount_name().' && sudo reboot', 'stop_core_services.sh', diff --git a/newinstaller.sh b/newinstaller.sh index fb0cac89..b63cb719 100755 --- a/newinstaller.sh +++ b/newinstaller.sh @@ -34,7 +34,7 @@ export HOME=$HOME export USER=$USER PACKAGES_MISSING= -for cmd in git jq ; do +for cmd in git jq gpsd; do if ! which $cmd &> /dev/null;then PACKAGES_MISSING="${PACKAGES_MISSING} $cmd" fi diff --git a/requirements.txt b/requirements.txt index 6cc8bbba..c81a907a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,3 +19,5 @@ altair<5 inotify requests matplotlib +gpsdclient +apscheduler \ No newline at end of file diff --git a/scripts/config.php b/scripts/config.php index 269c8a6f..ad9c1df5 100644 --- a/scripts/config.php +++ b/scripts/config.php @@ -51,6 +51,9 @@ function syslog_shell_exec($cmd, $sudo_user = null) { if(isset($_GET["latitude"])){ $latitude = $_GET["latitude"]; $longitude = $_GET["longitude"]; + $location_autoupdate = $_GET["location_autoupdate"]; + $location_autoupdate_interval = $_GET["location_autoupdate_interval"]; + $location_autoupdate_threshold = $_GET["location_autoupdate_threshold"]; $site_name = $_GET["site_name"]; $site_name = str_replace('"', "", $site_name); $site_name = str_replace('\'', "", $site_name); @@ -145,6 +148,9 @@ function() { $contents = preg_replace("/SITE_NAME=.*/", "SITE_NAME=\"$site_name\"", $contents); $contents = preg_replace("/LATITUDE=.*/", "LATITUDE=$latitude", $contents); $contents = preg_replace("/LONGITUDE=.*/", "LONGITUDE=$longitude", $contents); + $contents = preg_replace("/LOCATION_AUTOUPDATE=.*/", "LOCATION_AUTOUPDATE=$location_autoupdate", $contents); + $contents = preg_replace("/LOCATION_AUTOUPDATE_INTERVAL=.*/", "LOCATION_AUTOUPDATE_INTERVAL=$location_autoupdate_interval", $contents); + $contents = preg_replace("/LOCATION_AUTOUPDATE_THRESHOLD=.*/", "LOCATION_AUTOUPDATE_THRESHOLD=$location_autoupdate_threshold", $contents); $contents = preg_replace("/BIRDWEATHER_ID=.*/", "BIRDWEATHER_ID=$birdweather_id", $contents); $contents = preg_replace("/APPRISE_NOTIFICATION_TITLE=.*/", "APPRISE_NOTIFICATION_TITLE=\"$apprise_notification_title\"", $contents); $contents = preg_replace("/APPRISE_NOTIFICATION_BODY=.*/", "APPRISE_NOTIFICATION_BODY=\"$apprise_notification_body\"", $contents); @@ -458,8 +464,26 @@ function runProcess() { + + + + + + + + + + + + + + +

Set your Latitude and Longitude to 4 decimal places. Get your coordinates here.

+

Location autoupdate enables BirdNET-Pi to update its position from GPS device (via gpsd service).

+

Location autoupdate interval is set in seconds.

+

Location autoupdate threshold sets sensitivity for location changes, this way small fluctuations will be ingored.


BirdWeather

diff --git a/scripts/install_config.sh b/scripts/install_config.sh index 9456c613..b8857d0f 100755 --- a/scripts/install_config.sh +++ b/scripts/install_config.sh @@ -34,10 +34,17 @@ SITE_NAME="$HOSTNAME" ## TO BE CHANGED TO STATIC VALUES ## Please only go to 4 decimal places. Example:43.3984 - LATITUDE=$LATITUDE LONGITUDE=$LONGITUDE +#--------------------- Experimental: location autoupdate ---------------------# + +## This is an experiment to create service for updating location from locally +## running gpsd daemon, requires supported GPS device to be attached. +LOCATION_AUTOUPDATE=0 +LOCATION_AUTOUPDATE_INTERVAL=300 +LOCATION_AUTOUPDATE_THRESHOLD=0.0002 + #--------------------------------- Model --------------------------------------# #_____________The variable below configures which BirdNET model is_____________# #______________________used for detecting bird audio.__________________________# diff --git a/scripts/install_services.sh b/scripts/install_services.sh index 9fe1d4e6..99d8476b 100755 --- a/scripts/install_services.sh +++ b/scripts/install_services.sh @@ -56,6 +56,22 @@ EOF systemctl enable birdnet_analysis.service } +install_location_autoupdate_service() { + cat << EOF > $HOME/BirdNET-Pi/templates/location_autoupdate.service +[Unit] +Description=The gpsd based location autoupdate for BirdNET +[Service] +Restart=no +Type=simple +User=${USER} +ExecStart=$PYTHON_VIRTUAL_ENV /usr/local/bin/location_autoupdate.py +[Install] +WantedBy=multi-user.target +EOF + ln -sf $HOME/BirdNET-Pi/templates/location_autoupdate.service /usr/lib/systemd/system +} +export -f install_location_autoupdate_service + create_necessary_dirs() { echo "Creating necessary directories" [ -d ${EXTRACTED} ] || sudo -u ${USER} mkdir -p ${EXTRACTED} @@ -420,6 +436,7 @@ install_services() { install_cleanup_cron install_weekly_cron increase_caddy_timeout + install_location_autoupdate_service # But does not enable, as it's experimental feature create_necessary_dirs generate_BirdDB diff --git a/scripts/location_autoupdate.py b/scripts/location_autoupdate.py new file mode 100644 index 00000000..a57bb1ea --- /dev/null +++ b/scripts/location_autoupdate.py @@ -0,0 +1,86 @@ +"""This module gets location from gpsd daemon and updates configuration if needed.""" +import logging +import sys + +from apscheduler.schedulers.background import BlockingScheduler +import gpsdclient +from utils.helpers import get_settings, _load_settings, write_settings + +log = logging.getLogger(__name__) + +def main(): + """Starting the location updates at given interval.""" + conf = get_settings() + + if(conf.getint('LOCATION_AUTOUPDATE') == 1): + log.info("Starting location autoupdate service") + scheduler = BlockingScheduler() + scheduler.add_job(location_update,'interval',seconds=conf.getint('LOCATION_AUTOUPDATE_INTERVAL')) + scheduler.start() + else: + log.info("Location autoupdate service is not enabled in birdnet.conf. Not starting.") + +def location_update(): + """Gets location from gpsd and updates configuration if needed.""" + _load_settings('/etc/birdnet/birdnet.conf',True) + conf = get_settings() + currentlatitude = conf.getfloat('LATITUDE') + currentlongitude = conf.getfloat('LONGITUDE') + + threshold=conf.getfloat('LOCATION_AUTOUPDATE_THRESHOLD') + with gpsdclient.GPSDClient(host="127.0.0.1") as client: + for result in client.dict_stream(convert_datetime=True, filter=["TPV"]): + lat = result.get("lat", "n/a") + lon = result.get("lon", "n/a") + if(lat != "n/a" and lon != "n/a"): + break + + newlatitude=round(lat,4) + newlongitude=round(lon,4) + + latdiff = abs(currentlatitude - newlatitude) + londiff = abs(currentlongitude - newlongitude) + + if((latdiff > threshold) or (londiff > threshold)): + log.info("New location detected: %s, %s",newlatitude,newlongitude) + lat2replace = "LATITUDE="+str(currentlatitude) + lon2replace = "LONGITUDE="+str(currentlongitude) + lat2replacewith = "LATITUDE="+str(newlatitude) + lon2replacewith = "LONGITUDE="+str(newlongitude) + + try: + with open('/etc/birdnet/birdnet.conf', 'r') as configfile: + configuration = configfile.read() + configuration = configuration.replace(lat2replace,lat2replacewith) + configuration = configuration.replace(lon2replace,lon2replacewith) + configfile.close() + except Exception as e: + log.error("Error occured while trying to read configuration: ", e) + + try: + with open('/etc/birdnet/birdnet.conf', 'w') as configfile: + configfile.write(configuration) + configfile.flush() + configfile.close() + except Exception as e: + log.error("Error occured while trying to write configuration: ", e) + + _load_settings('/etc/birdnet/birdnet.conf',True) + write_settings() + + +def setup_logging(): + """Do logging in a nice and polite way.""" + logger = logging.getLogger() + formatter = logging.Formatter("[%(name)s][%(levelname)s] %(message)s") + handler = logging.StreamHandler(stream=sys.stdout) + handler.setFormatter(formatter) + logger.addHandler(handler) + logger.setLevel(logging.INFO) + global log + log = logging.getLogger('location_autoupdater') + + +if __name__ == '__main__': + setup_logging() + main() diff --git a/scripts/restart_services.sh b/scripts/restart_services.sh index 9ce33d39..fba7aa0e 100755 --- a/scripts/restart_services.sh +++ b/scripts/restart_services.sh @@ -8,6 +8,7 @@ my_dir=$HOME/BirdNET-Pi/scripts sudo systemctl stop birdnet_recording.service services=(chart_viewer.service + location_autoupdate.service spectrogram_viewer.service icecast2.service birdnet_recording.service diff --git a/scripts/service_controls.php b/scripts/service_controls.php index 97a3d6ec..d0756d7a 100644 --- a/scripts/service_controls.php +++ b/scripts/service_controls.php @@ -88,6 +88,14 @@ function service_status($name) { +

Location Autoupdate (!experimental!)

+
+ + + + +
+
diff --git a/scripts/update_birdnet_snippets.sh b/scripts/update_birdnet_snippets.sh index 5157a952..8842456d 100755 --- a/scripts/update_birdnet_snippets.sh +++ b/scripts/update_birdnet_snippets.sh @@ -160,6 +160,26 @@ if ! [ -L /etc/avahi/services/http.service ];then systemctl restart avahi-daemon.service fi +# Add location autoupdate service if it ain't there +if ! [ -f $HOME/BirdNET-Pi/templates/location_autoupdate.service ];then + sudo_with_user $HOME/BirdNET-Pi/birdnet/bin/pip3 install gpsdclient + sudo_with_user $HOME/BirdNET-Pi/birdnet/bin/pip3 install apscheduler + export PYTHON_VIRTUAL_ENV="$HOME/BirdNET-Pi/birdnet/bin/python3" + cat << EOF > $HOME/BirdNET-Pi/templates/location_autoupdate.service +[Unit] +Description=The gpsd based location autoupdate for BirdNET +[Service] +Restart=no +Type=simple +User=${USER} +ExecStart=$PYTHON_VIRTUAL_ENV /usr/local/bin/location_autoupdate.py +[Install] +WantedBy=multi-user.target +EOF + sudo -E chown $USER:$USER $HOME/BirdNET-Pi/templates/location_autoupdate.service + ln -sf $HOME/BirdNET-Pi/templates/location_autoupdate.service /usr/lib/systemd/system +fi + if [ -L /usr/local/bin/analyze.py ];then rm -f /usr/local/bin/analyze.py fi