Zonnestroompanelen in Nederland

duurzaamheid achter de meter

(48) My ESP32-WROOM-32 -ILI9341 TFT OpenWeatherMap station

by Floris Wouterlood – The Netherlands – April 3, 2021

This paper discusses the software programming of an Arduino weather station based on an ESP32-WROOM-32 microcontroller board that powers a 3.2 inch ILI9341 TFT display (320×240 pixels, 16-bit color). Local / regional weather data are downloaded from an OpenWeatherMap server in the form of a JSON object, processed and displayed.

Information about the weather is available from a variety of sources. For people living in Western Europe with its ever changing weather situations easy access to this kind of information can be very handy.
One can distinguish ‘microclimate registration stations’ that typically collect interesting data in the immediate environment of a person, say inside or immediately around the home, while inside that home maybe in a particular room, office, basement or attic. For this purpose a simple Arduino can be wired with a range of sensors designed to measure environmental parameters like barometric pressure, temperature, humidity, CO2, light intensity, UV radiation, fine dust and so forth. I built several of such ‘microclimate’ data collecting, displaying and logging indoor Arduino-based devices. Examples are a desktop room climate station* and a ‘sniffer box**.
One can also distinguish a true ‘weather station’ that reports regional, national or even continental weather conditions.
The challenge here is to build one’s own weather station that uses information picked up from the internet. There are several weather services and airports that continuously broadcast weather reports. Relatively new are internet services and private companies such as OpenWeatherMap, an open source community. OpenWeatherMap makes these data available as JSON strings that can be parsed and then processed and forwarded to a display. To achieve this is the purpose of the present project. The hardware platform is the ESP32-WROOM32-ILI9341 TFT display test bench published on TheSolarUniverse at WordPress.com on March 1, 2021*** (figure 1). The ESP32 microcontroller platform is particularly attractive because is is fast, budget-friendly, has much more memory than a common Arduino, is fully supported by the Arduino IDE, has wifi on board and is supported by powerful libraries for internet connectivity and for display. Especially mentioned here should be Bodmer’s extensive ‘TFT_eSPI’ library. A nice sketch snippet for display is the Rainbow Circular Scale Gauge, earlier published by Bodmer****.

TFT displays equipped with ILI9143 controller

figure 1. Weather station running on the test bench: ESP32-WROOM-32 microcontroller board and a 3.2 inch 320*240 TFT display with ILI9341 controller. JSON data obtained from OpenWeatherMap are presented numerically and with several gauges.

ESP82 microcontroller boards support displays that are much larger than OLEDs. Displays that I experience as matching the ESP32 very well are the 2.8” or 3.2” TFT displays with an ILI9341 controller chip and SPI interface. The ILI9341 is a fast controller whose graphical functionality is fully supported by a library written specifically for ESP32 microcontroller support by Bodmer: “TFT_eSPI.h”. This library can be installed in your Arduino IDE via the IDE’s Library manager.

Wiring of an ILI9341 SPI TFT display with an ESP32-WROOM-32
An ILI9341 SPI TFT display has a single row of 14 pins (figure 2). Eight of these pins are used to control the display while the remaining serve touch functionality and SD card support. The pinout of the display is presented as a table in figure 2. This is the wiring used in the current weather station.
The display shown in figures 1 and 2 has a touch screen. The pins supporting ‘touch’ as well as the pins connecting the SD card reader are not connected: we concentrate on displaying text, variables, graphics and fast sequences of bitmaps (‘image frames’).

figure 2. 14-pin SPI TFT with wiring scheme and pin connection table. the microcontroller board is an ESP32-WROOM32.


OpenWeatherMap.org is a company specialized in the distribution of global weather data (https://openweathermap.org). Data for 200,000 locations on earth is continuously available. Although the firm offers a repertoire of (mostly) commercial products, one of their services is a free subscription to a limited amount of weather data, say a ‘teaser’. One can obtain a free API, capped to a generous 60 calls per minute or a one million calls per month. Perfect for the hobbyist.
Once one has registered at OpenWeatherMap.org and an API key has been obtained, software programming can start.

Structure of the weather station sketch
In brief, the weather station sketch proceeds through the following steps:

in void setup ():
1. Establish a connection with the local wifi network,
2. Setup the display and construct the static elements of the graphical presentation through the function ‘drawAllWindowFrames ()’,
3. Run the function ‘doTheHardWork ()’ which – as its name implies – carries the workload:

3.1. Establish a connection with the server at www.openweathermap.org and download via a http-GET instruction the JSON document containing the regional weather data,
3.2. Calculate the dynamic elements of the graphical presentation,
3.3. Send results of these calculations to the upper part of the display as dynamic alphanumerical data.
3.4. Call functions that govern the various dials, charts and gauges. These are: rainbowScaleMeter ()’, ‘needleMeter ()’, ‘circleSegmentMeter ()’, ‘compassGauge ()’, ‘compassPointer ()’ and ‘windSectorReporter()’.

in void loop ():

In void loop a timer is set and the value of this timer forwarded to the function ‘doTheHardWork ()’. The timer is necessary to adhere to the conditions of the Openweathermap.org API

Parsing the JSON Document

The document received is a string in JSON notation. In my case:

JSON object = {“coord”:{“lon”:4.4931,”lat”:52.1583},”weather”: [{“id”:804,”main”:”Clouds”, “description”:”overcast clouds”, “icon”:”04d”}],”base”: “stations”,”main”:{“temp”:279.47, “feels_like”:277.62,”temp_min”:278.71, “temp_max”:279.82, “pressure”:1024, “humidity”:88}, “visibility”:10000, “wind”: {“speed”:0.89, “deg”:325, “gust”:1.34}, “clouds”: {“all”:100}, “dt”:1615904762, “sys”:{“type”:3, “id”:2009098, “country”: “NL”, “sunrise” :1615874031, “sunset”:1615916851}, “timezone”:3600, “id”:2751773, “name”:”Leiden”,”cod”:200}

If you transfer the coordinates “lon” and “lat” to Google Maps they cause the city center of my hometown: Leiden, The Netherlands, to be displayed on my computer’s screen.
Parsing of the downloaded string into JSON object-value pairs is performed by instructions in the library “Arduino_JSON.h”, and the only thing the current sketch does is to send the values of the objects “temp”, “pressure”, “humidity”, “wind” {“speed”} and “wind” {“deg”} to the display. Temperature is provided in degrees Kelvin, needing conversion to degrees Celsius (or degrees Fahrenheit if you wish). Wind speed is in meters per second and “deg” represents the compass direction where the wind comes from, with ‘0’ being North, 090 being East, 180 being South and 270 being West. Degrees need to be converted into radials wherever positions of needles or pointers in the graphical representation need to be calculated. Note also that the JSON string consists of an interesting set of data of which my weather station sketch selects only a few for display. All data are otherwise printed to Serial Monitor.

Display divided into windows
A screen 240 pixels wide and 320 pixels high has sufficient space to host several windows. Apart from the Title frame the screen is in the current sketch subdivided into seven subscreens, each surrounded by a frame. In void Setup() the function ’drawAllWindowFrames ()’ is called that contains the TFT_eSPI instructions to generate window frames. These frames are drawn with rounded corners: tft.drawRoundRect (x,y,width, height, radius of corner quarter circle). One frame is reserved for the alphanumerical representation and four frames serve graphical gauges.

Dynamic alphanumerical weather data
Figure 3 highlights the upper left part of the display where selected dynamic weather data are printed in white color: temperature, barometric pressure, humidity, wind speed and wind direction. The characters printed in yellow are the static elements in this window.

Font: The default font of the ILI9341 does not spectacularly catch the eye. Fortunately the TFT_eSPI.h library is accompanied with several font libraries that contain more pleasing fonts than the ILI3941 default font. Here used is the font “FF1“ defined in the library “Free_fonts.h” Note that a copy of this font library needs to be present in the folder containing the weather station sketch.

figure 3: Alphanumerical window of the display.

Scales and gauges

figure 4. Rainbow scale temperature gauge window.

Rainbow scale
The left half of the display contains the alphanumerical window and the window showing Bodmer’s Rainbow Scale Gauge (figure 4). This gauge consists of a series of circularly arranged segments. Segments are built up in the function ‘ringMeter ()’. Each segment consists of two triangles whose colors are controlled by a function called ‘rainbow ()’. The higher the temperature, the more segments become colored, with yellow in the lower temperature segments transforming to red colored segments at high temperatures. The rainbow scale range is set in the sketch between zero and 50 degrees Celsius. With outside temperatures below the freezing point the scale segments remain in neutral color while the numerical value is displayed with a minus sign.

Wind compass gauge

figure 5. Wind compass gauge.

The right upper window in the display graphically represents the wind direction: the wind compass gauge (figure 5). On top of the compass gauge window is a small window that contains the alphanumerical wind sector indicator.
The sketch contains three functions governing this part of the graphical presentation: ‘compassGauge ()’, ’compassPointer ()’, and ’windSectorReporter ()’. ‘CompassGauge ()‘ constructs the graphical compass while ‘compasPointer()‘ calculates the position of the compass indicator and the wind sector. Feed for ‘compassPointer ()‘ is the JSON object “deg”. The value of “deg” is transferred to the variable windDir.
The compass indicator consists of two triangles positioned back-to-back. They share the tip: x and y coordinates for the tip are calculated from windDir. The wind sector reporter determines which sector of the compass rose corresponds with the windDir via a series of ‘if’ instructions.

Humidity gauges
Two humidity gauge windows are incorporated in the right lower sector of the display: a humidity indicator with a needle and a visual indicator based on a circular pie chart gauge (figure 6).

Needle indicator
The challenge here was to control the needle angle (0-90 degrees) that covers a 60-unit trajectory, i.e., between 40% and 100% humidity, in a 90-degrees space. Further, the needle should turn counterclockwise while default needle indicator rotations are clockwise. The needle indicator is built up via two functions, one constructing the static portion: ‘drawScaleSmallGauge ()’, and the function ‘needleMeter ()’ that controls actual needle movement .
The value of the JSON object “humidity” is transferred to the float parameter ‘hum_01’ which in turn is converted into an int variable ‘hum_02’ because the gauge is too coarse to report decimals. Hum_02 is fed into the function that constructs the angle of the reporting needle.

fiugre 6. Humidity gauges

Pie chart humidity indicator
A visually attractive way of presenting percentages is the pie chart. While complete filled circles are easy to draw via the ‘tft.fillCircle ()’ function, the drawing of a pie chart has its own challenges. One may for instance draw a complete color filled circle and then superimpose a black segment. Another way is to draw a background color circle and then fill part of it – a sector – with (360-n) radials where n corresponds with the percentage reported relative humidity. This what the current sketch does.
Also in this part of the sketch there is a function that controls the static part of the operation: ‘circleSegmentMeter ()’, and a function constructing the actual pie segment: ‘fillSegments ()’.

Note on using the TFT_eSPI library
Workflow with the TFT_eSPI library works differently than with other libraries. A main difference is that the TFT display’s controller is defined in a custom user setup file that is saved in the library folder. How to proceed with a workflow once you have installed the TFT_eSPI library has been described in the post ‘ESP32-WROOM-32 and ILI9341 TFT display – an interesting match’ ***.

Note that the sketch needs seven libraries for compilation:
#include “ArduinoJson.h>
#include “SPI.h”
#include “TFT_eSPI.h”
#include “WiFi.h”
#include “HTTPClient.h”
#include “Arduino_JSON.h”
#include “Free_Fonts.h”


Sketch named ‘ESP32_ILI9341_openweathermap.ino
This sketch is packed in a ZIP file.

The folder included in the ZIP file also has “Free_Fonts.h” as that library is required to display text in ‘mono’ font.


*An 128×64 graphic LCD display with ST7920 controller for the Arduino, displaying temperature and relative humidity  – Thesolaruniverse.wordpress.com – august 11, 2017.

**Sniffer box 2: updated portable weather station with ESP8266-wifi – Thesolaruniverse.wordpress.com – February 7, 2021.

***ESP32-WROOM-32 and ILI9341 TFT display, an interesting match – Thesolaruniverse.wordpress.com – March 1, 2021.

***Arduino Analogue ‘ring’ Meter on Colour TFT Display – Bodmer – Instructables com, March 17, 2015
url: https://www.instructables.com/Arduino-analogue-ring-meter-on-colour-TFT-display/