Skip to content

Instantly share code, notes, and snippets.

@Ovid
Last active June 5, 2023 11:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ovid/cedd9186d1ae6a97f1e6f1b9dc355909 to your computer and use it in GitHub Desktop.
Save Ovid/cedd9186d1ae6a97f1e6f1b9dc355909 to your computer and use it in GitHub Desktop.
A Perl script to track flights of a jet. Defaults to last 7 days of Elon Musk's primary jet
#!/usr/bin/env perl
use v5.20;
use warnings;
use lib 'lib';
use WebService::OpenSky;
use Geo::ICAO 'code2airport';
use Text::CSV_XS 'csv';
use File::Temp 'tempfile';
use Mojo::UserAgent;
use DateTime;
use DateTime::Format::Strptime;
use Getopt::Long;
# Musk apparently has three private jets, but we are interested in the
# one he flies the most, which is registered as N628TS.
GetOptions(
'days=i' => \( my $days = 7 ),
'icao=s' => \( my $icao24 = 'a835af' ), # default is Musk's jet
) or die "Bad options";
# use a nice "Monday, 29 May, 04:34 PM UT" format
my $strp = DateTime::Format::Strptime->new(
pattern => '%A, %d %b, %I:%M %p %Z',
locale => 'en_US',
);
my $openapi = WebService::OpenSky->new;
my $icao_lookup = get_icao_data();
my $now = time;
my $then = $now - 86400 * $days;
my $flight_data = $openapi->get_flights_by_aircraft( $icao24, $then, $now );
my $flight_number = 1;
foreach my $flight ( reverse $flight_data->all ) {
my $departure = DateTime->from_epoch( epoch => $flight->firstSeen )->set_formatter($strp);
my $arrival = DateTime->from_epoch( epoch => $flight->lastSeen )->set_formatter($strp);
my ($departure_airport, $departure_location,
$arrival_airport, $arrival_location
) = get_airport_data( $flight, $icao_lookup );
say "Flight #$flight_number. Departed $departure\n\tfrom $departure_airport, $departure_location";
say "Flight #$flight_number. Arrived $arrival\n\tat $arrival_airport, $arrival_location\n";
$flight_number++;
}
sub get_airport_data {
my ( $flight, $icao_lookup ) = @_;
my ( $departure_airport, $departure_location ) = ( 'unknown airport', 'unknown city' );
my ( $arrival_airport, $arrival_location ) = ( 'unknown airport', 'unknown city' );
my $estDepartureAirport = $flight->estDepartureAirport // '';
my $estArrivalAirport = $flight->estArrivalAirport // '';
if ( my $icao_departure = $icao_lookup->{$estDepartureAirport} ) {
$departure_airport = $icao_departure->{name};
$departure_location = $icao_departure->{city} . ', ' . $icao_departure->{subd} . ', ' . $icao_departure->{country};
}
else {
( $departure_airport, $departure_location ) = code2airport($estDepartureAirport)
if $estDepartureAirport;
}
if ( my $icao_arrival = $icao_lookup->{$estArrivalAirport} ) {
$arrival_airport = $icao_arrival->{name};
$arrival_location = $icao_arrival->{city} . ', ' . $icao_arrival->{subd} . ', ' . $icao_arrival->{country};
}
else {
( $arrival_airport, $arrival_location ) = code2airport($estArrivalAirport)
if $estArrivalAirport;
}
$departure_airport //= $estDepartureAirport || 'unknown airport';
$departure_location //= 'unknown city';
$arrival_airport //= $estArrivalAirport || 'unknown airport';
$arrival_location //= 'unknown city';
return (
$departure_airport, $departure_location,
$arrival_airport, $arrival_location
);
}
sub get_icao_data {
# Geo::ICAO::code2airport($estDepartureAirport) turns out to be very
# out of data and is missing many existing airports, so we use more
# up-to-date list from github, falling back to Geo::ICAO if needed.
my $url = 'https://raw.githubusercontent.com/mborsetti/airportsdata/main/airportsdata/airports.csv';
my $ua = Mojo::UserAgent->new;
return eval {
my $response = $ua->get($url)->res;
my %lookup;
if ( $response->is_success ) {
my ( $fh, $filename ) = tempfile();
print {$fh} $response->body;
close $fh;
my $data = csv( in => $filename, headers => "auto" );
%lookup = map { $_->{icao} => $_ } @$data;
}
\%lookup;
};
}
__END__
=head1 NAME
flights.pl - get flight history for a jet
=head1 SYNOPSIS
perl flights.pl [options] [days]
Options:
--days number of days to look back (default 7)
--icao icao24 code of the jet (default a835af, Elon Musk's primary jet)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment