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 a D32 Pro 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.


Web images on TFT

“Bodmer vs Bodmer…”


Looking for a fast way to have an ESP32 download and show web images on a TFT display, I came accross the very fast TJpg_Decoder library* on Github. It’s by Bodmer (the guy deserves a statue) and integrates nicely with his TFT_eSPI library.

One of the library’s examples shows how to download a jpg image to a file in SPIFFS, and then decode and render it to a 320×240 TFT display. Rendering time is impressive, but I managed to make it 10% faster by rendering from RAM instead of SPIFFS.

The sketch at the end of this post shows the essential steps. It pushes a 320×240 web image to the display 2x faster than my older sketches, that use the JPEGDecoder library (also by Bodmer!). Another difference from my earlier sketches is the use of the HTTPClient library. It takes away the hassle of dealing with http headers and chunked-encoded response.

By the way: after rendering the jpg file to the display, you can still copy it from the array to a file in SPIFFS or on SD card for later use. This only takes a single line of extra code.

There is something that I noticed while measuring this library’s speed on ESP32 boards with PSRAM. Sketches that were compiled with PSRAM Enabled rendered almost 15% slower than the same sketch with PSRAM disabled, even if PSRAM wasn’t used at all. This is not necessarily related to the library; it could also be a general PSRAM issue. Luckily, since jpg images for small TFT displays will likely fit inside RAM (even for many ESP8266 boards), there’s no need to enable PSRAM, unless your program needs it for other purposes. Make sure that BUFFSIZE fits in RAM and is large enough to hold your jpg files.

As for grabbing other image formats (gif, bmp, png…) and resizing: most hobbyists will have access to a (local or hosted) webserver with php. Thanks to very powerful php graphic libraries, only a few lines of php code can take care of converting any common image format to jpg, and send it (resized, rotated, cropped, sharpened, blurred or whatever) to your ESP for rendering. If that’s not an option, then this new library can still reduce the size of an image by a factor 2, 4 or 8 by calling function TJpgDec.setJpgScale() with the desired factor as parameter.

Below is an adapted and stripped version of Bodmer’s example, using an array instead of SPIFFS. Make sure to select the right setup for the TFT_eSPI library before compiling. Some boards also require you to explicitely switch on the backlight in your sketch.


Output on the Serial monitor will be something like:

[HTTP] connection closed or file end.
Downloaded in 188 ms.
Decoding and rendering: 125 ms.

Too slow for your eyes? By storing decoded tiles to a display buffer in (PS)RAM instead of pushing them to the display one by one, the image can be pushed to the display in 44 ms

On an ESP32, you can speed up the entire process by using both cores. The library has an example that lets core 0 do the decoding. Whenever it finishes a tile (usually 16×16 pixels), core 1 will push it to the display in parallel. However, this will not beat the above display buffer method with regard to the visual part of the process.

*TJpg_Decoder uses the Tiny JPEG Decompressor engine by ChaN





Currently ‘lockdown-ed’ at sea level, my thoughts often wander to the majestic heights of my beloved Alps. After visiting one of those Alpine webcam sites, I wondered if I could turn my M5Stack Fire into a handheld Alpenpanorama. Or, to reverse Francis Bacon’s words: if you can’t go to the mountain, then the mountain must come to you…

This project was a bit more challenging than expected, as showing JPEG-encoded web images on a 320×240 TFT display requires extracting, decoding and resizing binary data from a chunked-encoded http response. After two days of bit-wrestling, here’s the result:

The time interval between images was reduced for this video. Music: “Schwärzen-Polka”

At startup, the program reads a list of 60+ webcam links from my web server. This enables me to change the displayed webcams without updating the software. Once running, the middle button pauses/resumes the loop, the left button removes the currently displayed webcam from the loop and the right button restores the original webcam list.

Because these live photo webcams refresh their pictures every 10 minutes, this gadget continuously gives me an up to date view of places where I would so much rather be….

P.S. I recommend not to use the official M5Stack library. In this project, decoding jpeg images with Bodmer’s fast JPEGDecoder library became more than 3 times faster after I replaced M5Stack (that has TFT_eSPI built in) with native TFT_eSPI. This could very well be caused by their library’s interrupt based button functions that are also notorious for causing WiFi crashes.



Spectrum Analyzer Revisited

Encouraged by the happy ending of the Swinging Needles project, I decided to revisit an earlier audio spectrum analyzer. This time, instead of programmatically processing analog signals, I used a VS1053 plugin to let the chip do the Fourier stuff.

Before even starting to read actual frequency band values, I wanted to test my sketch by reading the plugin’s default frequency settings from VS1053’s memory. However, some of these readings made no sense at all, up to the point that I suspected a faulty chip. It took me some time to find out that the chip needs a few seconds of audio input before it will tell you something useful, even if it concerns a fixed setting like number of frequency bands.

Once the above mystery was solved, things became very straightforward. What a versatile chip this VS1053 is! While playing a 320 Kbps internet radio station, it can easily handle 14 frequency bands and let an esp8266 at 160 MHz show the results on a 128×64 Oled display.

Running the test sketch (without amplifier/speakers).


Here’s the sketch that I wrote for testing: a fixed-station internet radio (no metadata, no audio buffer), just to show a 14 band spectrum analyzer on a 128×64 SH1106 Oled display. Used pins are for the rather rare Wemos D1 R1, so you’ll probably have to change them.


This is the content of the plugin.h file that needs to be in the directory of the sketch:





Mini MP3 Player

This little €4 module filled my entire weekend, mainly spent on finding the right documentation and a library that will work on Arduino, ESP8266 and ESP32. It’s a DFPlayer Mini MP3 Player from DFRobot (or, more likely, one of its many clones).

It can play MP3 and WAV files, stored on an SD card in the onboard card reader or from an attached USB drive. So far, I only tested MP3 files from SD.

You can connect one (4 Ω) speaker to the (quite impressive) onboard mono amplifier. Stereo line output is said to be provided on the DAC_R and DAC_L pins.

The main control method of this player is via commands over the module’s 9600 baud serial port. A subset of most commonly used commands can also be executed by means of two GPIO pins and/or two resistor-sensitive ‘ADKEY’ pins.

I made a false start by testing it on an ESP32 over hardware serial. That didn’t seem to work, so I tried an ESP8266 over software serial. That didn’t work either, and I had reached the point of giving up, assuming it was just another Chinese fake, when I gave it one more try on my good old Arduino Uno. With a quick & dirty 1K resistor for level shifting the module’s RX pin, the example sketch of one of many libraries finally made the little guy play me a song! In the end, it was the power supply that made the difference.

Some important things that I learned so far:

  • The module works best when powered by a stable 5 Volt. My Arduino Uno and Wemos D1 R2 could deliver it from their 5V pin, smaller ESP8266 and ESP32 boards couldn’t. In that case: use a separate 5 Volt power supply.
  • Wiring as suggested here caused a shutdown of my laptop’s usb port! I’m still searching for a way to connect the module to ESP32.
  • The module operates on 3.3 V logic level, so make sure to level shift the connection to the module’s RX pin when using a 5 V microcontoller.
  • Startup noise disappeared after I connected both GND pins from the player to ground.
  • Although it’s for a Flyron FN-M16P module, this excellent manual/datasheet has more and better written information than DFRobot’s own poorly translated summary. Apparently both modules use the same commands and probably have the same chip.
  • Getting stereo ouput from the DAC pins is still a problem. According to the manual, DAC is enabled on startup, but is it? Explicitely enabling it by sending 0x0000 to memory address 0x1A made no difference while sending 0x0001 instead (supposed to turn it off) started a terrible noise…
  • I tested quite some libraries from github, most of which have issues [update: starting sketches with delay(1000); solved most of them] and seem unnecessarily complicated to me. An exception is this simple and transparent library that is basically just a wrapper for sending serial commands. It can easily be extended with additional methods, even by unexperienced C++ programmers. You just have to lookup the command- and parameter bytes for the desired function in the datasheet and create a new function to send them (see example at the bottom of this page). [update: the author of the library has meanwhile added more commands]
  • The module has an SPK_1 and an SPK_2 pin, with a GND pin in between, which could suggest that it has a stereo amplifier. Although the documentation clearly says it’s mono, someone actually published a wiring diagram with two speakers connected. This person may own a different version of the module, but mine definitely has a mono amplifier. So the two wires of a single speaker should go to the SPK pins.

[ Wiring for Arduino Uno, with SoftSerial on pins 10 and 11; don’t forget the 1K resistor! ]


The location of files and their names is also very important because of the way commands address them. All information can be found in the datasheet, but here’s a summary:

  • The SD card’s maximum size is 32 GB. It must be FAT or FAT32 formatted.
  • There can be up to 3000 .mp3 (or .wav) files in the root directory of the SD card, named 0001.mp3 to 3000.mp3.
  • The root can have up to 99 subdirectories, named 01, 02, … 99. Each of these subdirectories can hold up to 255 files. Their names must start with 001, 002, … 255,  but you can append decriptive titles to these files, e.g. 007_James_Bond_Tune.mp3.
  • You can have a special subdirectory in the root named MP3. This can hold up to 3000 files, named 0001.mp3 to 3000.mp3.
  • You can also have a subdirecory ADVERT in the root. Special commands are available for making tracks in this folder interrupt currently playing tracks from the MP3 folder (for advertisement puposes). The rules for the MP3 subdirectory apply here as well.
  • Don’t create subdirectories inside subdirectories.
  • The module does not actually use file- or directory names, but the order of files and directories in the SD card’s FAT. The previously mentioned naming conventions just try to give you control over that order. If you properly organize your audio files in a folder on your PC first, and then copy that entire structure to a freshly formatted SD card, then (in theory) the FAT order should match the file- and directory numbering. See also this tool

Apart from adding some extra functions to the above mentioned library, I still have to find out how to reliably receive and read the module’s response to commands and queries. Once that I’m in full control over this (for its price) remarkably versatile module, it will be useful for a couple of ‘talking’ projects that I have in mind. Probably just mono and not ESP32 driven, but anyway: lots of fun for just €4.


Here’s an example of a function that I added to the DFPlayerMini_Fast library. Calling play_in_dir(2, 5) will play file 005.mp3 in subdirectory 02.

Using an existing function as a template, I first added my new function to the DFPlayerMini_Fast.cpp file:

Then I added these two accompanying lines to the DFPlayerMini_Fast.h header file:

and (inside the code for the class):


Explanation: according to the datasheet, the 10 (hexadecimal) bytes that have to be sent (by the sendData() function) to play track 005.mp3  in directory 02 are:

7E FF 06 0F 00 02 05 xx xx EF

7E FF 06 are the first three bytes for every command. The following 0F is de code for ‘play a file in a direcory’, the following 00 means ‘no confirmation feedback needed’ and is followed by the two parameters for the desired directory- and file number: 02 and 05. Then comes xx xx which are two checksum bytes that will be calculated and replaced by the findChecksum() function of the library before the command is sent by sendData(). Finally, every command has to be closed by EF.

As you can see, my newly added function play_in_dir() takes two parameters only, corresponding with two bytes in the command sequence. All other bytes of the sequence are either fixed or calculated by the findChecksum() function.



LOLIN TFT-2.4 Shield

Here’s a well designed new display from Wemos Electronics. They call it a (D1 Mini) Shield, but instead of going on top of a Wemos D1 Mini (Pro), it lets you plug in the Mini at the back of the 2.4″ TFT touch screen display, leaving all GPIO pins accessible, thanks to double header rows. Very useful!

This table shows the internal pin mapping when used as a shield. For TFT_LED, TFT_RST and TS_CS, this mapping can be changed by closing solder bridges at the back of the display (default NC for TFT_LED means “backlight always on”).

The default pin mapping leaves I2C pins D1 and D2, as well as D4, A0, TX and RX available for other purposes. With my Wemos Mini Pro v2 plugged in, this shield has become my first choice for battery powered esp8266 projects that require a display.



But there’s more. All pins are also broken out to a breadboard-friendly header and to a TFT connector. Connecting the display to a D32 Pro (that also has a TFT connector) now requires only one (special) cable! The picture shows the connector’s pinout.


The 320×240 display uses the well-proven ili9341 chip, for which I already wrote a lot of sketches, both for esp8266 and esp32 boards. The XPT2046 library can be used to drive the touch screen.

I tested several sketches on a plugged-in Mini Pro, as well as a TFT cable-connected D32 Pro, and everything worked fine. Example sketches on the Wemos site use Adafruit’s ili9341 library, but I prefer the much faster TFT_eSPI library with built-in touch screen support.

Here’s a video showing the display in action:


Conclusion: this is a well-thought product that makes solderless wiring very convenient and stable. Recommended!



Quest for Fire

By no means a gamer myself, I’ve always been interested in the math behind the graphics in video games. A previous post showed how simple clouds can be produced by the Diamond-Square algorithm, running on an esp8266. That algorithm can generate maps and landscapes as well.

Another visual effect on my todo list was algorithmically simulated fire.


The video shows my first attempt on a small TFT display. I had to write a relatively simple algorithm, because it needs to run on a microcontroller. Some further experimenting with the color palette, weighting factors and randomization, as well as adding Perlin noise, will hopefully result in a more realistic fire. I also plan to add a rotary encoder for regulating the ‘fire’.

[Update: a newer version is here]

Visual memory

Soon after my start with Arduino, I bought an external 32KB EEPROM, just in case a future project would need more memory than the board’s modest SRAM. But when I finally needed it for a sketch, I realized that the 300 KByte RAM of my 480×320 TFT display could be used for this purpose as well.

I had used pixels as memory before in visualisations of IFS fractals, where I made each pixel keep track of the number of times it was ‘hit’ by the iteration process, and then color it accordingly. Recent examples are this autumn inspired version of Barnsley’s Fern and this conifer-like fractal, based on an example on Ken Brakke’s IFS page. Both fractals were produced by an esp8266 on a 320×240 TFT display (ili9341).

Using a display as external memory for projects brings memory intensive algorithms, like the A* path search algorithm for my 15-Puzzle project, within reach of Arduino and ESP boards without PSRAM. The only prerequisite is that your display library lets you read single pixel values. Bonus: leaving the display’s backlight on will show a ‘brain scan’ of the sketch in progress.


Newton fractal

Here’s another famous fractal that I wanted to try on Arduino: the Newton fractal. It’s named after Isaac Newton’s iterative method for finding roots of functions. The classic example applies the method to function f(z) = z3 – 1 , where z is a complex number. This function has three roots in the complex plane.

classic newton fractal

The sketch that produced this picture loops over the pixels of a 480×320 display, mapping each of them to a complex number z0, that will serve as the initial value for Newton’s iteration process:

zn+1 = zn – f(zn) / f'(zn)

The basic color of a pixel (red, green or blue) depends on to which of the three roots the process converges. Its color intensity depends on the number of iterations that were needed to reach that root within a pre-defined precision. It’s just that simple!

Apart from playing with different color mappings (always essential for producing visually appealing fractals), I wanted to use modified versions of Newton’s method, as well as to apply them to different functions. The Arduino core has no support for complex calculus, and a library that I found didn’t even compile. So I wrote a couple of basic complex functions and put them in a functions.h file. There must better ways, but it works for me.

Once you have a basic sketch, the canvas of complexity is all yours!



f(z) = z4 – 1


This is my functions.h file. It must be in the same folder as the fractal sketch.


And here’s the Newton fractal sketch. Note the #include “functions.h” on the first line.



Snowflakes & Clouds

I haven’t been working on larger projects for a while, so here’s a couple of recent chips from the workbench.

In my ongoing quest for a faster HX8357D display driver, I was excited to read that the fast TFT_eSPI library now claims to support this beautiful but rather slow display. Unfortunately, the results were disappointing (unstable, readPixel freezes the screen). However, a nice bycatch of my experiments was the discovery that display updates become noticeably faster when the esp8266’s runs at 160MHz. Very useful for my fractal sketches, and for faster aircraft position updates on the Flight Radar‘s map.

Then I wondered how fast an esp8266 could actually drive my ili9341 driven 320×240 display. So I used my fast ‘offset-modulo’ Koch Snowflake algorithm for a snowflake animation speed test.

The result: an esp8266 at 160MHz can draw more than 100 (iteration depth 3) snowflakes per second on an ili9341 display, using the TFT_eSPI library. That’s about 5x faster than Adafruit’s HX8357 library can achieve on my 480×320 display. Hopefully, there will be a fast and reliable library for that display some day. Update: the TFT_eSPI library now supports driving the HX8457 in parallel mode and the results are impressive.


My renewed attention to the Koch Snowflake led to the discovery of a fractal that was new to me: the Plasma fractal. A commonly used algorithm to produce it is the Diamond-square algorithm. It’s apparently being used to generate nature-like backgrounds for video games.

I wrote a small demo sketch that produces random clouds (well, sort of…), but it can also be used to produce (non-musical) rock formations or landscapes.

6 samples of randomly generated clouds

(picture quality suffers from camera pixel interference with the TFT display)


The Diamond-square algorithm assigns initial values to the four corners of a (2n+1)x(2n+1) grid. Then it starts a process of calculating the remaining elements of the grid, based on neighbour values and a random noise of decreasing magnitude. The visual result depends on the four initial corner values, the random noise and the chosen color mapping.

The name Plasma fractal becomes clear when we show consecutive results in a loop. While still using random noise, the trick is to initialize the random generator with the same seed value for every new loop cycle. By slightly changing the initial corner values for each new cycle, the results will also be slightly different from the previous one, which is exactly what we want for a smooth animation.

The general formula that I used for initializing corner k with value h[k] is:

h[k] = d[k] + a[k]*sin( t*f[k] )   where t is a loop counter.

So the value of corner k will periodically swing around value d[k] with amplitude a[k]. The period of the swing is determined by f[k].

Now we can play with the d, a and f values for each corner, as well as with the color mapping, in order to find visually appealing animations. Here’s a first impression (esp8266 & ili9341 320×240 display). The sketch uses a 65×65 grid, with every point filling a corresponding 3×4 rectangle on the display with it’s color value. Since grid values are stored in 4-byte float variables, a 129×129 grid would become too large for the esp8266.


Used values:


Color mapping: