Plane✈/Sailing - Completely unnecessary military situational awareness display for your home https://planesailing.ianrenton.com
  • Python 50.6%
  • JavaScript 35%
  • HTML 8%
  • CSS 6.4%
Find a file
2026-05-24 10:57:05 +01:00
.idea Misc tweaks 2026-05-23 12:05:23 +01:00
data Remove ABC, more pythonic duck-typeiness 2026-05-24 09:25:09 +01:00
datafiles Fix ship type to symbol lookup 2026-05-23 16:08:17 +01:00
feederinterfaces Remove the manual extraction of callsign from Comm-B messages, the pyModeS library already does this (and provides extra information we didn't extract) 2026-05-24 10:23:00 +01:00
img Add screenshot 2026-05-23 16:19:20 +01:00
static Style tweaks 2026-05-24 10:09:23 +01:00
utils Extra track count metrics 2026-05-24 10:57:05 +01:00
webserver Replace manual generation of Prometheus metrics with the Python library 2026-05-24 10:43:58 +01:00
.gitignore Continuing to work on Python port 2026-05-23 11:18:21 +01:00
config-example.yml Change default web server port to 8091 to avoid conflicts 2026-05-23 14:30:36 +01:00
LICENSE First commit, just playing around 2020-09-19 10:26:54 +01:00
planesailing.py Replace manual generation of Prometheus metrics with the Python library 2026-05-24 10:43:58 +01:00
README.md Global reformat 2026-05-24 09:06:05 +01:00
requirements.txt Replace manual generation of Prometheus metrics with the Python library 2026-05-24 10:43:58 +01:00

Plane✈/Sailing

The completely unnecessary military situational awareness display for your home!

Plane Sailing Banner

What is it?

Plane/Sailing shows the location of nearby aircraft, ships, amateur radio stations, radiosondes and Meshtastic nodes, in real time, using NATO symbology overlaid on a map.

This software receives data from local ADS-B, AIS, APRS and HORUS-compatible receiving software, along with Meshtastic nodes. It combines them into one large "track table", and provides a web interface to view them.

For more information on the Plane/Sailing project, including the hardware build guide, please see https://ianrenton.com/projects/planesailing.

You can see my instance running, showing live data from my ADS-B, AIS and APRS receivers, at https://planesailing.ianrenton.com.

Why is it?

I spent too much time thinking about whether I could, and not enough time thinking about whether I should.

Who is it for?

No idea. Ex-military hams who can't leave the SIGINT life behind? Turbo nerds with a hard-on for MIL-STD 2525 symbology? Anyone with a family tolerant enough to let them wall-mount a huge telly and make their kitchen look like Apollo Mission Control?

Please note that this software is intended to receive and display data sourced from your own radio receivers. It does not pull in data from websites such as MarineTraffic or FlightRadar24.

Features

  • Receives AIS messages in NMEA-0183 format via UDP (e.g. from AIS Catcher, rtl_ais or dedicated receive hardware)
  • Receives Mode-S/A/C, ADS-B and some Comm-B messages in BEAST Binary, BEAST AVR and SBS/BaseStation format (e.g. from Dump1090 or MODE-S BEAST)
  • Receives MLAT messages in BEAST Binary and SBS/BaseStation format (e.g. from PiAware)
  • Receives complete aircraft data sets direct from Dump1090 in its own JSON format, if preferred
  • Receives APRS messages via KISS TCP (e.g. from Direwolf)
  • Receives HORUS JSON format messages via UDP (e.g. from radiosonde_auto_rx)
  • Queries Meshtastic nodes via their Python API to obtain details of nearby nodes
  • Includes support for config-based addition of extra tracks for the base station, airports and seaports
  • Includes support for config-based addition of AIS track names, to cover the period between getting a position message and a details message
  • Includes look-up tables to determine aircraft operators, types, and the correct MIL-STD2525C symbols to use for a variety of tracks
  • Persists data to disk so the content of the track table is not lost on restart
  • Provides a fully featured web UI to view the information, with customisable layers and settings
  • Provides a track table and statistics for the backend in the web UI
  • Provides a web-based JSON API which can be used to retrieve the data so you can write other front-ends
  • Provides a TCP server repeater for incoming AIS data, to allow other software to view the merged feed from multiple clients.

Plane Sailing Screenshot

Getting a Copy

Downloading the Software

To download Plane/Sailing, go to the latest release page and download the ZIP file containing the source code. You can also clone the repository using git, if you prefer.

Unpack this to wherever you would like to run it from. This could be inside your user area if you're just testing or planning to modify the software. If it's on a public web server, for security reasons I recommend running it as a new user specifically created for the job, with the software located in its user area, e.g. /home/planesailing/planesailing.

Setup

In order to use this software, you should be running some combination of hardware and software to provide the data to it, e.g. a hardware AIS transponder, AIS-Catcher or rtl_ais, Dump1090/PiAware, Direwolf etc. You can find more information on how to install and set those up on the Plane/Sailing build guide.

To run Plane/Sailing:

  1. Ensure your machine has Python 3.11 or later installed along with pip and venv support, e.g. sudo apt install python3 python3-pip python3-venv.
  2. Find your copy of Plane/Sailing and change into its directory.
  3. Create a virtual environment and install the Python dependencies:
    python3 -m venv .venv
    source .venv/bin/activate
    pip install -r requirements.txt
    
  4. Copy config-example.yml to config.yml and edit it in your editor of choice.
  5. Set the IP addresses and ports as required. A list of receiving nodes (computers) is supported, each of which can have any number of AIS, ADS-B, MLAT, APRS, HORUS and Meshtastic receivers associated with it. One configuration of each type is provided as an example for you to copy. If there's something your setup doesn't do, just delete the corresponding section.
  6. Set the base station position, and any airports and seaports you'd like to appear in your data.
  7. Set the default position and zoom of the map when it first loads. (You may wish to delay this step until you see it working, so you can adjust accordingly.)
  8. Adjust anything else you can see in config.yml that you feel like you might want to change.
  9. Run the server: python3 planesailing.py
  10. Hopefully you should see log messages indicating that it has started up and loaded data! Every 10 seconds it will print out a summary of what's in its track table.
  11. Leave the software running, then access the web server at http://[ipaddress]:8091. You should see the web interface and tracks will hopefully start to appear.

If you'd like to make it run automatically on startup on something like a Raspberry Pi, and put it on the internet for everyone to use, the later sections of this README will help you.

Automatic Run on Startup

Depending on your use case you may wish to have the software run automatically on startup. How to do this is system-dependent, on most Linux systems that use systemd, like Ubuntu and Raspbian, you will want to create a file like /etc/systemd/system/plane-sailing.service with the contents similar to this:

[Unit]
Description=Plane/Sailing
After=network.target

[Service]
ExecStart=/home/pi/plane-sailing/.venv/bin/python3 /home/pi/plane-sailing/planesailing.py
WorkingDirectory=/home/pi/plane-sailing
StandardOutput=inherit
StandardError=inherit
Restart=always
User=pi

[Install]
WantedBy=multi-user.target

Then to complete the setup by running:

sudo systemctl daemon-reload
sudo systemctl enable plane-sailing
sudo systemctl start plane-sailing

If you want to check it's working, use e.g. systemctl status plane-sailing to check it's alive, and journalctl -u plane-sailing.service -f to see its logs in real time. You should see it successfully start up its interfaces to Dump1090, AIS Dispatcher and Direwolf (if they are enabled) and the regular track table messages should indicate several ships, aircraft and/or APRS tracks depending on what's around you.

If you are running Plane/Sailing on Windows you can make it start automatically by using NSSM to install Plane/Sailing as a service, or with Scheduled Tasks, a shortcut in your Startup items, etc.

Reverse Proxy Setup

Users can quite happily connect to Plane/Sailing's web server directly on its default port of 8091. However, you may wish to add a "proper" web server providing a reverse proxy setup. There are several reasons you might want to do this:

  • It allows the use HTTPS (with certificates, e.g. from Let's Encrypt), so the client can connect securely
  • It allows Plane/Sailing to run on a port that Linux will let it open with normal user privileges (by default 8091) while still making it accessible to the internet on port 80 and/or 443
  • You can host other software with web interfaces on the same machine, e.g. SkyAware, AIS Dispatcher etc. via the same public port.
  • You can enable caching in the web server, so that no matter how many visitors your site gets, the server itself sees a stable number of requests and doesn't get overloaded.

In this example, we will use Nginx due to its relatively easy config and support in Let's Encrypt Certbot, but you could use Apache, Lighttpd, HAProxy or anything you like that supports a reverse proxy configuration.

Start off by installing Nginx, e.g. sudo apt install nginx. You should then be able to enter the IP address of the server using a web browser and see the "Welcome to nginx" page. Next we need to change that default setup to instead provide a reverse proxy pointing at Plane/Sailing. Create a file like /etc/nginx/sites-available/plane-sailing.conf with contents similar to the following:

server {
    listen 80;
    server_name planesailing.ianrenton.com;

    location / {
        proxy_pass http://127.0.0.1:8091;
    }
}

This sets up your server for HTTP only at the moment, which is OK - we will let Certbot set up the HTTPS configuration later.

Once you're finished creating that file, delete the default site, enable the new one, and restart nginx:

sudo rm /etc/nginx/sites-enabled/default
sudo ln -s /etc/nginx/sites-available/plane-sailing.conf /etc/nginx/sites-enabled/plane-sailing.conf
sudo systemctl restart nginx

When you now visit the IP address of your server using a web browser, without specifying a port, you should see Plane/Sailing's web interface. Your reverse proxy setup is now working!

If nginx didn't restart properly, you may have mistyped your configuration. Try sudo nginx -t to find out what the problem is.

You may wish to add extra features to this configuration. For example if you had Dump1090 and AISCatcher installed on the same machine, and you want Plane/Sailing accessible in the root directory as normal, but then have Dump1090 on /dump1090-fa and AIS Catcher's web interface on /aiscatcher too, all on port 80, you can do that by tweaking the adding new "location" parameters as follows. They are handled in order so Plane/Sailing comes last, only if the URL doesn't match any of the other locations.

server {   
    listen 80;
    server_name planesailing.ianrenton.com;

    # Skyaware web interface
    rewrite ^/skyaware$ /skyaware/ permanent;
    location /skyaware/ {
        alias /usr/share/skyaware/html/;
    }
    location /skyaware/data/ {
        alias /run/dump1090-fa/;
    }

    # AIS Dispatcher web interface
    rewrite ^/aiscatcher$ /aiscatcher/ permanent;
    location /aiscatcher/ {
        proxy_pass http://127.0.0.1:8100;
    }

    # Plane/Sailing
    location / {
        proxy_pass http://127.0.0.1:8091;
    }
}

HTTPS Setup

You can use Let's Encrypt to enable HTTPS on your Nginx server, so the client can request data securely. The easiest way is using Certbot, so following the instructions here:

sudo apt install snapd
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo certbot --nginx

At this stage you will be prompted to enter your contact details and domain information, but Certbot will take it from there—it will automatically validate the server as being reachable from the (sub)domain you specified, issue a certificate, install it, and reconfigure nginx to use it.

If it fails with an error involving /.well-known/acme-challenge, it's trying to verify that your server can be retrieved at the URL you have set up, but it can't create a file and and check that it exists because your nginx config is pointing to Plane/Sailing via the remote proxy setup rather than a standard directory of HTML files. If this is the case, you will want to add the following to your nginx config:

    # Wellknown area for Lets Encrypt
    location /.well-known/ {
        alias /var/www/html/.well-known/;
    }

Once Certbot finishes its job, what you'll probably find is that it has helpfully reconfigured your server to use only HTTPS, and HTTP now returns a 404 error. In my opinion it would be best for both versions to provide the same response. To re-enable both HTTP and HTTPS, you need to delete the extra "server" block in /etc/nginx/sites-enabled/plane-sailing.conf and add listen 80 back into the main block. You should end up with something like this (with your own domain names in there):

server {
    listen 80;
    listen 443 ssl;
    server_name planesailing.ianrenton.com;

    location / {
        proxy_pass http://127.0.0.1:8091;
    }

    ssl_certificate /etc/letsencrypt/live/planesailing.ianrenton.com/full$
    ssl_certificate_key /etc/letsencrypt/live/planesailing.ianrenton.com/$
}

Finally, sudo systemctl restart nginx and you should now find that Plane/Sailing is accessible via both HTTP and HTTPS. The good news is, Certbot should automatically renew your certificate when required, and shouldn't mess with your config again.

Prometheus Metrics

Plane/Sailing exposes a Prometheus metrics endpoint from its web server, at the standard URL of /metrics. Metrics available include the number of tracks of various types in the system, and maximum detection ranges. This can be used to aggregate & analyse data on performance, provide alerting on the loss of a feed, and to add pretty graphs to Grafana.

Aircraft, Ship and APRS track charts in Grafana

How the Software Works

Plane/Sailing was formerly two separate pieces of software, a client written in JavaScript and a server written in Java. The server has since been rewritten in Python, with the client-side HTML, JavaScript etc. served by the same web server, to simplify install and setup.

The Python server is responsible for ingesting data from ADS-B, AIS, APRS etc. receiver software. So for example, you may have AIS Catcher receiving data from an RTL-SDR dongle, and AIS Catcher then sends NMEA-0183 format data over UDP to Plane/Sailing. Plane/Sailing then aggregates all this data from the different sources, and deals with things like persistence times, and converting everything to a common data set.

The Python server then exposes an HTTP JSON API which the client JavaScript code connects to. This way the client receives only consistently-formatted data, rather than having to deal with the differences between e.g. ADS-B and AIS data, as was the case in Plane/Sailing v1, which was client-side code only.

When the server runs, it loads a number of data files available to it which contain mappings of vessel types, ICAO codes to airframes, etc. It also has available to it a directory called static which contains all the front-end HTML, JS and CSS assets. As well as serving the JSON API, the server also serves these static files. The static files are served from the root of the HTTP server, while the API endpoints are served from a subdirectory called /api.

So, when the user accesses the Plane/Sailing instance with a path like https://yourserver.com/, they get served the index.html file and other static content. Within these files, code.js performs the client-side processing, which queries the API to get its data.

There are five API endpoints available:

  • /api/config provides a set of config for the client-side code to use. This comes via the server-side simply to avoid the owner of a Plane/Sailing instance having to tailor both config.yml for the server and code.js for the client to their liking. Instead, config.yml also includes client-side config, and the server's API provides it to the client once on first access via this call.
  • /api/first provides a complete set of details for all known tracks, including their complete history. The client-side code calls this only once, on first load, to retrieve the full history.
  • /api/update provides only the current data for all known tracks, not the history. The client-side code calls this every 10 seconds. It uses this to update its data model, appending the current position to the history, and dropping any tracks that are no longer known to the server.
  • /api/telemetry provides server telemetry such as CPU, RAM and disk usage. The client-side code calls this every 30 seconds if it is enabled by the user.
  • /metrics provides Prometheus metrics (note, not inside the /api directory to comply with the standard)

If any other path is requested from the server, it will then check if it matches a static file. If so, it will serve it, if not, it will return a 404 error.

A Note on Choosing Aircraft Data Protocols

A number of aircraft data formats are supported—for the gory details see the Tracking Packet Format FAQ. The preferred format is BEAST Binary format, which Dump1090 produces as an output. This contains the raw Mode-A, Mode-C, Mode-S, ADS-B and Comm-B bytes with some encapsulation. Plane/Sailing can use the same format for receiving live data from the radio via Dump1090 as it can receiving MLAT data from PiAware.

BEAST AVR format is also supported, which is ASCII-encoded and therefore a little easier to parse, but PiAware does not support this for MLAT data. SBS/BaseStation format is supported too, which is both ASCII-encoded and supported by PiAware for MLAT, but it doesn't contain all information fields e.g. aircraft category.

Finally, Plane/Sailing v1 loaded its aircraft data from a JSON file written by Dump1090, and Plane/Sailing v2 preserves this capability. This data contains every data point including merged-in MLAT data, however the data is not "live" so requires some adjustments in the code for the time at which data was recorded. It's no longer the preferred option but it is available.

If you're not sure, the default will work fine.

Third Party Libraries

Plane/Sailing is built on top of several open-source libraries. For Python check dependencies.txt for a list; for JavaScript check the head of index.html to see what it imports. All libraries are used with many thanks.

It also contains a self-hosted copy of Font Awesome's free library, in the /static/fa/ directory. This is subject to Font Awesome's licence. This approach was taken in preference to using their hosted kits due to the popularity of this project exceeding the page view limit for their free hosted offering.