Virtual Radar Server

What’s Up? ” revisited

The discovery that you can run Virtual Radar Server (VRS) on a Raspberry Pi triggered me to revise my What’s Up flight radar for ESP32/8266 once again. Mainly interested in aircraft within the range of my ADS-B receivers, I already preferred querying those receivers over using the adsbexchange API, especially after they removed most static metadata from their json response. This had even forced me to setup and maintain my own database for looking up fields like aircraft model, type, operator, country etc.

However, querying Virtual Radar Server on one of my PiAware receivers lets VRS do these lookups from its own up-to-date web databases! Its enriched json response, based on my own receivers’ ADS-B and MLAT reception, contains more details than the current adsbexchange API. Besides, unlike adsbexchange, a local VRS doesn’t mind to be queried once every second! Using VRS as the primary source, I can always choose to find possibly¬† filtered out ‘sensitive’ aircraft by querying adsbexchange as well.

A quick prototype on an ESP32 and a 2.4″ TFT display finally shows flicker free icon movement after applying some display techniques from earlier projects.

My smartphone doesn’t like filming TFT displays…

While simultaneously running the old adsbexchange version and this new one, I noticed that the new version showed more aircraft, especially nearby aircraft at low flight levels. This is surprising, since claims to provide unfiltered data and they should be aware of those those missing aircraft because I feed them!

Anticipating a future project (“Automatic Plane Spotter“), the new version also keeps track of the nearest aircraft’s position, expressed in azimuth and elevation. This will be used for driving the stepper motors of a pan-tilt camera mount that I’m currently building.


ADS-B Exchange!

Despite some turbulence within the ADS-B Exchange community after their API policy change, owner James Stanford kindly sent me a key for the new REST API ūüôā

In exchange for feeding ADSBx, non-commercial users may use the API for free. Your key needs to be included in the header of each (https) API request.

The following code is at the top of my new What’s Up? sketch for monitoring all aircraft within a distance of 25 nautical miles from my location. Latitude- and longitude filters have not (yet) been implemented in the new API, so they need to be applied on the query results programmatically.

Then, inside loop(), I create an instance of WiFiClientSecure and send the API request over https, including my API key in the header:

The json response can now be processed as usual by reading from the stream ‘client’. Although the key names of the new API differ from the old ones, I didn’t have to make any changes to the json streaming parser that I wrote for earlier ADS-B projects because it takes these names from a global array that now looks like:

Some keys from the old API do not (yet) have an equivalent in the new json response. As a temporary solution, I now host a local API on my webserver, returning aircraft model and flight operator for an icao or opicao code. It’s powered by a MySQL database, imported from json files found at

A further change in the new json reponse forced me to rewrite my function for character decoding. The new API uses Unicode code points instead of multi-byte utf-8 for encoding special characters. When using GFX-based graphic libraries, these need to be converted to Extended Ascii Code page 850 (“Latin-1”), or to ‘romanized’ cyrillic characters.

[UPDATE] Meanwhile, I discovered that Bodmer’s unbeatable TFT_eSPI library offers great unicode support and lets you create font files with only the desired unicode blocks!

It all works OK, although responses from the new ADBSx API show more drop outs then before. Also, jumps between consecutive position updates seem larger, making the so arduously conquered flicker free icon movements less striking.

I expect to post a video of my new (and hopefully final) ESP32 version of What’s Up? in one of the next posts. In order to use the code, you’ll either have to be (or become) an ADSBx feeder, or buy a key. I went for the first option (with two feeders) and made a donation as well, despite my strong aversion to PayPal.




ADS-B Exchange(d?)



Please do feed!


It’s been over two years since the discovery of formed the inspiration for my What’s Up? project: visualization of air traffic on a small TFT display. Last week, I decided to rewrite the ESP8266 code for the ESP32 (Wrover) module, hoping that its extra CPU speed and PSRAM would make the aircraft icons move more smoothly over the map. The result was totally satisfying (as long as it lasted), and I even managed to build in my internet radio code for receiving live air traffic control (ATC) stations.

But then, on the very next day, the free adsbexchange API stopped working…

I understand the owner’s decision, though, and even feel guilty about not having made my two FlightAware receivers feed ADSBx much earlier. In a post on the site’s forum, the clearly ‘pissed’ owner (James Stanford) complains about the fact that many FA and FR24 feeders use his API, but don’t feed ADSBx. That must be annoying, but as for me (and there may be others), there’s a simple explanation for it: ‘Fear of Linux….‘.

When I started with ADS-B, the FlightAware logo on my dongle encouraged me to try their Piaware image first. Everything worked fine out of the box, and for me, with close to zero Linux experience, that was a black box (well, actually a transparent lunch box). However, making it feed ADBSx as well would require me to execute cryptic Linux shell commands… And then I also got confused by sources saying Piaware takes control over what can be installed, so I decided not to jeopardize my precious feeder.

Encouraged by the broken API, finding this Piaware 3.7.1. based setup guide convinced me that it was safe to make the move, hoping to meet the conditions for receiving an API key. After executing the following commands, my FA feeders now feed ADBSx as well!
sudo apt update
sudo apt install git socat
git clone
cd adsb-exchange
chmod +x
sudo ./

Note: the new version of the script will no longer auto-start the feeder from rc.local, but from systemd.

It’ll take a while before a new feeder appears on all ADSBx pages, but you can immediately check if messages from your ip address are being received by ADSBx here. You will see someting like this:











Once the mlat syncs with nearby peers have been established, your feeder will also appear on the MLAT Sync Stats page for your region.

After an hour or so, the location of your feeder will be indicated on the coverage map of your region ( for my location).

If you are currently feeding FA (I can’t speak for FR24), why not start feeding ADSBx as well? It’s entirely safe and will not affect your FA feeder in any way. Moreover: you’ll be supporting their dedication to sharing unfiltered flight data.

With my brand new What’s UP? sketch currently being grounded, I’ve humbly requested an API key from ADSBx.

PiAware & Automatic Gain Control

Odd fluctuations in my PiAware ADS-B receivers’ coverage graphs made me wonder how AGC in dump1090-fa really worked, because information on the subject is contradictory. A common technique for gaining insight into a process is by studying its anomalies, and the following announcement offered a promising opportunity.

     February 12th, 2019
For one of my receivers, air traffic over Belgium is the main source of ADS-B messages, especially in the 80-160 km range. So I was expecting to collect substantially less position broadcasts during the 24-hour strike. That proved to be the case, but I also noticed something else: for the first time since I permanently mounted the antenna outside, I was finally receiving a considerable amount of long distance (420+ km) positions again.

[Note that the bar graphs have different scales]

I recognized the above behaviour from the time when my antenna was still mobile. It always occurred immediately after moving the antenna from inside to outside the house. The effect would then gradually fade during the next couple of hours.

Conclusion so far is that many strong (relatively nearby) messages will make the AGC mechanism gradually reduce the receiver’s sensitivity. This may be beneficial for the total number of aircraft seen, but it comes at the cost of long distance reception. Once the strike was over, long distance reception dropped again within a couple of hours.

I’ve been experimenting with fixed gain values in order to receive more long distance aircraft, mainly to determine how far my receiver could reach. However, none of the allowed gain values gave results that resembled what I got during the 24-hour strike, or shortly after moving the antenna from inside to outside. Could it be that AGC does more than just adjust the receiver’s gain?




Both Sides Now…

With my FlightAware feeder now permanently mounted outside, I began thinking of installing a second ADS-B/Mode-S feeder at the opposite side of my apartment. Would the extra reception coverage be worth the costs, as the second antenna could only be placed inside, blocked by some nearby obstacles. Earlier tests with a NooElec NESDR SMArt dongle and a simple antenna had been quite disappointing, but after placing the antenna behind a solid wall instead of a window, reception suddenly became interesting enough to make me buy a second RasPi + FlightAware Pro Stick Plus + 66 cm antenna.

Antenna coverage graphs of both feeders


First I had the second RasPi run just dump1090-fa (not the complete Piaware suite) and forward its decoded messages to the first feeder. A picture on the FlightAware site illustrates how processes are linked together.

[not shown is port 30004, on which dump1090-fa is listening for incoming ADS-B messages from other feeders]

I used netcat for forwarding messages from one feeder to the other:


Forwarding messages from dump1090-fa to the FlightAware feeder boosted its detected aircraft figure, but (inevitably) at the cost of its MLAT synchronisation/reception. So I ended up with both feeders running Piaware and showing up as two separate ‘sites’ under my account. For visualizing detected traffic from both receivers I use Virtual Radar Server’s local webpage ( on a Windows laptop.

The image below shows my Virtual Radar, with combined coverage graphs of both receivers’ ADS-B & MLAT reception. The outer black circle is at 400 km from my location, so I’ve been receiving aircraft from well over 600 km distance. Occasionally, particularly when nearby traffic is low, the receivers pick up positions from even further distances (800+ km), but these are too irregular to be represented in VR’s coverage graph.


[ I could figure out which of the feeders gets most MLAT aircraft, and then forward that feeder’s ADS-B messages to the other feeder. This would stop that other feeder from receiving MLAT aircraft and make it feed FlightAware with ADS-B aircraft from both feeders. That would substantially raise its site ranking as well as my FA user ranking (ADS-B aircraft from the first feeder would be counted twice). I suspect that FA wouldn’t be pleased, so I’ll stick to operating two strictly separated feeders. ]

ADS-B experiences

After two months of experimenting with a generic SDR dongle, a dedicated ADS-B dongle and a couple of antennas, here’s my experience so far.


Used equipment:

  • FlightAware Pro Stick Plus
  • NooElec NESDR SMArt
  • FlightAware antenna (66 cm)
  • Magnetic ground plane antenna
  • Telescopic FM antenna
  • Raspberry Pi 3B+ (Piaware image)

In order of importance, expressed in an (approximated) percentage of influence on my ADS-B reception, this is what helped to improve my FlightAware feeder statistics:

[70%] – Antenna placement. Outside is better than inside (obviously), especially for houses with energy saving windows (metal coated glass reduces signal strength ~40%). Higher is better, in general, but it pays off to experiment:

  • Raising my outside antenne by 80 cm, as well as increasing its view angle by 2 degrees, made it receive more aircraft – but at the cost of most of its >400 km reception…
  • My inside antenna turned out to perform much better after moving it from the window to a wall, where an obstacle outside did no longer block a high air traffic area.
  • Since ADS-B is basically a ‘line of sight’ transmission, it’s clear that obstacles can block signals. But they can also act as rear view mirrors! A large apartment building that blocks my long range reception in one direction compensates for this by bouncing signals from an otherwise completely blocked direction. ¬†

[20%] – Antenna type & quality. The FlightAware antenna isn’t cheap, but its 5 dB gain will extend your reception range compared to simple 1/4 or 1/2 wavelength antennas.

[5%] – Dongle. The FlightAware Pro Stick Plus squeezed a bit more out of all tested antennas. And it didn’t get as hot as the NooElec.

[5%] – Cables & connectors. Use quality cables and keep them as short as possible. Also: periodically check your SMA and/or N-type connections (they can get loose over time).

Tip 1: The amazing Virtual Radar Server (VRS) software is extremely useful for finding the best antenna position. It can create receiver range plots over time, even for different altitude ranges. This allows for a visual comparison of different antenna positions and choosing the one that fits your needs (i.e. best coverage of a particular area, best long range reception, etc.)

Tip 2: Experiment with your receiver’s gain. This is a setting in dump1090 (the demodulator/decoder software component). Default setting in the Piaware image is ‘AGC’ (Automatic Gain Control), that is supposed to dynamically adjust gain in order to avoid ‘clipping’ of the strongest signals. However, some reliable sources claim it will set gain to ‘max’ (49.6 dB) …

If you have ssh enabled on Piaware, here’s the commands to read the current gain setting:

sudo systemctl status dump1090-fa -l

To set gain to, for instance, 40.2 dB:

sudo piaware-config rtlsdr-gain 40.2

Make sure to restart the dump1090 process for your changes to come into effect:

sudo systemctl restart dump1090-fa

Possible gain values are: 0.0, 0.9, 1.4, 2.7, 3.7, 7.7, 8.7, 12.5, 14.4, 15.7, 16.6, 19.7, 20.7, 22.9, 25.4, 28.0, 29.7, 32.8, 33.8, 36.4, 37.2, 38.6, 40.2, 42.1, 43.4, 43.9, 44.5, 48.0 and 49.6

Note: supplied values will be rounded to the closest value in the list. A value of -10 will set the receiver in AGC mode.




Pi in the Sky

It had been waiting on the runway for some time, but now my tinkering with Raspberry Pi  has finally been cleared for takeoff. After getting familiar with my FlightAware ADS-B dongle on Windows (previous post), using a RasPi as a 24/7 FlightAware feeder was a logical choice. No Linux knowledge required: just download the PiAware image, burn it on an SD card, boot the RasPi with it and claim your device at

The essential program here is dump1090, a clever piece of software for decoding raw Mode_S messages to human-readable flight information. Collected data is made accessible through its built in web server, via TCP, or in json format (default address: http://<local_ip_address_of_piaware>:8080/data/aircraft.json). The program is also highly configurable:

The PiAware package comes with Skyview, a web interface for displaying received flight data from your receiver. It connects to a local web server, so no Internet connection is required. I also discovered that the Virtual Radar program that I use on my Windows PC can be configured to retrieve its data from RasPi’s dump1090 instance:

Note: the above setting will only grab ADS-B aircraft. If your Piaware receiver has MLAT enabled, you can configure a second receiver, listening to port 30105 of the RasPi. Then you can combine both aircraft types in a merged feed (Tools – Options – Merged Feeds) and select ‘Merged Feed’ as receiver in the Virtual Radar web page.

The Virtual Radar web interface is similar to Skyview, but it shows some additional information in the right pane, like aircraft photos. It can use a local aircraft database for filling in missing data like registration and aircraft type, based on the received ICAO code.

Now that I’ve come this far with my close-to-zero Linux knowledge, it’s time for some new challenges:

  • Expand coverage by placing a second ADS-B receiver at the opposite side of my house, merging data from both receivers (= boost my FlightAware ranking) by having an additional instance of dump1090 acting as a hub (–net-only mode).
  • Feed other flight tracking services with the same (merged) data, like and – the original goal of this whole excercise – There are scripts for that, but I want to make sure that they will not mess up my current setup.
  • Make a local version of my What’s Up sketch, that gets its json data from the RasPi.

Some of this may require some (hopefully not too much) Linux knowledge, and at least SSH access to the RasPi(s), which is said to be easily achieved by putting an empty file named ‘ssh’ in the /root folder on the PiAware SD card.

So far, we’re on schedule. Stay on board and enjoy your flight.

Radar Love

My What’s Up? flight radar sketch for esp8266 relies on for its data. In order to do something in return, I bought this ADS-B receiver and a decent 1090 MHz antenna*.

The idea is to become a feeder for the and servers, sharing transponder data that’s picked up from planes within reach of my receiver.

The quickest way for me to test the device was by plugging it into a Windows 10 tablet. Everything turned out to be simple: within 10 minutes I was looking at “my airplanes”, quietly moving over a map. Even with the antenna placed indoors, the receiver managed to ‘see’ planes at a distance of up to 340 355 390 km! (even> 450 km after opening the window). If my rough calculations are correct, that’s close to the distance where an aitplane at 12 km altitude will disappear behind the antenna’s horizon. Impressive.

This is the (free) software that I used on Windows 10:

  • zadig : this magic tool lets you replace the default Windows driver for the dongle by an alternative driver that supports RTL/SDR functions. This needs to be done just once (per usb port?).
  • dump1090 : extracts and decodes the received ADS-B messages. Keep this program running because it provides the source information for virtual radar (see next).
  • virtual radar : starts a local web server and opens a console window with some statistics + the url of a local web page, displaying all planes within reach of the receiver.

After some experimenting in order to find the best antenna position, my receiver is now part of a Raspberry Pi-based FlightAware ADS-B feeder. Next step will be to feed the database simultaneously.

Piaware Skyview

*Surprisingly, this ‚ā¨ 60 antenna performs only slightly better than a cheap 6.8 cm antenna that came with a Nooelec SRD dongle. Placement of the antenna is clearly more important.


What’s up? (finishing touch)

Today I finished my What’s up (flight monitor) project by adding touch functionality to the TFT display. Touching a plane on the map will temporarily turn its icon red and display its flight details in a popup text area. After a couple of seconds, the map will be restored to full size again.

[Background conversation is live air traffic control from Amsterdam Airport Schiphol; video quality suffers from interference between the TFT display and my smartphone’s camera]

I had to use a STMPE160 touch screen controller because an esp8266 board like the Wemos only has one analog input, whereas my display needs two. Adafruit’s STMPE160 library seems to lack reliable control over the touch buffer, resulting in old touch point data being returned when a new touch event occurs. Luckily, I found a way to flush the buffer and make the sketch work.

I learned a lot from this challenging project and I’m quite satisfied with the final result. Intermediate versions of this project are here and here.

What’s up? (graphical)

Going graphical was a logical step between my original text-based flight monitor and the final touch screen version. Here’s the result on a 480×320 TFT display, powered by an esp8266 based Wemos D1 R2. It shows spotted airplanes over the displayed area, updating their positions every 5 seconds.

The suddenly appearing fourth airplane obviously just switched on its transponder while standing on the runway of Eindhoven Airport, that’s why it doesn’t move.

Military airplanes will appear in a different color and I’m considering the use of different icons for helicopters, gliders, air balloons and UFOs…

The refresh of the airplane icons isn’t as fast as I had hoped for, especially if there are many (can’t do them one at the time because they can overlap). This HX8357D driven Adafruit 3.5″ display is great, but not exactly fast. Let’s hope someone optimizes the library one day. Anyway, I’m still quite satisfied with the overall result so far.

See also: the final touch screen version of this project. Clicking a plane temporarily shows its flight details in a popup text area.