kopia lustrzana https://github.com/jprochazka/adsb-receiver
Merge pull request #586 from jprochazka/jobs
v2.8.4 (Should be back to where we were now.)pull/589/head v2.8.4
commit
1792d3ee02
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -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:
|
||||
|
|
63
CREDITS.md
63
CREDITS.md
|
@ -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
|
||||
|
|
54
README.md
54
README.md
|
@ -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)
|
||||
|
|
|
@ -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
|
29
bash/main.sh
29
bash/main.sh
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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", "");
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
?>
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
Ładowanie…
Reference in New Issue