The home situational awareness display nobody wanted or needed!
This is the server-side code for Plane/Sailing version 2.
This software receives data from local ADS-B, AIS, APRS and HORUS-compatible receiving software, along with Meshtastic nodes. The data is used for tracking planes, ships, amateur radio stations, radiosondes, and Meshtastic nodes respectively. It combines them into one large "track table", and provides a web interface by which the Plane/Sailing client can fetch data via JSON.
For more information on the Plane/Sailing project, please see https://ianrenton.com/hardware/planesailing
- Receives AIS messages in NMEA-0183 format via UDP (e.g. from rtl_ais)
- 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)
- 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
- Customisable times to drop tracks etc.
- Provides a web-based JSON API which can be used to retrieve this information.
If you just want to use Plane/Sailing Server (without making any changes to the source code), go to the latest release page and download the ZIP file containing the compiled software. This will be a ZIP named like "plane-sailing-server-x.y.z.zip" (not "Source Code (zip)").
Unpack this to wherever you would like to run it from, then jump ahead to the Setup section.
If you want to modify and build the software yourself, it's best to clone it using git, e.g. git clone git@github.com:ianrenton/planesailing-server.git. If you're a GitHub user you could also create your own fork before doing this.
Plane/Sailing Server is a Maven project, so with Maven and a JDK installed, you can build it by running mvn package, and you'll find the output in target/output/.
IntelliJ IDEA is my IDE of choice, so the source code comes with IDEA config files to help you get up and running. If you prefer a different IDE, and you want to run the software direct from your IDE for testing, you will want to set the runtime working directory to target/output and add -Dconfig.file=application.conf to the VM arguments.
In order to use this software, you should be running some combination of software to provide the data to it, e.g. 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 Server:
- Ensure your machine has Java 17 or later installed, e.g.
sudo apt install openjdk-17-jre-headless - Find your copy of Plane/Sailing Server, either from the ZIP download or one you built yourself (see the previous section). You should have three files: a JAR file, an
application.conffile, arun.sh, and adatasubdirectory. - Edit
application.confand set the IP addresses and ports as required. A list of receiving nodes is supported, each with any number of AIS, ADS-B, MLAT, APRS, HORUS and Meshtastic receivers. 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. - Set the base station position, and any airports and seaports you'd like to appear in your data.
- Save
application.confand run the application, e.g.chmod +x run.sh,./run.sh - 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.
If you're running Plane/Sailing Server on Windows, you may see an "Address already in use" error, and the software will fail to start. This is due to the choice of default port for the webserver, 8090, and its interaction with a Windows 10/11 feature called WinNAT. While there is a workaround for this involving stopping/starting WinNAT, it's probably easier just to pick a different port for Plane/Sailing Server's web interface to run on. You can change it in application.conf.
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.
Meshtastic node support relies on calling on the Python command-line utility to connect to the node and retrieve data. This is inelegant and somewhat insecure, but does easily provide the ability to connect to Bluetooth nodes as well as WiFi, and avoids me having to write and maintain a Meshtastic protobuf API for Java :)
In application.conf you will simply provide a command line for the application to run at an interval. In order for this to work, you will need to set up the Meshtastic Python CLI interface. On some systems (e.g. recent Ubuntu), this involves a venv (virtual environment) as pip cannot be run at the system level and the Meshtastic library is not yet available in the package manager. For example, the following may be required to set it up:
sudo apt install python3 python3-pip python3-venv
python3 -m venv ~/meshtastic-venv
source ~/meshtastic-venv/bin/activate
pip3 install --upgrade pytap2
pip3 install --upgrade meshtastic
deactivateThen the following command is run from Plane/Sailing:
source ~/meshtastic-venv/bin/activate && meshtastic --host [ipaddress] --info Plane/Sailing is currently explicitly calling bash to run the command, and therefore this will only work on Linux and where bash is available. Improving this is a work in progress.
By default, Plane/Sailing Server runs on port 8090. Leave the software running, then access http://[ipaddress]:8090/ in a web browser. You should see something that looks like this:
(Expecting to see the Plane/Sailing interface, with a map background etc.? That's part of the Plane/Sailing client, not the server. The two are provided separately in case you want to run them in different places—e.g. I run the server on a Raspberry Pi, but host the client using GitHub Pages. If you want to run the client and server on the same machine, read on as this is covered in the "Reverse Proxy Setup" section.)
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-server.service with the contents similar to this:
[Unit]
Description=Plane/Sailing Server
After=network.target
[Service]
ExecStart=/home/pi/plane-sailing-server/run.sh
WorkingDirectory=/home/pi/plane-sailing-server
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-server
sudo systemctl start plane-sailing-serverIf you want to check it's working, use e.g. systemctl status plane-sailing-server to check it's alive, and journalctl -u plane-sailing-server.service -f to see its logs in real time. You should see it successfully start up its interfaces to Dump1090, AIS Dispatcher and Direwolf (assuming they are all enabled) and the regular track table messages should indicate several ships, aircraft and APRS tracks depending on what's around you.
If you are running Plane/Sailing Server on Windows you can make it start automatically by using NSSM to install Plane/Sailing Server as a service, or with Scheduled Tasks, a shortcut in your Startup items, etc.
The client can quite happily connect to the Plane/Sailing Server directly on its default port of 8090. 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 Server to run on a port that Linux will let it open with normal user privileges (by default 8090) while still making it accessible to the internet on port 80 and/or 443
- You can host other software on the same machine, e.g. Plane/Sailing Client, Dump1090, 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 Server. Create a file like /etc/nginx/sites-available/plane-sailing-server.conf with contents similar to the following:
server {
listen 80;
server_name planesailingserver.ianrenton.com;
location / {
proxy_pass http://127.0.0.1:8090;
}
}
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-server.conf /etc/nginx/sites-enabled/plane-sailing-server.conf
sudo systemctl restart nginxWhen you now visit the IP address of your server using a web browser, you should instead see "Plane/Sailing Server is up and running!". Your reverse proxy setup is now working, and a client pointed at the default HTTP port (80) on that PC will now be able to communicate with Plane/Sailing Server.
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 wanted Plane/Sailing Server accessible in the root directory as normal, but then have Dump1090 on /dump1090-fa and AIS Dispatcher's web interface on /aisdispatcher 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 Server comes last, only if the URL doesn't match any of the other locations.
server {
listen 80;
server_name planesailingserver.ianrenton.com;
# Skyaware web interface
rewrite ^/skyaware$ /skyaware/ permanent;
location /skyaware/ {
alias /usr/share/skyaware/html/;
# Allow CORS requests to /data/ for UMID1090 - not necessarily required for your server!
add_header Access-Control-Allow-Origin *;
}
location /skyaware/data/ {
alias /run/dump1090-fa/;
# Allow CORS requests to /data/ for UMID1090 - not necessarily required for your server!
add_header Access-Control-Allow-Origin *;
}
# AIS Dispatcher web interface
rewrite ^/aisdispatcher$ /aisdispatcher/ permanent;
location /aisdispatcher/ {
proxy_pass http://127.0.0.1:8080;
}
# Plane/Sailing Server
location / {
proxy_pass http://127.0.0.1:8090;
}
}
If you want to host both the Plane/Sailing client (available separately) and the server on the same machine, you can use the same reverse proxy approach. Here it would make sense to have the client in the root of the server, and the server in a subdirectory. For example you could put the client in /home/pi/plane-sailing-client and set up your nginx config file like this:
server {
listen 80;
server_name planesailing.yourdomain.com;
# Plane/Sailing Server
location /server/ {
proxy_pass http://127.0.0.1:8090;
}
# Plane/Sailing Client
location / {
alias /home/pi/plane-sailing-client;
}
}
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 --nginxAt 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 Server 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-server.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 planesailingserver.ianrenton.com;
location / {
proxy_pass http://127.0.0.1:8090;
}
ssl_certificate /etc/letsencrypt/live/planesailingserver.ianrenton.com/full$
ssl_certificate_key /etc/letsencrypt/live/planesailingserver.ianrenton.com/$
}
Finally, sudo systemctl restart nginx and you should now find that Plane/Sailing Server 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.
Job. Done.
The Plane/Sailing client, or any other client you write, should do the following:
- At the start of a user session, make a call to
/first. The response will be a JSON map of ID to track parameters. All tracks will be included, and if they have a position history, that will be included too. This information should be stored locally, and used to render the tactical picture. - Every few seconds (suggested: 10), make a call to
/update. The response will be the same JSON map, which should be merged with the original one. There are a few complications to this merge:- The new data won't include position history, to save bandwidth. Rather than overwriting the client's track with the new one, it should preserve the old position history, appending the new position in the track data to the position history list.
- Any track the client has that isn't in the update data set should be dropped, except if it has the
createdByConfigflag set true. These are the immutable tracks that represent the base station, airports and seaports, and they are only sent in the/firstcall, again to save bandwidth. Their absence in the/updatecall doesn't mean they should be deleted.
- Rather than just reporting tracks' last known locations, clients may wish to "dead reckon" their current position and update the display with that more often than every 10 seconds. Because the server and client's clocks may not match, the server provides a "time" field (milliseconds since UNIX epoch) in every response. The position data for each track has a time field too. The combination of these can be used to determine how old the track's data is without having to use the local system clock.
- Optionally, clients can make a call to
/telemetryfor server telemetry such as connection status, CPU utilisation, uptime etc.
Clients are of course free to set their own policies about what tracks to show and hide, how to present the data, etc. If you are writing your own client or fork of Plane/Sailing, I am happy to receive pull requests to add new data into the API.
If you're just looking for the default web-based client that I wrote, that's here and it's also Public Domain, so you can just use it or modify it however you like.
Plane/Sailing Server 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.


