Munich subway tracker

Information is available every where, and can be used in so many ways.

Similar projects worth following
During my u-Bahn commutes I noticed this QR code in every station, which opens a web page with station, line and direction information. This info could be easily parsed and used to define when the subway arrives. After some more research using MVG new webpage I notice that it actually uses a JSON API (amazing, right?) which is much more efficiently parsed by the microcontroller. There is a python API that offers nearby stations based on geolocation, next departures for any station in the MVV, includes S-Bahn, Schienenersatzverkehr and also warnings about service interruptions.

Development was done using ESP32-WROVER, it fetches (using HTTPS) each station to collect data, then parse the JSON information. Now it knows when the subway should arrive, and to define current time it checks NTP for synchronization. Using addressable LED WS2812B, it can control RGB outputs with dimming. In other words, it will light up and LED according to the station when the subway arrives.

The inspiration for this project was traintrackr, at first I thought about using IS31FL3731 LED driver IC to control up to 144 LEDs with the built-in cross-plexing feature. The pros about using this IC is the small footprint, relatively easy to control, low current consumption and PWM, on the negative side I would have only one color. I designed a PCB for it, but I didn't like it.

Finally I decided to use WS2812B addressable LEDs, its RGB, easy to program, control brightness, easy to design the PCB and I also like the size of it. The only problem with those LEDs is the high current draw, each RGB LED draws approximately 50mA when it is set to full brightness and powered at 5V. This means that, for 96 train stations we turn on, our LED array could be drawing as much as 4.5A. Since this project is not powering up all LEDs at the same time, I designed the PCB with LM7805 (1.5A), which we could power 30 LEDs with maximum brightness. I did also some tests powering all LEDs, but using 40% of the brightness, it works very well and I had no problem at all.

To control everything the microcontroller selected was the ESP32 WROVER, WIFI was mandatory to fetch online data, it also works with ESP8266, but with ESP32 the code was running much faster to parse online data, and I could make use of tasks.

In Munich, all transport stations have this QR code, where you can scan and open an webpage with information about line, direction and arrival time, for example Petuelring stations:

Checking the source code of the webpage, its easy to find the information about the station, and also easy to parse using ESP32, specially because it was HTTP:

Well, that was the first plan, and it did work but was not the best approach, to get information from other stations I would have to write the hole name:

After some research I found the new webpage from MVG, where we have a similar feature to search the station information:

Using the JQuery AJAX Capture Chrome extension I saw this https url query.

Its the ID of the station plus services selected:

And there was the information, all available in JSON, much better to parse:

There is even an python library from MVG (amazing!) but I didn't use it. "A library for fetching departures, routes and service interruptions from Munich Transport Authority MVG, using the newer JSON-api on"

Nice, so now I can get information using JSON, but where to find all stations IDs? Well after some more searche, I found this webpage from MVV for developers:

There can download the list of all stations with name, global ID and other nice information.

The HTTPS GET now can be easily build:

const String urlHost = "";
const String urlquery = "?apiKey=aklKa290LsadOLW&sbahn=false&tram=false&bus=false";

String strHstGlobaleID = urlHost + String(hstGlobaleID[j]) + urlquery;

To parse JSON data using ESP32, I made use of the amazing ArduinoJson assistant, I simplified the JSON to get only the first 4 departure times of each station:

It also generates for you the parsing program:

const size_t capacity = JSON_ARRAY_SIZE(4) + 5*JSON_OBJECT_SIZE(1) + 80;
DynamicJsonDocument doc(capacity);

const char* json = "{\"departures\":[{\"departureTime\":1603563780000},{\"departureTime\":1603563960000},{\"departureTime\":1603564380000},{\"departureTime\":1603564560000}]}";

deserializeJson(doc, json);

JsonArray departures = doc["departures"];

long long departures_0_departureTime = departures[0]["departureTime"]; // 1603563780000

long long departures_1_departureTime = departures[1]["departureTime"];...
Read more »

Arduino IDE code

x-zip-compressed - 4.63 kB - 10/24/2020 at 20:51


lib_deps = bblanchon/ArduinoJson@^6.17.0 fastled/FastLED@^3.3.3 arduino-libraries/NTPClient@^3.1.0 paulstoffregen/Time@^1.6

x-zip-compressed - 31.06 MB - 10/24/2020 at 20:42


Gerber files for production

x-zip-compressed - 687.50 kB - 10/24/2020 at 19:11


Easyeda full project (SCH + LAYOUT)

x-zip-compressed - 808.96 kB - 10/24/2020 at 19:09


  • 96 × WS2812B RGB LED
  • 1 × ESP32-DevKitC-VB
  • 1 × LM7805 Power Management ICs / Linear Voltage Regulators and LDOs
  • 96 × 100nF capacitor

View project log

  • 1
    Project construction

View all instructions

Enjoy this project?



Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates