Version 2.1 of Flight Historian is now live.
Table of Contents
Boarding Passes
In general, my Flight Historian has been a big time saver for me as far as tracking my flights—instead of manually generating reports and maps from an Excel file, I can simply add flights to a database and let it do all the work. However, as I’ve started tracking more details about my flights over time, the task of entering the flights has become less simple.
Since I’d been working on parsing boarding pass barcode data, it seemed like a logical next step to write some sort of scanner that would read a boarding pass barcode and import the data as a new flight. But since I usually used digital boarding passes on my phone, it would also be really useful if I had a way to import those directly into Flight Historian.
Getting Flight Data from an Apple Wallet Pass
Apple Wallet is an application included with iPhones that, among other things, can be used to store boarding passes from various airlines in a single location.
Even more importantly, Wallet lets you share boarding passes by email.
So I decided I’d do for boarding passes what sites like TripIt do for itineraries. I would set up an email address that I could simply email my Wallet boarding passes to, and then have my server look for emails from me and process any boarding pass attachments.
Getting Boarding Passes from IMAP
As the boarding pass email address I set up supports IMAP, I used Ruby’s Net::IMAP
class to have Flight Historian interact with my email account.1
When I go to the Import Boarding Pass page on Flight Historian, it checks for new messages (from a specified list of my email addresses) which have a PKPass (PassKit Package) attachment.
The PKPass format is how Wallet stores and shares digital boarding passes. It’s actually a zipped file archive with the extension .pkpass. Inside this archive is, among other things, a file called pass.json which contains all of the information about the pass in JSON format, including the visible text and the data encoded in the 2-D barcode.
Thus, I wrote a BoardingPassEmail
module for Flight Historian which would loop through any email attachments, and for each attachment, unzip it, navigate to pass.json, and store it as a PKPass object in my database. Once Flight Historian successfully saves the pass, it deletes the email that the pass came from.
Adding a Flight from a Stored Boarding Pass
Since Flights need to be part of a Trip, every trip provides a link to my new Import Boarding Pass view with the Trip’s ID as an argument. However, I included the ability to select a different trip to accept the new flight, if necessary.
Each Create Flight link brings me to the same New Flight form as before, but it includes a PKPass ID as an argument. If that pass ID is present, the Flights controller knows that it needs to read the JSON data associated with that pass, and use it to populate the appropriate form fields, saving a great deal of manual data entry.
There are three sources for filling in the the fields:
- Some fields can be populated directly from the pass.json file.
- Some field data is encoded in the pass’s barcode string. Thus, I created a barcode method for the PKPass model, which uses my Boarding Pass Parser to decode and return the barcode data.
- The remainder are not found anywhere in the electronic boarding pass. I wrote a method to look up the remaining flight data on FlightAware’s AeroAPI using the boarding pass’s airline, flight number, and UTC departure time.
When the new flight is saved, it also includes a pass_serial_number
field, which is a string uniquely identifying each boarding pass as defined in the PKPass format. This way, if a boarding pass is updated, Flight Historian knows that the updated pass needs to be associated with an existing flight rather than a new flight.
Updating a Flight
If Flight Historian finds a boarding pass attachment with a serial number that is already associated with a saved flight, it shows the pass in a Flights with Updated Passes list instead.
This time, since the flight already exists, the form only shows the values which have changed, and allows the user to select the new value or keep the existing value.
Aircraft Types
My flight log previously kept track of aircraft families (e.g. any Boeing 737), and didn’t do anything with specific types (e.g. Boeing 737-800), other than to optionally note them in an aircraft variant text field. This was a deliberate decision, as my flight log was generally set up to catalog my flight experiences, and there was no substantial quality of flight difference for me between, say, a 737-800 and a 737-900.
However, one of the fields I needed to look up on AeroAPI was the aircraft type. AeroAPI does return the specific aircraft type (by ICAO code), so at the very least, I needed to write a lookup function to convert specific aircraft types into the general aircraft families I was using.
However, I decided that it would make more sense to do it right, and actually incorporate aircraft types into my database. I still wanted to maintain my aircraft family structure, and I still had some old flights in my database that I didn’t know the type for anyway. So I eventually decided to add a parent/child relationship to my Aircraft Families table, where both types and families would be stored in the table (and I could assign a flight either a family or a specific type), but the aircraft types would have a parent_id
field that linked to the ID of their parent family. That way, I could still summarize all of my flights by their parent family (by looking at all aircraft types that were part of the given family), and for each specific type AeroAPI returned, I would know the family.
The side benefit of this structure is that it also made it easy for me to show statistics for the specific types. Each aircraft family page still includes all the flights it did before, but it also shows a list of types, and clicking on one of those types provides details for that type.
Changelog
Added
- Created Import Boarding Pass from Email functionality (using Apple PKPass boarding passes).
- Created
BoardingPass
class for parsing and interpreting Bar Coded Boarding Pass (BCBP) formatted data. - Created
BoardingPassEmail
module for connecting to an IMAP email acccount, finding PKPass attachments, and processing them. - Created
PKPass
model for storing PKPass data. - Added email and alternate email parameters to
User
model (enables whitelisting valid senders of PKPass attachments). - Added Numeric code parameter to
Airline
model (enables lookups of numeric codes in BCBP data). - Added JSON API for parsed boarding pass data.
- Added Import Boarding Passes view.
- Added a form to allow entry of airport data for BCBP IATA codes not found in the
Airports
table - Added a form for editing an existing flight with an updated PKPass.
- Added an admin view to list any flights with invalid BCBP data.
- Created
- Created a new message banner system, to make all messages look consistent.
- Added aircraft types to
AircraftFamily
model, and views to show aircraft types.
Changed
- Add Flight form now autofills PKPass data when available.
-
As of 13 August 2024, Flight Historian uses AWS SES and S3 to handle boarding pass email instead of connecting to an email account with IMAP. ↩︎