Merge pull request #586 from jprochazka/jobs

v2.8.4 (Should be back to where we were now.)
pull/589/head v2.8.4
Joseph Prochazka 2024-07-13 20:50:05 -04:00 zatwierdzone przez GitHub
commit 1792d3ee02
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
20 zmienionych plików z 728 dodań i 598 usunięć

Wyświetl plik

@ -2,10 +2,23 @@
The following is a history of the changes made to this project.
## v2.8.3 *(July 7th, 2024)* :chicken:
## v2.8.4 *(July 13th, 2024)* :rooster:
### Installers
* Added the option to install the airplanes.live feeder client and web interface.
### Portal
* Can now toggle daily data purges as well specify the number of days to keep within the portal.
* Rewrote the aircraft.py script and fixed issues found with newer versions of dump1090.
* Rewrote the maintenance.py script and addressed issue mentioned in an incompatible pull request.
* The page displaying plots now shows missing data in the side bar revealing when clicking on marker.
* Added images to the side bar displayed when the marker is clicked when viewing the plots page.
* The flights page now only shows links when position information is present in the database.
## v2.8.3 *(July 7th, 2024)* :chicken:
* Added the option to install the Fly Italy ADS-B feeder client.
* Tested installation processes on Armbian Bookworm.
* Tested installation processes on Armbian Jammy.
@ -16,9 +29,6 @@ The following is a history of the changes made to this project.
* The --branch <branch_name> and -b <branch_name> parameters properly specify the branch to use.
* Fixed issue noticed in the line downloading the Duck DNS log during setup.
* Refactoring and standards compliance changes were made to multiple bash scripts.
### Portal
* The proper collectd CPU temperature configuration is inserted for Raspberry PI 4 Model B devices.
## v2.8.2 *(June 29th, 2024)* :baby_chick:

Wyświetl plik

@ -1,11 +1,9 @@
# Credits :airplane:
## People and Places
## Collaborators and Contributors
First off I would like to thank the collaborators and contributors who have contributed to the project
directly. Their time and effort is greatly appreciated by myself as well as many others I am sure.
**Direct Contributors**
First and foremost I would like to thank the collaborators and contributors who have contributed to
the project directly. Their time and effort is greatly appreciated by myself as well as many others.
* @mgunther68
* @jdwall
@ -29,37 +27,44 @@ directly. Their time and effort is greatly appreciated by myself as well as many
* @Romeo-Golf
* @g0wfv
I would like to thank the members and contributors to the following forums for all the time and effort
they have put in in order to create a useful and informative place to discuss aircraft tracking.
## The Flight Tracking Community
* The FlightAware Forums: http://discussions.flightaware.com
* The PlaneFinder Forums: http://forum.planefinder.net
I would like to thank the members and contributors to the following forums for all the time and effort
they have put in in order to create useful and informative places to discuss aircraft tracking.
* The FlightAware Forums: https://discussions.flightaware.com
* The PlaneFinder Forums: https://forum.planefinder.net
* The ADS-B Exchange Forums: https://adsbx.discourse.group
The performance graphs were created thanks in part to the great contributions made by members of both
the FlightAware and PlaneFinder communities. Through their examples and help posted to the following
threads myself and a couple contributors were able to add these very informative graphs.
threads myself along with other contributors to the cause were able to add these informative graphs.
* http://discussions.flightaware.com/ads-b-flight-tracking-f21/system-monitoring-t26999.html
* http://forum.planefinder.net/threads/web-portal-and-collectd-rrd-graphs-automated-installation.256/
* http://forum.planefinder.net/threads/web-portal-and-collectd-rrd-graphs-automated-installation.256
## Third Party Software
## Third Party Software Developers
I would like to thank the developers and contributors to the following projects. Without their
hard work and dedication this project would not have been possible.
I would like to thank the maintainers and contributors of the following projects. Without their
hard work and dedication to their respective projects this project would not have been possible.
* Dump1090 (fa): https://github.com/flightaware/dump1090
* Dump978 (fa): https://github.com/flightaware/dump978
* FlightAware's PiAware: https://github.com/flightaware/piaware
* Plane Finder ADS-B Client: https://planefinder.net
* Flightradar24 Client: https://www.flightradar24.com
* Dump1090-Tools: https://github.com/mutability/dump1090-tools
* Beast-Splitter https://github.com/flightaware/beast-splitter
* bootpag http://botmonster.com/jquery-bootpag
* Bootstrap: http://getbootstrap.com/
* jQuery: http://jquery.com/
* jQuery Steps: http://www.jquery-steps.com
* js-cookie: https://github.com/js-cookie/js-cookie/releases
* jquery-validation: https://github.com/jzaefferer/jquery-validation
* Google Charts: https://developers.google.com/chart
* Duck DNS http://www.duckdns.com
* ADS-B Exchange Client: https://github.com/adsbexchange/feedclient
* Airplanes.live Client: https://github.com/airplanes-live/feed
* Beast-Splitter: https://github.com/flightaware/beast-splitter
* Dump1090 (FlightAware): https://github.com/flightaware/dump1090
* Dump1090-Tools: https://github.com/mutability/dump1090-tools
* Dump978 (FlightAware): https://github.com/flightaware/dump978
* Fly Italy ADS-B Client: https://github.com/flyitalyadsb/fly-italy-adsb
* PiAware (FlightAware): https://github.com/flightaware/piaware
Thanks also goes out to the developers and the businesses that employ them who work to supply us
with quality closed source packages which they have made available to the community.
* Flightradar24: https://flightradar24.com
* OpenSky Network: https://opensky-network.org
* Plane Finder: https://planefinder.net
Yet another thanks goes out to those kind enough to share their photographs the community as well as
those hosting these images and make them avaiable for us to use in projects such as this.
* https://www.planespotters.net

Wyświetl plik

@ -4,7 +4,7 @@
This project continues to realize that for some, Docker and premade images are not the most optimal solution.
It would seem as of late the move towards premade and as well as Docker and other PaaS images with preinstalled software are the rage within the community. The problem is Docker images require additional software and overhead in order to run and premade images lack installation options. Solutions such as these come preinstalled with software you may never wish to use as part of the image. What this project offers is the possibility for less overhead and better performance, depending on your installation choices of course, on a wide range of devices and hardware archetectures while installing only the applications you want natively.
It would seem as of late the move towards premade as well as Docker and other PaaS images with preinstalled software has become popular within the community. Docker images require additional software and overhead in order to run and premade images lack installation options. Most of these solutions come with preinstalled software you may never use as part of the image as well. This project offers the ability to choose and install only what you want or need across a wide range of devices with minimal command line experience.
## Obtaining And Using This Software
@ -32,15 +32,15 @@ The following software can be installed using these scripts.
Included is the option to install the ADS-B Portal which offers the following features.
* Saves all flights seen as well as displays a plot for the flight. (advanced)
* Saves all flights seen as well as displays a plot for the flight.
* Control what is displayed online via a web based administration area.
* A more uniform website site layout that can be easily navigated.
* Web accessible dump1090 and system performance graphs.
* A web accessible live dump1090 map.
* A web accessible live dump978 map.
* Easy access to live dump1090 and dump978 maps.
* A blog which can be used to share your plane tracking experiences with others.
* Informs visitors when specific flights are being tracked by dump1090.
* Easily customize the look of your portal using the template system.
* Visitors can be informed when specific flights are being tracked.
* Administrators can be informed via email when specific flights are being tracked.
* Easily customize the look of your portal using the custom template system.
When setting up the portal you will have to choose between a lite or advanced installation. Advanced features adds flight logging and plotting and should only be chosen on devices running a more sturdy data storage solution.
@ -48,40 +48,34 @@ When setting up the portal you will have to choose between a lite or advanced in
### Decoders
* Dump1090 (FlightAware): https://github.com/flightaware/dump1090
* Dump978 (FlightAware): https://github.com/mutability/dump978
* Dump1090 (FlightAware): https://github.com/flightaware/dump1090
* Dump978 (FlightAware): https://github.com/mutability/dump978
### Feeders
* ADS-B Exchange Feeder Client: https://adsbexchange.com
* FlightAware's PiAware: https://flightaware.com
* Flightradar24 Feeder Client: https://flightradar24.com
* Fly Italy ADS-B Feeder Client: https://flyitalyadsb.com/
* OpenSky Feeder Client: https://opensky-network.org
* Plane Finder ADS-B Client: https://planefinder.net
* ADS-B Exchange Feeder Client: https://adsbexchange.com
* Airplanes.live Feeder Client: https://airplanes.live
* FlightAware's PiAware: https://flightaware.com
* Flightradar24 Feeder Client: https://flightradar24.com
* Fly Italy ADS-B Feeder Client: https://flyitalyadsb.com
* OpenSky Feeder Client: https://opensky-network.org
* Plane Finder ADS-B Client: https://planefinder.net
### Extras
* Beast-Splitter: https://github.com/flightaware/beast-splitter
* DuckDNS.org Support: https://www.duckdns.org/
* Beast-Splitter: https://github.com/flightaware/beast-splitter
* DuckDNS.org Support: https://www.duckdns.org
## Supported Operating Systems
The project currently supports the following Linux distributions.
* Armbian Bookworm
* Armbian Jammy
* Debian Bookworm
* Debian Bullseye
* DietPi (Bookworm)
* DietPi (Bullseye)
* Rasbperry PI OS (Bookworm)
* Rasbperry PI OS Legacy (Bullseye)
* Ubuntu Jammy Jellyfish
* Ubuntu Focal Fossa
* Armbian _(Bookworm and Jammy)_
* Debian _(Bookworm and Bullseye)_
* DietPi _(Bookworm aand Bullseye)_
* Rasbperry PI OS _(Bookworm and Bullseye)_
* Ubuntu _(Jammy Jellyfish and Focal Fossa)_
## Useful Links
_Support is available via this repository through the use of the issue tracker or discussions._
- GitHub Repository - https://github.com/jprochazka/adsb-receiver
- GitHub Wiki - https://github.com/jprochazka/adsb-receiver/wiki
- Changelog - https://github.com/jprochazka/adsb-receiver/blob/master/CHANGELOG.md
[Support for Ubuntu Noble Numbat is on hold due to incompatibilities with PiAware's MLAT client.](https://github.com/jprochazka/adsb-receiver/issues/575)

Wyświetl plik

@ -0,0 +1,113 @@
#!/bin/bash
## INCLUDE EXTERNAL SCRIPTS
source $RECEIVER_BASH_DIRECTORY/variables.sh
source $RECEIVER_BASH_DIRECTORY/functions.sh
## BEGIN SETUP
clear
echo -e "\n\e[91m ${RECEIVER_PROJECT_TITLE}"
echo -e ""
echo -e "\e[92m Setting up the airplanes.live feeder client..."
echo -e ""
echo -e "\e[93m ------------------------------------------------------------------------------\e[96m"
echo -e ""
# Confirm component installation.
if ! whiptail --backtitle "${RECEIVER_PROJECT_TITLE}" --title "Airplanes.live Feeder Client Setup" --yesno "The airplanes.live feeder client takes data from a local dump1090 instance and shares this with airplanes.live. for more information please see their website:\n\n https://airplanes.live/how-to-feed/\n\nContinue setup by installing the airplanes.live feeder client?" 13 78 3>&1 1>&2 2>&3; then
echo -e "\e[91m \e[5mINSTALLATION HALTED!\e[25m"
echo -e " Setup has been halted at the request of the user."
echo -e ""
echo -e "\e[93m ------------------------------------------------------------------------------"
echo -e "\e[92m Airplanes.live feeder client setup halted.\e[39m"
echo -e ""
read -p "Press enter to continue..." discard
exit 1
fi
## START FEEDER INSTALLATION
echo -e ""
echo -e "\e[95m Begining the airplanes.live feeder client installation process...\e[97m"
echo -e ""
# Create the component build directory if it does not exist
if [[ ! -d $RECEIVER_BUILD_DIRECTORY/airplaneslive ]]; then
echo -e "\e[94m Creating the airplanes.live feeder client build directory...\e[97m"
echo ""
mkdir -vp $RECEIVER_BUILD_DIRECTORY/airplaneslive
echo ""
fi
# Change to the component build directory
echo -e "\e[94m Entering the airplanes.live feeder client build directory...\e[97m"
cd $RECEIVER_BUILD_DIRECTORY/airplaneslive 2>&1
echo ""
# Download the official airplanes.live feeder installation script
echo -e "\e[95m Beginning the airplanes.live feeder client installation...\e[97m"
echo -e ""
echo -e "\e[94m Downloading the airplanes.live feeder client installation script...\e[97m"
echo ""
wget -v https://raw.githubusercontent.com/airplanes-live/feed/main/install.sh
echo -e "\e[94m Executing the airplanes.live feeder client installation script...\e[97m"
echo ""
sudo bash $RECEIVER_BUILD_DIRECTORY/airplaneslive/install.sh
echo ""
## CHECK THE STATUS OF THE FEEDER
echo -e "\e[95m Checking if the reciver is now feeding airplanes.live...\e[97m"
echo -e ""
"\e[95m Checking for connections on ports 30004 and 31090 to IP address 78.46.234.18...\e[97m"
netstat_output = `netstat -t -n | grep -E '30004|31090'`
if [[ $netstat_output == *"78.46.234.18:30004 ESTABLISHED"* && $netstat_output == *"78.46.234.18:31090 ESTABLISHED"* ]]
"\e[95m The receiver appears to be feeding airplanes.live...\e[97m"
else
"\e[91m The receiver does not appear to be feeding airplanes.live at this time...\e[97m"
"\e[95m Please reboot your device and run the command ''netstat -t -n | grep -E '30004|31090' to see if a connection has been astablished.\e[97m"
"\e[95m If the issue presists supply the last 20 lines given by the following command on the airplanes.live discord.\e[97m"
"\e[95m 'sudo journalctl -u airplanes-feed --no-pager'\e[97m"
"\e[95m 'sudo journalctl -u airplanes-mlat --no-pager'\e[97m"
fi
echo ""
## INSTALL THE AIRPLANES.LIVE WEB INTERFACE
if whiptail --backtitle "${RECEIVER_PROJECT_TITLE}" --title "Airplanes.live Web Interface Setup" --yesno "Airplanes.live offers the option to install an additional web interface.\n\nWould you like to install the web interface now?" 12 78; then
echo -e "\e[95m Begining the airplanes.live web interface installation...\e[97m"
echo ""
echo -e "\e[94m Executing the airplanes.live web interface installation script...\e[97m"
echo ""
sudo bash sudo bash /usr/local/share/airplanes/git/install-or-update-interface.sh
echo ""
fi
## POST INSTALLATION INFORMATION
whiptail --backtitle "${RECEIVER_PROJECT_TITLE}" --title "Airplanes.live Feeder Setup Complete" --msgbox "Setup of the airplanes.live feeder client is now complete. You can check your feeder status at https://airplanes.live/myfeed." 12 78
## SETUP COMPLETE
# Return to the project root directory
echo -e "\e[94m Returning to ${RECEIVER_PROJECT_TITLE} root directory...\e[97m"
cd $RECEIVER_ROOT_DIRECTORY 2>&1
echo -e ""
echo -e "\e[93m ------------------------------------------------------------------------------"
echo -e "\e[92m Airplanes.live feeder client setup is complete.\e[39m"
echo -e ""
read -p "Press enter to continue..." discard
exit 0

Wyświetl plik

@ -42,6 +42,15 @@ function InstallAdsbExchange() {
fi
}
# Execute the airplanes.live setup script.
function InstallAirplanesLive() {
chmod +x ${RECEIVER_BASH_DIRECTORY}/feeders/airplaneslive.sh
${RECEIVER_BASH_DIRECTORY}/feeders/airplaneslive.sh
if [[ $? -ne 0 ]] ; then
exit 1
fi
}
# Execute the Flightradar24 Feeder client setup script.
function InstallFlightradar24() {
chmod +x ${RECEIVER_BASH_DIRECTORY}/feeders/flightradar24.sh
@ -208,6 +217,17 @@ else
FEEDER_LIST=("${FEEDER_LIST[@]}" 'ADS-B Exchange Feeder' '' OFF)
fi
# Check if the airplanes.live feeder has been set up.
if [[ -f /lib/systemd/system/airplanes-feed.service && -f /lib/systemd/system/airplanes-mlat.service ]]; then
# The feeder appears to be set up.
echo "Airplanes.live Feeder (reinstall)" >> ${RECEIVER_ROOT_DIRECTORY}/FEEDER_CHOICES
FEEDER_LIST=("${FEEDER_LIST[@]}" 'Airplanes.live Feeder (reinstall)' '' OFF)
else
# The feeder does not appear to be set up.
echo "Airplanes.live Feeder" >> ${RECEIVER_ROOT_DIRECTORY}/FEEDER_CHOICES
FEEDER_LIST=("${FEEDER_LIST[@]}" 'Airplanes.live Feeder' '' OFF)
fi
# Check if the Fly Italy ADS-B feeder has been set up.
if [[ -f /lib/systemd/system/flyitalyadsb-mlat.service && -f /lib/systemd/system/flyitalyadsb-feed.service ]]; then
# The feeder appears to be set up.
@ -306,7 +326,7 @@ fi
if [[ -n "${FEEDER_LIST}" ]] ; then
# Display a checklist containing feeders that are not installed if any.
whiptail --backtitle "${RECEIVER_PROJECT_TITLE}" --title "Feeder Installation Options" --checklist --nocancel --separate-output "The following feeders are available for installation.\nChoose the feeders you wish to install." 13 65 6 "${FEEDER_LIST[@]}" 2>${RECEIVER_ROOT_DIRECTORY}/FEEDER_CHOICES
whiptail --backtitle "${RECEIVER_PROJECT_TITLE}" --title "Feeder Installation Options" --checklist --nocancel --separate-output "The following feeders are available for installation.\nChoose the feeders you wish to install." 15 65 7 "${FEEDER_LIST[@]}" 2>${RECEIVER_ROOT_DIRECTORY}/FEEDER_CHOICES
else
# Since all available feeders appear to be installed inform the user of the fact.
whiptail --backtitle "${RECEIVER_PROJECT_TITLE}" --title "All Feeders Installed" --msgbox "It appears that all the optional feeders available for installation by this script have been installed already." 8 65
@ -466,6 +486,9 @@ if [[ -s "${RECEIVER_ROOT_DIRECTORY}/FEEDER_CHOICES" ]]; then
"ADS-B Exchange Feeder"|"ADS-B Exchange Feeder (reinstall)")
RUN_ADSBEXCHANGE_SCRIPT="true"
;;
"Airplanes.live Feeder"|"Airplanes.live Feeder (reinstall)")
RUN_AIRPLANESLIVE_SCRIPT="true"
;;
"FlightAware PiAware"|"FlightAware PiAware (upgrade)"|"FlightAware PiAware (reinstall)")
RUN_PIAWARE_SCRIPT="true"
;;
@ -489,6 +512,10 @@ if [[ "${RUN_ADSBEXCHANGE_SCRIPT}" = "true" ]]; then
InstallAdsbExchange
fi
if [[ "${RUN_AIRPLANESLIVE_SCRIPT}" = "true" ]]; then
InstallAirplanesLive
fi
if [[ "${RUN_PIAWARE_SCRIPT}" = "true" || "${FORCE_PIAWARE_INSTALL}" = "true" ]]; then
InstallPiAware
fi

Wyświetl plik

@ -1,36 +1,5 @@
#!/bin/bash
#####################################################################################
# ADS-B RECEIVER #
#####################################################################################
# #
# This script is not meant to be executed directly. #
# Instead execute install.sh to begin the installation process. #
# #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# #
# Copyright (c) 2015-2024 Joseph A. Prochazka #
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy #
# of this software and associated documentation files (the "Software"), to deal #
# in the Software without restriction, including without limitation the rights #
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
# copies of the Software, and to permit persons to whom the Software is #
# furnished to do so, subject to the following conditions: #
# #
# The above copyright notice and this permission notice shall be included in all #
# copies or substantial portions of the Software. #
# #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #
# SOFTWARE. #
# #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
## VARIABLES
PORTAL_BUILD_DIRECTORY="${RECEIVER_BUILD_DIRECTORY}/portal"

Wyświetl plik

@ -1,50 +1,18 @@
#!/bin/bash
#####################################################################################
# ADS-B RECEIVER #
#####################################################################################
# #
# This script is not meant to be executed directly. #
# Instead execute install.sh to begin the installation process. #
# #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# #
# Copyright (c) 2015-2024 Joseph A. Prochazka #
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy #
# of this software and associated documentation files (the "Software"), to deal #
# in the Software without restriction, including without limitation the rights #
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
# copies of the Software, and to permit persons to whom the Software is #
# furnished to do so, subject to the following conditions: #
# #
# The above copyright notice and this permission notice shall be included in all #
# copies or substantial portions of the Software. #
# #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #
# SOFTWARE. #
# #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
## VARIABLES
PORTAL_PYTHON_DIRECTORY="${RECEIVER_BUILD_DIRECTORY}/portal/python"
PYTHON_PATH=`which python3`
python_path=`which python3`
## SETUP FLIGHT LOGGING
echo -e ""
echo -e "\e[95m Setting up flight logging...\e[97m"
echo -e "\e[95m Setting up portal flight logging and maintenance...\e[97m"
echo -e ""
# Create the cron jobs responsible for logging and maintenance.
echo -e "\e[94m Creating the maintenance maintenance script...\e[97m"
echo -e "\e[94m Creating the portal script cron file...\e[97m"
sudo tee /etc/cron.d/adsb-receiver-flight-logging > /dev/null <<EOF
* * * * * root ${PYTHON_PATH} ${PORTAL_PYTHON_DIRECTORY}/flights.py
30 * * * * root ${PYTHON_PATH} ${PORTAL_PYTHON_DIRECTORY}/maintenance.py
* * * * * root ${python_path} ${RECEIVER_BUILD_DIRECTORY}/portal/python/flights.py
0 0 * * * root ${python_path} ${RECEIVER_BUILD_DIRECTORY}/portal/python/maintenance.py
EOF

Wyświetl plik

@ -1,40 +1,9 @@
#!/bin/bash
#####################################################################################
# ADS-B RECEIVER #
#####################################################################################
# #
# This script is not meant to be executed directly. #
# Instead execute install.sh to begin the installation process. #
# #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# #
# Copyright (c) 2015-2024, Joseph A. Prochazka #
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy #
# of this software and associated documentation files (the "Software"), to deal #
# in the Software without restriction, including without limitation the rights #
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
# copies of the Software, and to permit persons to whom the Software is #
# furnished to do so, subject to the following conditions: #
# #
# The above copyright notice and this permission notice shall be included in all #
# copies or substantial portions of the Software. #
# #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #
# SOFTWARE. #
# #
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
## SOFTWARE VERSIONS
# The ADS-B Receiver Project
PROJECT_VERSION="2.8.3"
PROJECT_VERSION="2.8.4"
# FlightAware
DUMP1090_FA_VERSION="9.0"

Wyświetl plik

@ -7,9 +7,6 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/admin/assets/css/bootstrap.min.css">
<link rel="stylesheet" href="/admin/assets/css/bootstrap-theme.min.css">
<?php if (basename($_SERVER['PHP_SELF']) == "index.php") { ?>
<link rel="stylesheet" href="/admin/assets/css/jquery.datetimepicker.css">
<?php } ?>
<link rel="stylesheet" href="/admin/assets/css/admin.css">
<script src="/admin/assets/js/jquery-3.1.1.min.js"></script>
<script src="/admin/assets/js/bootstrap.min.js"></script>

Wyświetl plik

@ -7,7 +7,7 @@
// //
// The MIT License (MIT) //
// //
// Copyright (c) 2015-2016 Joseph A. Prochazka //
// Copyright (c) 2015 Joseph A. Prochazka //
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy //
// of this software and associated documentation files (the "Software"), to deal //
@ -154,6 +154,10 @@
if (isset($_POST['hideNavbarAndFooter']) && $_POST['hideNavbarAndFooter'] == "TRUE")
$hideNavbarAndFooter = TRUE;
$purgeOlderData = FALSE;
if (isset($_POST['purgeOlderData']) && $_POST['purgeOlderData'] == "TRUE")
$purgeOlderData = TRUE;
// Update settings using those supplied by the form.
$common->updateSetting("siteName", $_POST['siteName']);
$common->updateSetting("template", $_POST['template']);
@ -183,6 +187,8 @@
$common->updateSetting("enableWebNotifications", $enableWebNotifications);
$common->updateSetting("googleMapsApiKey", $_POST['googleMapsApiKey']);
$common->updateSetting("hideNavbarAndFooter", $hideNavbarAndFooter);
$common->updateSetting("purge_older_data", $purgeOlderData);
$common->updateSetting("days_to_save", $_POST['daysToSave']);
// Purge older flight positions.
if (isset($_POST['purgepositions'])) {
@ -223,7 +229,7 @@
}
$enableWebNotifications = $common->getSetting("enableWebNotifications");
// Get general settings from settings.xml.
// Get general settings.
$siteName = $common->getSetting("siteName");
$currentTemplate = $common->getSetting("template");
$defaultPage = $common->getSetting("defaultPage");
@ -231,7 +237,7 @@
$timeZone = $common->getSetting("timeZone");
$googleMapsApiKey = $common->getSetting("googleMapsApiKey");
// Get navigation settings from settings.xml.
// Get navigation settings.
$enableFlights = $common->getSetting("enableFlights");
$enableBlog = $common->getSetting("enableBlog");
$enableInfo = $common->getSetting("enableInfo");
@ -242,7 +248,7 @@
$enablePfclient = $common->getSetting("enablePfclient");
$hideNavbarAndFooter = $common->getSetting("hideNavbarAndFooter");
// Get aggregate site settings from settings.xml.
// Get aggregate site settings.
$enableFlightAwareLink = $common->getSetting("enableFlightAwareLink");
$flightAwareLogin = $common->getSetting("flightAwareLogin");
$flightAwareSite = $common->getSetting("flightAwareSite");
@ -252,14 +258,18 @@
$flightRadar24Id = $common->getSetting("flightRadar24Id");
$enableAdsbExchangeLink = $common->getSetting("enableAdsbExchangeLink");
// Get units of measurement setting from settings.xml.
// Get units of measurement settings.
$measurementRange = $common->getSetting("measurementRange");
$measurementTemperature = $common->getSetting("measurementTemperature");
$measurementBandwidth = $common->getSetting("measurementBandwidth");
// Get the network interface from settings.xml.
// Get the network interface settings.
$networkInterface = $common->getSetting("networkInterface");
// Get data purge settings.
$purgeOlderData = $common->getSetting("purge_older_data");
$daysToSave = $common->getSetting("days_to_save");
// Create an array of all directories in the template folder.
$templates = array();
$path = "../templates/";
@ -578,20 +588,15 @@
<div class="panel-heading">Purge Positions</div>
<div class="panel-body">
<p>Current Database Size: <?php echo $common->getDatabaseSize("mb"); ?>MB</p>
<div class="form-group">
<label for="purgepositionspicker">Purge flight positions old than...</label><br />
<input type="text" class="form-control" id="purgepositionspicker" name="purgepositionspicker" autocomplete="off" <?php ($settings::db_driver == "xml" ? print ' disabled' : ''); ?>>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="purgepositions" value="purge"<?php ($settings::db_driver == "xml" ? print ' disabled' : ''); ?>> Check to confirm purge of data.
<input type="checkbox" id="purgeOlderData" name="purgeOlderData" value="TRUE"<?php ($purgeOlderData == 1 ? print ' checked' : ''); ?><?php ($settings::db_driver == "xml" ? print ' disabled' : ''); ?>> Enable daily purges of older flight data.
</label>
</div>
<script type="text/javascript">
jQuery('#purgepositionspicker').datetimepicker({
inline:true
});
</script>
<div class="form-group">
<label for="daystosave"">Keep only data newer than X days.</label>
<input type="text" class="form-control" id="daysToSave" name="daysToSave" value="<?php echo $daysToSave; ?>"<?php ($settings::db_driver == "xml" ? print ' disabled' : ''); ?>>
</div>
</div>
</div>
</div>

Wyświetl plik

@ -1,33 +1,5 @@
<?php
/////////////////////////////////////////////////////////////////////////////////////
// ADS-B RECEIVER PORTAL //
// =============================================================================== //
// Copyright and Licensing Information: //
// //
// The MIT License (MIT) //
// //
// Copyright (c) 2015-2024 Joseph A. Prochazka //
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy //
// of this software and associated documentation files (the "Software"), to deal //
// in the Software without restriction, including without limitation the rights //
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //
// copies of the Software, and to permit persons to whom the Software is //
// furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in all //
// copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE //
// SOFTWARE. //
/////////////////////////////////////////////////////////////////////////////////////
class template {
// PUT THE TEMPLATE TOGETHER
@ -37,7 +9,7 @@
// Check if the portal is installed or needs upgraded.
$thisVersion = "2.8.3";
$thisVersion = "2.8.4";
if (!file_exists($_SERVER['DOCUMENT_ROOT']."/classes/settings.class.php")) {
header ("Location: /install/install.php");

Wyświetl plik

@ -7,7 +7,7 @@
// //
// The MIT License (MIT) //
// //
// Copyright (c) 2015-2016 Joseph A. Prochazka //
// Copyright (c) 2015 Joseph A. Prochazka //
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy //
// of this software and associated documentation files (the "Software"), to deal //
@ -62,7 +62,7 @@
}
$dbh = $common->pdoOpen();
$sql = "SELECT COUNT(*) FROM ".$settings::db_prefix."flights WHERE flight LIKE :like ORDER BY lastSeen DESC, flight";
$sql = "SELECT COUNT(*) FROM ".$settings::db_prefix."flights WHERE flight LIKE :like AND EXISTS (SELECT * FROM ".$settings::db_prefix."positions WHERE ".$settings::db_prefix."positions.flight = ".$settings::db_prefix."flights.id)";
$sth = $dbh->prepare($sql);
$sth->bindValue(':like', "%".$searchString."%", PDO::PARAM_STR);
$sth->execute();
@ -71,7 +71,7 @@
$dbh = NULL;
$dbh = $common->pdoOpen();
$sql = "SELECT * FROM ".$settings::db_prefix."flights WHERE flight LIKE :like ORDER BY lastSeen DESC, flight LIMIT :start, :items";
$sql = "SELECT * FROM ".$settings::db_prefix."flights WHERE flight LIKE :like AND EXISTS (SELECT * FROM ".$settings::db_prefix."positions WHERE ".$settings::db_prefix."positions.flight = ".$settings::db_prefix."flights.id) ORDER BY lastSeen DESC, flight LIMIT :start, :items";
$sth = $dbh->prepare($sql);
$sth->bindValue(':like', "%".$searchString."%", PDO::PARAM_STR);
$sth->bindValue(':start', $start, PDO::PARAM_INT);

Wyświetl plik

@ -7,7 +7,7 @@
// //
// The MIT License (MIT) //
// //
// Copyright (c) 2015-2024 Joseph A. Prochazka //
// Copyright (c) 2015 Joseph A. Prochazka //
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy //
// of this software and associated documentation files (the "Software"), to deal //
@ -29,7 +29,7 @@
/////////////////////////////////////////////////////////////////////////////////////
// The most current stable release.
$thisVersion = "2.8.3";
$thisVersion = "2.8.4";
// Begin the upgrade process if this release is newer than what is installed.
if (file_exists($_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR."classes".DIRECTORY_SEPARATOR."settings.class.php")) {
@ -233,7 +233,7 @@ EOF;
flight VARCHAR(10) NOT NULL);';
$positionsSql = 'CREATE TABLE '.$dbPrefix.'positions (
id INT(11) AUTO_INCREMENT PRIMARY KEY,
flight BIGINT NOT NULL,
flight BIGINT NULL,
aircraft BIGINT NOT NULL,
time datetime NOT NULL,
message INT NOT NULL,
@ -443,7 +443,8 @@ EOF;
$common->addSetting('enableWebNotifications', FALSE);
$common->addSetting('googleMapsApiKey', '');
$common->addSetting("hideNavbarAndFooter", FALSE);
$common->addSetting("purgeAircraft", FALSE);
$common->addSetting("purge_older_data", FALSE);
$common->addSetting("days_to_save", "30");
$common->addSetting("advancedMapCenterLatitude", "41.3683798");
$common->addSetting("advancedMapCenterLongitude", "-82.1076486");

Wyświetl plik

@ -48,7 +48,7 @@
try {
// Update the version and patch settings..
// Update the version and patch settings.
$common->updateSetting("version", "2.8.3");
$common->updateSetting("patch", "");

Wyświetl plik

@ -0,0 +1,83 @@
<?php
/////////////////////////////////////////////////////////////////////////////////////
// ADS-B RECEIVER PORTAL //
// =============================================================================== //
// Copyright and Licensing Information: //
// //
// The MIT License (MIT) //
// //
// Copyright (c) 2015 Joseph A. Prochazka //
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy //
// of this software and associated documentation files (the "Software"), to deal //
// in the Software without restriction, including without limitation the rights //
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //
// copies of the Software, and to permit persons to whom the Software is //
// furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in all //
// copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE //
// SOFTWARE. //
/////////////////////////////////////////////////////////////////////////////////////
///////////////////////
// UPGRADE TO V2.8.4
///////////////////////
// --------------------------------------------------------
// Updates the version setting to 2.8.4.
// --------------------------------------------------------
$results = upgrade();
exit(json_encode($results));
function upgrade() {
require_once($_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR."classes".DIRECTORY_SEPARATOR."common.class.php");
require_once($_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR."classes".DIRECTORY_SEPARATOR."settings.class.php");
$common = new common();
$settings = new settings();
try {
// Update the version and patch settings..
$common->updateSetting("version", "2.8.4");
$common->updateSetting("patch", "");
// Allow NULL flights in the positions table.
$dbh = $common->pdoOpen();
$sql = "ALTER TABLE ".$settings::db_prefix."positions MODIFY flight BIGINT NULL";
$sth = $dbh->prepare($sql);
$sth->execute();
$sth = NULL;
// Rename purgeAircraft to purge_older_data.
$purge_older_data = $common->getSetting('purgeAircraft');
$common->deleteSetting('purgeAircraft');
$common->addSetting("purge_older_data", $purge_older_data);
// Add days to save setting.
$common->addSetting("days_to_save", "30");
// The upgrade process completed successfully.
$results['success'] = TRUE;
$results['message'] = "Upgrade to v2.8.4 successful.";
return $results;
} catch(Exception $e) {
// Something went wrong during this upgrade process.
$results['success'] = FALSE;
$results['message'] = $e->getMessage();
return $results;
}
}
?>

Wyświetl plik

@ -7,7 +7,7 @@
// //
// The MIT License (MIT) //
// //
// Copyright (c) 2015-2024 Joseph A. Prochazka //
// Copyright (c) 2015 Joseph A. Prochazka //
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy //
// of this software and associated documentation files (the "Software"), to deal //
@ -33,7 +33,7 @@
$common = new common();
// The most current stable release.
$thisVersion = "2.8.3";
$thisVersion = "2.8.4";
// Begin the upgrade process if this release is newer than what is installed.
if ($common->getSetting("version") == $thisVersion) {
@ -213,6 +213,15 @@
$version = "2.8.3";
}
// UPGRADE TO V2.8.4
if ($common->getSetting("version") == "2.8.3" && $success) {
$json = file_get_contents("http://localhost/install/upgrade-v2.8.4.php");
$results = json_decode($json, TRUE);
$success = $results['success'];
$message = $results['message'];
$version = "2.8.4";
}
require_once($_SERVER['DOCUMENT_ROOT'].DIRECTORY_SEPARATOR."admin".DIRECTORY_SEPARATOR."includes".DIRECTORY_SEPARATOR."header.inc.php");
// Display the instalation wizard.

Wyświetl plik

@ -1,33 +1,4 @@
<?php
/////////////////////////////////////////////////////////////////////////////////////
// ADS-B RECEIVER PORTAL //
// =============================================================================== //
// Copyright and Licensing Information: //
// //
// The MIT License (MIT) //
// //
// Copyright (c) 2015-2016 Joseph A. Prochazka //
// //
// Permission is hereby granted, free of charge, to any person obtaining a copy //
// of this software and associated documentation files (the "Software"), to deal //
// in the Software without restriction, including without limitation the rights //
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell //
// copies of the Software, and to permit persons to whom the Software is //
// furnished to do so, subject to the following conditions: //
// //
// The above copyright notice and this permission notice shall be included in all //
// copies or substantial portions of the Software. //
// //
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR //
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, //
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE //
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER //
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, //
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE //
// SOFTWARE. //
/////////////////////////////////////////////////////////////////////////////////////
// Start session
session_start();
@ -47,7 +18,7 @@
// Add position data to the $pageData array.
$dbh = $common->pdoOpen();
$sql = "SELECT id FROM ".$settings::db_prefix."flights WHERE flight = :flight";
$sql = "SELECT id, aircraft, flight, firstSeen, lastSeen FROM ".$settings::db_prefix."flights WHERE flight = :flight";
$sth = $dbh->prepare($sql);
$sth->bindParam(':flight', $_GET['flight'], PDO::PARAM_STR, 50);
$sth->execute();
@ -55,6 +26,10 @@
$sth = NULL;
$dbh = NULL;
$flightId = $row['id'];
$aircraftId = $row['aircraft'];
$pageData['flight'] = $row['flight'];
$pageData['flightFirstSeen'] = $row['firstSeen'];
$pageData['flightLastSeen'] = $row['lastSeen'];
$dbh = $common->pdoOpen();
$sql = "SELECT * FROM ".$settings::db_prefix."positions WHERE flight = :flight ORDER BY time";
@ -156,13 +131,36 @@
}
break;
}
}
}
$pageData['flightPaths'] = $selectedFlightPath;
} else {
$pageData['flightPathsAvailable'] = "FALSE";
}
// Page Data
$dbh = $common->pdoOpen();
$sql = "SELECT icao, firstSeen, lastSeen FROM ".$settings::db_prefix."aircraft WHERE id = :id";
$sth = $dbh->prepare($sql);
$sth->bindParam(':id', $aircraftId, PDO::PARAM_STR, 50);
$sth->execute();
$row = $sth->fetch();
$sth = NULL;
$dbh = NULL;
$pageData['icao'] = $row['icao'];
$pageData['aircraftFirstSeen'] = $row['firstSeen'];
$pageData['aircraftLastSeen'] = $row['lastSeen'];
// Planespotter.net image.
$url = 'https://api.planespotters.net/pub/photos/hex/'.$pageData['icao'];
$json = file_get_contents($url);
$planspotterData = json_decode($json);
$pageData['thumbnailSrc'] = $planspotterData->photos[0]->thumbnail->src;
$pageData['thumbnailWidth'] = $planspotterData->photos[0]->thumbnail->size->width;
$pageData['thumbnailHeight'] = $planspotterData->photos[0]->thumbnail->size->height;
$pageData['thumbnailPhotographer'] = $planspotterData->photos[0]->photographer;
$pageData['thumbnailLink'] = $planspotterData->photos[0]->link;
$template->display($pageData);
?>

Wyświetl plik

@ -1,24 +1,3 @@
{*
////////////////////////////////////////////////////////////////////////////////
// ADS-B RECEIVER PORTAL TEMPLATE INFORMATION //
// ========================================================================== //
// Template Set: default //
// Template Name: dump1090.tpl //
// Version: 2.0.0 //
// Release Date: //
// Author: Joe Prochazka //
// Website: https://www.swiftbyte.com //
// ========================================================================== //
// Copyright and Licensing Information: //
// //
// Copyright (c) 2015-2016 Joseph A. Prochazka //
// //
// This template set is licensed under The MIT License (MIT) //
// A copy of the license can be found package along with these files. //
////////////////////////////////////////////////////////////////////////////////
*}
{area:head}
<link rel="stylesheet" href="templates/{setting:template}/assets/css/dump1090.css">
<style>
@ -61,17 +40,19 @@
<div class="sidebar left">
<h3>Flight Data</h3>
<a href="{page:thumbnailLink}" target="_blank"><img src="{page:thumbnailSrc}" width="{page:thumbnailWidth}" height="{page:thumbnailHeight}"></a>
<span>image by {page:thumbnailPhotographer}</span>
<p>
<div><strong>ICAO: <span id="icao"></span></strong></div>
<div><strong>Flight Number: <span id="flight"></span></strong></div>
<div><strong>ICAO: <span id="icao">{page:icao}</span></strong></div>
<div><strong>Flight: <span id="flight">{page:flight}</span></strong></div>
</p>
<p>
<div>Aircraft First Seen: <span id="afs"></span></div>
<div>Aircraft Last Seen: <span id="als"></span></div>
<div>Aircraft First Seen: <span id="afs">{page:aircraftFirstSeen}</span></div>
<div>Aircraft Last Seen: <span id="als">{page:aircraftLastSeen}</span></div>
</p>
<p>
<div>Flight First Seen: <span id="ffs"></span></div>
<div>Flight Last Seen: <span id="fls"></span></div>
<div>Flight First Seen: <span id="ffs">{page:flightFirstSeen}</span></div>
<div>Flight Last Seen: <span id="fls">{page:flightLastSeen}</span></div>
</p>
</div>
@ -302,8 +283,8 @@
var i,x,y,ARRcookies=document.cookie.split(";");
for (i=0;i<ARRcookies.length;i++)
{
x=ARRcookies[i].substr(0,ARRcookies[i].indexOf("="));
y=ARRcookies[i].substr(ARRcookies[i].indexOf("=")+1);
x=ARRcookies[i].substr(0,ARRcookies[i].toString().indexOf("="));
y=ARRcookies[i].substr(ARRcookies[i].toString().indexOf("=")+1);
x=x.replace(/^\s+|\s+$/g,"");
if (x==c_name)
{

Wyświetl plik

@ -1,211 +1,234 @@
#!/usr/bin/python
#================================================================================#
# ADS-B FEEDER PORTAL #
# ------------------------------------------------------------------------------ #
# Copyright and Licensing Information: #
# #
# The MIT License (MIT) #
# #
# Copyright (c) 2015-2024 Joseph A. Prochazka #
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy #
# of this software and associated documentation files (the "Software"), to deal #
# in the Software without restriction, including without limitation the rights #
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
# copies of the Software, and to permit persons to whom the Software is #
# furnished to do so, subject to the following conditions: #
# #
# The above copyright notice and this permission notice shall be included in all #
# copies or substantial portions of the Software. #
# #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #
# SOFTWARE. #
#================================================================================#
# WHAT THIS DOES:
# ---------------------------------------------------------------
#
# 1) Read aircraft.json generated by dump1090-fa.
# 2) Add the flight to the database if it does not already exist.
# 3) Update the last time the flight was seen.
import datetime
import fcntl
import json
import logging
import MySQLdb
import os
import time
import sqlite3
from datetime import datetime
from time import sleep
from urllib.request import urlopen
def log(string):
#print(string) # uncomment to enable debug logging
return
class AircraftProcessor(object):
# Do not allow another instance of the script to run.
lock_file = open('/tmp/flights.py.lock','w')
# Log infromation to console
def log(self, string):
#print(f'[{datetime.now().strftime("%Y/%m/%d %H:%M:%S")}] {string}') # uncomment to enable debug logging
return
try:
fcntl.flock(lock_file, fcntl.LOCK_EX|fcntl.LOCK_NB)
except (IOError, OSError):
log('another instance already running')
quit()
# Create database connection
def create_connection(self):
self.log("Setting up database connection")
with open(os.path.dirname(os.path.realpath(__file__)) + '/config.json') as config_file:
config = json.load(config_file)
lock_file.write('%d\n'%os.getpid())
lock_file.flush()
match config["database"]["type"].lower():
case 'mysql':
return MySQLdb.connect(
host=config["database"]["host"],
user=config["database"]["user"],
passwd=config["database"]["passwd"],
db=config["database"]["db"]
)
case 'sqlite':
return sqlite3.connect(config["database"]["db"])
# Read the configuration file.
with open(os.path.dirname(os.path.realpath(__file__)) + '/config.json') as config_file:
config = json.load(config_file)
# Import the needed database library.
if config["database"]["type"] == "mysql":
import MySQLdb
else:
import sqlite3
class FlightsProcessor(object):
def __init__(self, config):
self.config = config
self.dbType = config["database"]["type"]
# List of required keys for position data entries
self.position_keys = ('lat', 'lon', 'nav_altitude', 'gs', 'track', 'geom_rate', 'hex')
def setupDBStatements(self, formatSymbol):
if hasattr(self, 'STMTS'):
# Read JSON supplied by dump1090
def read_json(self):
self.log("Reading aircraft.json")
try:
raw_json = urlopen('http://127.0.0.1/dump1090/data/aircraft.json')
json_object = json.load(raw_json)
return json_object
except:
logging.error("There was a problem consuming aircraft.json")
return
mapping = { "s": formatSymbol }
self.STMTS = {
'select_aircraft_count':"SELECT COUNT(*) FROM adsb_aircraft WHERE icao = %(s)s" % mapping,
'select_aircraft_id': "SELECT id FROM adsb_aircraft WHERE icao = %(s)s" % mapping,
'select_flight_count': "SELECT COUNT(*) FROM adsb_flights WHERE flight = %(s)s" % mapping,
'select_flight_id': "SELECT id FROM adsb_flights WHERE flight = %(s)s" % mapping,
'select_position': "SELECT message FROM adsb_positions WHERE flight = %(s)s AND message = %(s)s ORDER BY time DESC LIMIT 1" % mapping,
'insert_aircraft': "INSERT INTO adsb_aircraft (icao, firstSeen, lastSeen) VALUES (%(s)s, %(s)s, %(s)s)" % mapping,
'insert_flight': "INSERT INTO adsb_flights (aircraft, flight, firstSeen, lastSeen) VALUES (%(s)s, %(s)s, %(s)s, %(s)s)" % mapping,
'insert_position_sqwk': "INSERT INTO adsb_positions (flight, time, message, squawk, latitude, longitude, track, altitude, verticleRate, speed, aircraft) VALUES (%(s)s, %(s)s, %(s)s, %(s)s, %(s)s, %(s)s, %(s)s, %(s)s, %(s)s, %(s)s, %(s)s)" % mapping,
'insert_position': "INSERT INTO adsb_positions (flight, time, message, latitude, longitude, track, altitude, verticleRate, speed, aircraft) VALUES (%(s)s, %(s)s, %(s)s, %(s)s, %(s)s, %(s)s, %(s)s, %(s)s, %(s)s, %(s)s)" % mapping,
'update_aircraft_seen': "UPDATE adsb_aircraft SET lastSeen = %(s)s WHERE icao = %(s)s" % mapping,
'update_flight_seen': "UPDATE adsb_flights SET aircraft = %(s)s, lastSeen = %(s)s WHERE flight = %(s)s" % mapping
}
def connectDB(self):
if self.dbType == "sqlite": ## Connect to a SQLite database.
self.setupDBStatements("?")
return sqlite3.connect(self.config["database"]["db"])
else: ## Connect to a MySQL database.
self.setupDBStatements("%s")
return MySQLdb.connect(host=self.config["database"]["host"],
user=self.config["database"]["user"],
passwd=self.config["database"]["passwd"],
db=self.config["database"]["db"])
# Begin processing data retrived from dump1090
def process_all_aircraft(self):
data = self.read_json()
aircraft_data = data["aircraft"]
def processAircraftList(self, aircraftList):
db = self.connectDB()
# Get Database cursor handle
self.cursor = db.cursor()
# Assign the time to a variable.
self.time_now = datetime.datetime.utcnow().strftime("%Y/%m/%d %H:%M:%S")
if len(aircraft_data) == 0:
self.log(f'There is no aircraft data to process at this time')
return
for aircraft in aircraftList:
self.processAircraft(aircraft)
self.log(f'Begining to proocess {len(aircraft_data)} aircraft')
for aircraft in aircraft_data:
self.process_aircraft(aircraft)
# Close the database connection.
db.commit()
db.close()
connection.close()
def processAircraft(self, aircraft):
hexcode = aircraft["hex"]
# Check if this aircraft was already seen.
self.cursor.execute(self.STMTS['select_aircraft_count'], (hexcode,))
row_count = self.cursor.fetchone()
if row_count[0] == 0:
# Insert the new aircraft.
log("Added Aircraft: " + hexcode)
self.cursor.execute(self.STMTS['insert_aircraft'], (hexcode, self.time_now, self.time_now,))
return
# Process the aircraft
def process_aircraft(self, aircraft):
tracked=False
aircraft_id=None
try:
cursor.execute("SELECT COUNT(*) FROM adsb_aircraft WHERE icao = %s", (aircraft["hex"],))
if cursor.fetchone()[0] > 0:
tracked=True
except Exception as ex:
logging.error(f'Error encountered while checking if aircraft {aircraft["hex"]} has already been added', exc_info=ex)
return
if tracked:
self.log(f'Updating aircraft ICAO {aircraft["hex"]}')
try:
cursor.execute(
"UPDATE adsb_aircraft SET lastSeen = %s WHERE icao = %s",
(now, aircraft["hex"])
)
connection.commit()
cursor.execute(
"SELECT id FROM adsb_aircraft WHERE icao = %s",
(aircraft["hex"],)
)
aircraft_id = cursor.fetchone()[0]
except Exception as ex:
logging.error(f'Error encountered while trying to update aircraft {aircraft["hex"]}', exc_info=ex)
return
else:
# Update the existing aircraft.
self.cursor.execute(self.STMTS['update_aircraft_seen'], (self.time_now, hexcode,))
log("Updating Aircraft: " + hexcode)
# Get the ID of this aircraft.
self.cursor.execute(self.STMTS['select_aircraft_id'], (hexcode,))
row = self.cursor.fetchone()
aircraft_id = row[0]
log("\tFound Aircraft ID: " + str(aircraft_id))
self.log(f'Inserting aircraft ICAO {aircraft["hex"]}')
try:
cursor.execute(
"INSERT INTO adsb_aircraft (icao, firstSeen, lastSeen) VALUES (%s, %s, %s)",
(aircraft["hex"], now, now)
)
connection.commit()
aircraft_id = cursor.lastrowid
except Exception as ex:
logging.error(f'Error encountered while trying to insert aircraft {aircraft["hex"]}', exc_info=ex)
return
# Check that a flight is tied to this track.
if 'flight' in aircraft:
self.processFlight(aircraft_id, aircraft)
def processFlight(self, aircraft_id, aircraft):
flight = aircraft["flight"].strip()
# Check to see if the flight already exists in the database.
self.cursor.execute(self.STMTS['select_flight_count'], (flight,))
row_count = self.cursor.fetchone()
if row_count[0] == 0:
# If the flight does not exist in the database add it.
params = (aircraft_id, flight, self.time_now, self.time_now,)
self.cursor.execute(self.STMTS['insert_flight'], params)
log("\t\tAdded Flight: " + flight)
if 'flight' in aircraft:
self.process_flight(aircraft_id, aircraft)
else:
# If it already exists pdate the time it was last seen.
params = (aircraft_id, self.time_now, flight,)
self.cursor.execute(self.STMTS['update_flight_seen'], params)
log("\t\tUpdated Flight: " + flight)
# Get the ID of this flight.
self.cursor.execute(self.STMTS['select_flight_id'], (flight,))
row = self.cursor.fetchone()
flight_id = row[0]
self.process_positions(aircraft_id , None, aircraft)
# Check if position data is available.
if (all (k in aircraft for k in self.position_keys) and aircraft["altitude"] != "ground"):
self.processPositions(flight_id, aircraft)
return
def processPositions(self, flight_id, aircraft):
# Get the ID of this aircraft.
hexcode = aircraft["hex"]
self.cursor.execute(self.STMTS['select_aircraft_id'], (hexcode,))
row = self.cursor.fetchone()
aircraft_id = row[0]
# Process the flight
def process_flight(self, aircraft_id, aircraft):
if 'flight' in aircraft:
flight = aircraft["flight"].strip()
# Check that this message has not already been added to the database.
params = (flight_id, aircraft["messages"],)
self.cursor.execute(self.STMTS['select_position'], params)
row = self.cursor.fetchone()
tracked=False
try:
cursor.execute("SELECT COUNT(*) FROM adsb_flights WHERE flight = %s", (flight,))
if cursor.fetchone()[0] > 0:
tracked=True
except Exception as ex:
logging.error(f'Error encountered while checking if flight {flight} has already been added', exc_info=ex)
return
if row == None or row[0] != aircraft["messages"]:
# Add this position to the database.
if 'squawk' in aircraft:
params = (flight_id, self.time_now, aircraft["messages"], aircraft["squawk"],
aircraft["lat"], aircraft["lon"], aircraft["track"],
aircraft["nav_altitude"], aircraft["geom_rate"], aircraft["gs"], aircraft_id,)
self.cursor.execute(self.STMTS['insert_position_sqwk'], params)
log("\t\t\tInserted position w/ Squawk " + repr(params))
if tracked:
self.log(f' Updating flight {flight} assigned to aircraft ICAO {aircraft["hex"]}')
try:
cursor.execute(
"UPDATE adsb_flights SET lastSeen = %s WHERE flight = %s",
(now, flight)
)
connection.commit()
cursor.execute(
"SELECT id FROM adsb_flights WHERE flight = %s",
(flight,)
)
flight_id = cursor.fetchone()[0]
except Exception as ex:
logging.error(f'Error encountered while trying to update flight {flight}', exc_info=ex)
return
else:
params = (flight_id, self.time_now, aircraft["messages"], aircraft["lat"], aircraft["lon"],
aircraft["track"], aircraft["nav_altitude"], aircraft["geom_rate"], aircraft["gs"], aircraft_id,)
self.cursor.execute(self.STMTS['insert_position'], params)
log("\t\t\tInserted position w/o Squawk " + repr(params))
else:
log("\t\t\tMessage is the same")
self.log(f'Inserting flight {flight} assigned to aircraft ICAO {aircraft["hex"]}')
try:
cursor.execute(
"INSERT INTO adsb_flights (aircraft, flight, firstSeen, lastSeen) VALUES (%s, %s, %s, %s)",
(aircraft_id, flight, now, now)
)
connection.commit()
flight_id = cursor.lastrowid
except Exception as ex:
logging.error(f'Error encountered while trying to insert flight {flight}', exc_info=ex)
return
else:
self.log(f' Aircraft ICAO {aircraft["hex"]} was not assigned a flight')
self.process_positions(aircraft_id, flight_id, aircraft)
return
# Process positions
def process_positions(self, aircraft_id , flight_id, aircraft):
position_keys = ('lat', 'lon', 'alt_baro', 'gs', 'track', 'geom_rate', 'hex')
if (all(key in aircraft for key in position_keys)):
tracked=False
try:
cursor.execute("SELECT COUNT(*) FROM adsb_positions WHERE flight = %s AND message = %s", (flight_id, aircraft["messages"]))
if cursor.fetchone()[0] > 0:
tracked=True
except Exception as ex:
logging.error(f'Error encountered while checking if position has already been added for message ID {aircraft["messages"]} related to flight {flight_id}', exc_info=ex)
return
if tracked:
return
squawk = None
if 'squawk' in aircraft:
squawk = aircraft["squawk"]
altitude = aircraft["alt_baro"]
if 'alt_geom' in aircraft:
altitude = aircraft["alt_geom"]
try:
if flight_id is None:
self.log(f' Inserting position for aircraft ICAO {aircraft["hex"]}')
else:
self.log(f' Inserting position for aircraft ICAO {aircraft["hex"]} assigned flight {flight_id}')
cursor.execute(
"INSERT INTO adsb_positions (flight, time, message, squawk, latitude, longitude, track, altitude, verticleRate, speed, aircraft) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)",
(flight_id, now, aircraft["messages"], squawk, aircraft["lat"], aircraft["lon"], aircraft["track"], altitude, aircraft["geom_rate"], aircraft["gs"], aircraft_id)
)
connection.commit()
except Exception as ex:
logging.error(f'Error encountered while inserting position data for message ID {aircraft["messages"]} related to flight {flight_id}', exc_info=ex)
return
else:
self.log(f' Data required to insert position data for Aircraft ICAO {aircraft["hex"]} is not present')
return
if __name__ == "__main__":
processor = FlightsProcessor(config)
processor = AircraftProcessor()
processor.log("-- CHECKING IF FLIGHT RECORDER JOB IS ALREADY RUNNING")
# Do not allow another instance of the job to run
lock_file = open('/tmp/flights.py.lock','w')
try:
fcntl.flock(lock_file, fcntl.LOCK_EX|fcntl.LOCK_NB)
except (IOError, OSError):
processor.log("-- ANOTHER INSTANCE OF THIS JOB IS RUNNING")
quit()
lock_file.write('%d\n'%os.getpid())
# Main run loop
while True:
# Read dump1090 aircraft.json.
response = urlopen('http://localhost/dump1090/data/aircraft.json')
data = json.load(response)
processor.log("-- BEGINING FLIGHT RECORDER JOB")
processor.processAircraftList(data["aircraft"])
log("Last Run: " + datetime.datetime.now().strftime("%Y/%m/%d %H:%M:%S"))
time.sleep(15)
# Set up database connection
connection = processor.create_connection()
cursor = connection.cursor()
# Begin flight recording job
now = datetime.now()
processor.process_all_aircraft()
processor.log("-- FLIGHT RECORD JOB COMPLETE")
processor.log("SLEEPING 15 SECONDS BEFORE NEXT RUN")
sleep(15)

Wyświetl plik

@ -1,167 +1,173 @@
#!/usr/bin/python
#================================================================================#
# ADS-B FEEDER PORTAL #
# ------------------------------------------------------------------------------ #
# Copyright and Licensing Information: #
# #
# The MIT License (MIT) #
# #
# Copyright (c) 2015-2016 Joseph A. Prochazka #
# #
# Permission is hereby granted, free of charge, to any person obtaining a copy #
# of this software and associated documentation files (the "Software"), to deal #
# in the Software without restriction, including without limitation the rights #
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell #
# copies of the Software, and to permit persons to whom the Software is #
# furnished to do so, subject to the following conditions: #
# #
# The above copyright notice and this permission notice shall be included in all #
# copies or substantial portions of the Software. #
# #
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR #
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, #
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE #
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER #
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, #
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE #
# SOFTWARE. #
#================================================================================#
import datetime
import fcntl
import json
import logging
import MySQLdb
import os
import sqlite3
import time
# Do not allow another instance of the script to run.
lock_file = open('/tmp/flights.py.lock','w')
from datetime import datetime, timedelta
try:
fcntl.flock(lock_file, fcntl.LOCK_EX|fcntl.LOCK_NB)
except (IOError, OSError):
quit()
class MaintenanceProcessor(object):
lock_file.write('%d\n'%os.getpid())
lock_file.flush()
# Log infromation to console
def log(self, string):
print(f'[{datetime.now().strftime("%Y/%m/%d %H:%M:%S")}] {string}') # uncomment to enable debug logging
return
while True:
# Create database connection
def create_connection(self):
self.log("Setting up database connection")
with open(os.path.dirname(os.path.realpath(__file__)) + '/config.json') as config_file:
config = json.load(config_file)
## Read the configuration file.
with open(os.path.dirname(os.path.realpath(__file__)) + '/config.json') as config_file:
config = json.load(config_file)
match config["database"]["type"].lower():
case 'mysql':
return MySQLdb.connect(
host=config["database"]["host"],
user=config["database"]["user"],
passwd=config["database"]["passwd"],
db=config["database"]["db"]
)
case 'sqlite':
return sqlite3.connect(config["database"]["db"])
## Import the needed database library and set up database connection.
if config["database"]["type"] == "mysql":
import MySQLdb
db = MySQLdb.connect(host=config["database"]["host"], user=config["database"]["user"], passwd=config["database"]["passwd"], db=config["database"]["db"])
# Begin maintenance
def begin_maintenance(self):
self.log("Getting maintenance settings from the database")
purge_old_aircraft = False
try:
cursor.execute("SELECT value FROM adsb_settings WHERE name = 'purge_older_data'")
result = cursor.fetchone()[0]
purge_old_aircraft = result.lower() in ['true', '1']
except Exception as ex:
logging.error(f"Error encountered while getting value for setting purge_older_data", exc_info=ex)
return
if config["database"]["type"] == "sqlite":
import sqlite3
db = sqlite3.connect(config["database"]["db"])
if purge_old_aircraft:
cutoff_date = datetime.now() - timedelta(years = 20)
try:
cursor.execute("SELECT value FROM adsb_settings WHERE name = 'days_to_save'")
days_to_save = cursor.fetchone()[0]
except Exception as ex:
logging.error(f"Error encountered while getting value for setting days_to_save", exc_info=ex)
return
cutoff_date = datetime.now() - timedelta(days = days_to_save)
cursor = db.cursor()
else:
self.log("Maintenance is disabled")
## Get maintenance settings.
connection.commit()
purge_aircraft = False
# MySQL and SQLite
cursor.execute("SELECT value FROM adsb_settings WHERE name = 'purgeAircraft'")
row = cursor.fetchone()
if row:
purge_aircraft = row
connection.close()
purge_flights = False
# MySQL and SQLite
cursor.execute("SELECT value FROM adsb_settings WHERE name = 'purgeFlights'")
row = cursor.fetchone()
if row:
purge_flights = row
return
purge_positions = False
# MySQL and SQLite
cursor.execute("SELECT value FROM adsb_settings WHERE name = 'purgePositions'")
row = cursor.fetchone()
if row:
purge_positions = row
# Remove aircraft not seen since the specified date
def purge_aircraft(self, cutoff_date):
try:
cursor.execute("SELECT id FROM adsb_aircraft WHERE lastSeen < %s", (cutoff_date,))
aircraft_ids = cursor.fetchall()
except Exception as ex:
logging.error(f"Error encountered while getting aircraft IDs not seen since {cutoff_date}", exc_info=ex)
return
purge_days_old = False
# MySQL and SQLite
cursor.execute("SELECT value FROM adsb_settings WHERE name = 'purgeDaysOld'")
row = cursor.fetchone()
if row:
purge_days_old = row
if len(aircraft_ids) > 0:
id = tuple(aircraft_ids)
aircraft_id_params = {'id': id}
## Create the purge date from the age specified.
try:
cursor.execute("DELETE FROM adsb_aircraft WHERE id IN %(t)s", aircraft_id_params)
except Exception as ex:
logging.error(f"Error deleting aircraft not seen since {cutoff_date}", exc_info=ex)
return
if purge_days_old:
purge_datetime = datetime.datetime.utcnow() - timedelta(days=purge_days_old)
purge_date = purge_datetime.strftime("%Y/%m/%d %H:%M:%S")
else:
purge_datetime = None
purge_date = None
self.purge_flights_related_to_aircraft(aircraft_id_params, cutoff_date)
self.purge_positions_related_to_aircraft(aircraft_id_params, cutoff_date)
## Remove aircraft not seen since the specified date.
return
if purge_aircraft and purge_date:
# MySQL
if config["database"]["type"] == "mysql":
cursor.execute("SELECT id FROM adsb_aircraft WHERE lastSeen < %s", purge_date)
rows = cursor.fetchall()
for row in rows:
cursor.execute("DELETE FROM adsb_positions WHERE aircraft = %s", row[0])
cursor.execute("DELETE FROM adsb_flights WHERE aircraft = %s", row[0])
cursor.execute("DELETE FROM adsb_aircraft WHERE id = %s", row[0])
# Remove flights related to aircraft not seen since the specified date
def purge_flights_related_to_aircraft(self, aircraft_id_params, cutoff_date):
try:
cursor.execute("DELETE FROM adsb_flights WHERE aircraft = %(t)s", aircraft_id_params)
except Exception as ex:
logging.error(f"Error deleting flights related to aircraft not seen since {cutoff_date}", exc_info=ex)
return
# SQLite
if config["database"]["type"] == "sqlite":
params = (purge_date,)
cursor.execute("SELECT id FROM adsb_aircraft WHERE lastSeen < ?", params)
rows = cursor.fetchall()
for row in rows:
params = (row[0],)
cursor.execute("DELETE FROM adsb_positions WHERE aircraft = ?", params)
cursor.execute("DELETE FROM adsb_flights WHERE aircraft = ?", params)
cursor.execute("DELETE FROM adsb_aircraft WHERE id = ?", params)
return
## Remove flights not seen since the specified date.
# Remove positions related to aircraft not seen since the specified date
def purge_positions_related_to_aircraft(self, aircraft_id_params, cutoff_date):
try:
cursor.execute("DELETE FROM adsb_positions WHERE aircraft = %(t)s", aircraft_id_params)
except Exception as ex:
logging.error(f"Error deleting positions related to aircraft not seen since {cutoff_date}", exc_info=ex)
return
if purge_flights and purge_date:
# MySQL
if config["database"]["type"] == "mysql":
cursor.execute("SELECT id FROM adsb_flights WHERE lastSeen < %s", purge_date)
rows = cursor.fetchall()
for row in rows:
cursor.execute("DELETE FROM adsb_positions WHERE flight = %s", row[0])
cursor.execute("DELETE FROM adsb_flights WHERE id = %s", row[0])
return
#SQLite
if config["database"]["type"] == "sqlite":
params = (purge_date,)
cursor.execute("SELECT id FROM adsb_flights WHERE lastSeen < ?", params)
rows = cursor.fetchall()
for row in rows:
params = (row[0],)
cursor.execute("DELETE FROM adsb_positions WHERE flight = ?", params)
cursor.execute("DELETE FROM adsb_flights WHERE id = ?", params)
# Remove positions older than the specified date
def purge_flights(self, cutoff_date):
try:
cursor.execute("SELECT id FROM adsb_flights WHERE lastSeen < %s", (cutoff_date,))
flight_ids = cursor.fetchall()
except Exception as ex:
logging.error(f"Error encountered while getting aircraft IDs not seen since {cutoff_date}", exc_info=ex)
return
## Remove positions older than the specified date.
if len(flight_ids) > 0:
id = tuple(flight_ids)
flight_id_params = {'id': id}
if purge_positions and purge_date:
# MySQL
if config["database"]["type"] == "mysql":
cursor.execute("DELETE FROM adsb_positions WHERE time < %s", purge_date)
try:
cursor.execute("DELETE FROM adsb_flights WHERE id IN %(t)s", flight_id_params)
except Exception as ex:
logging.error(f"Error deleting flights older than the cut off date of {cutoff_date}", exc_info=ex)
return
#SQLite
if config["database"]["type"] == "sqlite":
params = (purge_date,)
cursor.execute("DELETE FROM adsb_positions WHERE time < ?", params)
self.purge_positions_related_to_flights(flight_id_params, cutoff_date)
## Close the database connection.
return
db.commit()
db.close()
# Remove positions related to aircraft not seen since the specified date
def purge_positions_related_to_flights(self, flight_id_params, cutoff_date):
try:
cursor.execute("DELETE FROM adsb_positions WHERE flight = %(t)s", flight_id_params)
except Exception as ex:
logging.error(f"Error deleting positions related to flights not seen since {cutoff_date}", exc_info=ex)
return
## Sleep until the next run.
return
time.sleep(3600)
# Remove positions older than the specified date
def purge_positions(self, cutoff_date):
try:
cursor.execute("DELETE FROM adsb_positions WHERE time < %s", (cutoff_date,))
except Exception as ex:
logging.error(f"Error deleting positions older than the cut off date of {cutoff_date}", exc_info=ex)
return
return
if __name__ == "__main__":
processor = MaintenanceProcessor()
processor.log("-- BEGINING PORTAL MAINTENANCE JOB")
# Do not allow another instance of the job to run
lock_file = open('/tmp/maintenance.py.lock','w')
try:
fcntl.flock(lock_file, fcntl.LOCK_EX|fcntl.LOCK_NB)
except (IOError, OSError):
processor.log("-- ANOTHER INSTANCE OF THIS JOB IS RUNNING")
quit()
# Set up database connection
connection = processor.create_connection()
cursor = connection.cursor()
# Begin maintenance job
lock_file.write('%d\n'%os.getpid())
processor.begin_maintenance()
processor.log("-- PORTAL MAINTENANCE JOB COMPLETE")