# Mini Weather Station ESP32-S3 TFT

## Overview

![](https://cdn-learn.adafruit.com/assets/assets/000/119/312/medium800/lcds___displays_miniStation2.jpg?1678377829)

Is the weather outside delightful or frightful?&nbsp; With the ESP32-S3 TFT, you can design a small weather monitor that displays the existing temperature, the highest and lowest temperatures of the day, and the current weather condition.

Using the ESP32-S3 TFT&nbsp;WiFi capabilities, you will be able to&nbsp;use the [OpenWeatherMap API](https://openweathermap.org/) and extract weather information. Once you've examined the information, you can showcase the current temperature, location, and daily highs and lows.

## Parts
### Adafruit ESP32-S2 TFT Feather - 4MB Flash, 2MB PSRAM, STEMMA QT

[Adafruit ESP32-S2 TFT Feather - 4MB Flash, 2MB PSRAM, STEMMA QT](https://www.adafruit.com/product/5300)
We've got a new machine here at Adafruit, it can uncover your deepest desires. Don't believe me? I'll turn it on right now to prove it to you! What, you want unlimited mozzarella sticks? OK well, that's not something we can provide. But we can provide your...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5300)
[Related Guides to the Product](https://learn.adafruit.com/products/5300/guides)
![Adafruit ESP32-S2 TFT Feather powered on by a USB- C power source displaying the product tittle in a red, yellow, green, white and blue. ](https://cdn-shop.adafruit.com/640x480/5300-06.jpg)

### Lithium Ion Battery - 3.7V 2000mAh

[Lithium Ion Battery - 3.7V 2000mAh](https://www.adafruit.com/product/2011)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 2000mAh. If you need a larger (or smaller!) battery,&nbsp;<a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/2011)
[Related Guides to the Product](https://learn.adafruit.com/products/2011/guides)
![Lithium Ion Polymer Battery 3.7v 2000mAh with JST 2-PH connector](https://cdn-shop.adafruit.com/640x480/2011-05.jpg)

### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

In Stock
[Buy Now](https://www.adafruit.com/product/4474)
[Related Guides to the Product](https://learn.adafruit.com/products/4474/guides)
![Angled shot of a coiled black, USB-C to USB-A cable.](https://cdn-shop.adafruit.com/640x480/4474-02.jpg)

# Mini Weather Station ESP32-S3 TFT

## CircuitPython

[CircuitPython](https://github.com/adafruit/circuitpython) is a derivative of [MicroPython](https://micropython.org) designed to simplify experimentation and education on low-cost microcontrollers. It makes it easier than ever to get prototyping by requiring no upfront desktop software downloads. Simply copy and edit files on the **CIRCUITPY** drive to iterate.

## CircuitPython Quickstart

Follow this step-by-step to quickly get CircuitPython running on your board.

[Download the latest version of CircuitPython for this board via circuitpython.org](https://circuitpython.org/board/adafruit_feather_esp32s2_tft/)
 **Click the link above to download the latest CircuitPython UF2 file.**

Save it wherever is convenient for you.

![install_circuitpython_on_most_boards_CircuitPython_downloaded.jpg](https://cdn-learn.adafruit.com/assets/assets/000/102/129/medium640/install_circuitpython_on_most_boards_CircuitPython_downloaded.jpg?1620922559)

![](https://cdn-learn.adafruit.com/assets/assets/000/107/769/medium800/adafruit_products_FTFT_reset_NeoPixel.jpg?1641925114)

Plug your board into your computer, using a known-good data-sync cable, directly, or via an adapter if needed.

Double-click the **reset** button (highlighted in red above), and you will see the **RGB status LED(s)** turn green (highlighted in green above). If you see red, try another port, or if you're using an adapter or hub, try without the hub, or different adapter or hub.

For this board, tap reset and wait for the LED to turn purple, and as soon as it turns purple, tap reset again. The second tap needs to happen while the LED is still purple.

If you do not see the LED turning purple, you will need to reinstall the UF2 bootloader. See the&nbsp; **Factory Reset** &nbsp;page in this guide for details.

If double-clicking doesn't work the first time, try again. Sometimes it can take a few tries to get the rhythm right!

A lot of people end up using charge-only USB cables and it is very frustrating! **Make sure you have a USB cable you know is good for data sync.**

You will see a new disk drive appear called **FTHRS2BOOT**.

&nbsp;

Drag the **adafruit\_circuitpython\_etc.uf2** file to **FTHRS2BOOT**.

![adafruit_products_FTFT_FTHRS2BOOT.png](https://cdn-learn.adafruit.com/assets/assets/000/107/771/medium640/adafruit_products_FTFT_FTHRS2BOOT.png?1641926447)

![adafruit_products_FTFT_drag_UF2.png](https://cdn-learn.adafruit.com/assets/assets/000/107/772/medium640/adafruit_products_FTFT_drag_UF2.png?1641926456)

The **BOOT** drive will disappear and a new disk drive called **CIRCUITPY** will appear.

That's it!

![install_circuitpython_on_most_boards_CIRCUITPY.jpg](https://cdn-learn.adafruit.com/assets/assets/000/102/130/medium640/install_circuitpython_on_most_boards_CIRCUITPY.jpg?1620923145)

# Mini Weather Station ESP32-S3 TFT

## OpenWeather Maps API

![](https://cdn-learn.adafruit.com/assets/assets/000/119/314/medium800/lcds___displays_openweatherss.png?1678449759)

## Open Weather Maps API Key

We'll be using [OpenWeatherMaps](https://openweathermap.org/) to retrieve the weather info through its API. To do so, you'll need to register for an account and get your API key.

Go to this&nbsp;[link](https://home.openweathermap.org/users/sign_up)&nbsp;and register for a **free** account. Once registered, you'll get an email containing your API key, known as the "openweather token."

# Mini Weather Station ESP32-S3 TFT

## Setting up your Credentials 

### Making a settings.toml file

The Mini Weather Station&nbsp;depends on you adding your WiFi and OpenWeatherMaps token to fetch JSON weather data.

Plug your Feather board into your computer via a known good data + power USB cable. Your board should show up as a thumb drive in your File Explorer / Finder (depending on your operating system) named **CIRCUITPY**.

Create a file with the name&nbsp; **settings.toml** &nbsp;in the root directory of the&nbsp; **CIRCUITPY** &nbsp;drive.

Add the following below:

The file should contain the keys&nbsp;`CIRCUITPY_WIFI_SSID`, &nbsp;`CIRCUITPY_WIFI_PASSWORD`, `CIRCUITPY_WEB_API_PASSWORD`,&nbsp; and&nbsp;`OPENWEATHER_KEY`. You must also include your state and country initials with the `LOCATION` key.&nbsp;

Once these are defined, CircuitPython will automatically connect to the network and start the webserver used for the workflow.

The web server is on port 80 unless overridden by&nbsp;`CIRCUITPY_WEB_API_PORT`. It also enables MDNS.

Here is an example&nbsp; **settings.toml** :

```auto
# To auto-connect to WiFi
CIRCUITPY_WIFI_SSID="YOUR-WIFI-NETWORK-NAME"
CIRCUITPY_WIFI_PASSWORD="YOUR-WIFI-NETWORK-PASSWORD"

# For OpenWeather API
OPENWEATHER_KEY="A-LONG-STRING-OF-INTS-AND-CHARACTERS"
LOCATION="New York, US"

# To enable modifying files from the web. Change this too!
# Leave the User field blank in the browser.
CIRCUITPY_WEB_API_PASSWORD="passw0rd"

CIRCUITPY_WEB_API_PORT=80
```

# Mini Weather Station ESP32-S3 TFT

## Using PyLeap

[![wearables_IMG_1660.png](https://cdn-learn.adafruit.com/assets/assets/000/118/374/medium800/wearables_IMG_1660.png?1675965441)](https://learn.adafruit.com/assets/118374)  
You can quickly transfer this project to your device using the PyLeap app.

[PyLeap](https://learn.adafruit.com/pyleap-app)&nbsp;is a free app available for iOS, iPad, and Android devices. It can be downloaded from the&nbsp;[Apple App Store](https://learn.adafruit.com/pyleap-app)&nbsp;or&nbsp;[Google Play Store](https://play.google.com/store/apps/details?id=com.adafruit.pyleap). It allows users to easily download code files and assets and transfer them to their Adafruit devices using Bluetooth Low Energy (BLE) or WiFi.

&nbsp;

To upload a project to your PyLeap-enabled device, select the project in the project list.&nbsp;

![](https://cdn-learn.adafruit.com/assets/assets/000/119/379/medium800/lcds___displays_IMG_1852.png?1678469568)

![](https://cdn-learn.adafruit.com/assets/assets/000/119/381/medium800/lcds___displays_IMG_1853.png?1678469659)

Then, once the project cell has collapsed, press the "Run it" button to download and transfer the project over to your PyLeap-enabled device.

# Mini Weather Station ESP32-S3 TFT

## PyLeap Mini Weather Station Code

![](https://cdn-learn.adafruit.com/assets/assets/000/119/313/medium800/lcds___displays_miniStation3.jpg?1678382151)

https://github.com/adafruit/Adafruit_Learning_System_Guides/blob/main/ESP32-S2_TFT_Mini_Weather_Station/code.py

This code is&nbsp;doing several things:

- Connecting to the internet via WiFi using your credentials
- Create a label for displaying temperature data
- Set up the background image for the current weather condition
- Fetch weather data from OpenWeatherMap API
- Extract temperature and weather condition data from the API response

## Connecting to WiFi

This code block connects to a WiFi network using the&nbsp;`wifi.radio.connect`&nbsp;function and passes in the network’s SSID and password as arguments from your credentials. The values of the SSID and password are read from environment variables&nbsp;`CIRCUITPY_WIFI_SSID`&nbsp;and&nbsp;`CIRCUITPY_WIFI_PASSWORD.`&nbsp;

```auto
try:
    wifi.radio.connect(
        os.getenv("CIRCUITPY_WIFI_SSID"), os.getenv("CIRCUITPY_WIFI_PASSWORD")
    )
    print("Connected to %s!" % os.getenv("CIRCUITPY_WIFI_SSID"))
except Exception as e:  # pylint: disable=broad-except
    print(
        "Failed to connect to WiFi. Error:", e, "\nBoard will hard reset in 30 seconds.")
```

If you haven't set up your credentials, go back here.

## Creating a Socket Pool

The&nbsp;`socketpool.SocketPool`&nbsp;function creates a pool of sockets for managing network connections. It takes the&nbsp;`wifi.radio`&nbsp;object as an argument to allow for network communication over a WiFi connection.

You will also need to create session object for making HTTP requests using `adafruit_requests.Session`.

```python
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
```

### Set up the URL for fetching weather data

Set a variable for the&nbsp;`DATA_SOURCE`,&nbsp;which will be used to query Open Weather Maps API next. This query will use the&nbsp;`LOCATION`&nbsp;and&nbsp;`UNITS`&nbsp;variables to form the request. The value of the `OPENWEATHER_KEY` is read from the environment variable `OPENWEATHER_KEY` located in your **settings.toml** file.&nbsp;

```auto
DATA_SOURCE = (
    "http://api.openweathermap.org/data/2.5/weather?q="
    + LOCATION
    + "&units="
    + UNITS
    + "&mode=json"
    + "&appid="
    + os.getenv("OPENWEATHER_KEY")
)
```

Using this information, the code can then send a query to Open Weather Maps's API that looks something like this:

`http://api.openweathermap.org/data/2.5/weather?q=New York, US&units=metric&mode=json&appid=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`

## Adding a time interval&nbsp;

Create a `time_interval` variable to have a set time to have our weather station fetch weather data every 30 seconds.

```auto
# Define time interval between requests
time_interval = 3000  # set the time interval to 30 minutes
```

## Setting the background image

First, create a variable called `display` that refers to the display object provided by the board module. This allows you to interact with the display hardware.

Then, create a variable called `bitmap` that refers to the `displayio.OnDiskBitmap()` function that creates a bitmap object from an image file stored on disk. You'll add the image file **/images/sunny.bmp** &nbsp;as a default image.

For the third line of code, create a `tile_grid` variable that refers to the `displayio.TileGrid()` function that creates a grid of tiles to display the bitmap on the display.

In the fourth line, create a group object that will have a reference to a `Group` container that will append the `tile_grid`. A Group is a container object that can hold multiple display objects and allows you to manipulate them as a single unit.

```auto
display = board.DISPLAY
bitmap = displayio.OnDiskBitmap("/images/sunny.bmp")
tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader)

group = displayio.Group()
group.append(tile_grid)
```

## Setting up a label for displaying temperature data

Here you'll create a label for displaying temperature data, add it to a main group, and shows the main group on display.

Create a Label object called `text_area` using a built-in font from the `terminalio` module and sets its scale to 3 times the default size.

Next, set the label's `anchor_point` and `anchored_position` for the second and third lines.&nbsp;Set `anchor_point` to the center of the Label using a tuple of (0.5, 0.5).

The `anchored_position` is the position of the anchor point relative to the display. Set to the center of the display using the `//` operator to divide the display width and height by 2.

```auto
text_area = bitmap_label.Label(terminalio.FONT, scale=3)
text_area.anchor_point = (0.5, 0.5)
text_area.anchored_position = (display.width // 2, display.height // 2)
```

Next, creates a display group called `main_group` to hold both the `tile_grid` and the Label. The Tile Grid and Label are added to the group using the `append` method.

Finally, the last line in this code block shows the main group on the display by setting the `root_group` property of the display object to the `main_group`.

```python
main_group = displayio.Group()
main_group.append(group)
main_group.append(text_area)
# Show the main group on the display
display.root_group = main_group
```

This function, called `get_weather_condition_icon()`, takes a weather condition as input and returns a file path for the corresponding image to display its background image. We'll use this in the `set_background` function.

```python
def get_weather_condition_icon(weather_condition):
    if "cloud" in weather_condition.lower():
        return "/images/cloudy.bmp"
    elif "rain" in weather_condition.lower():
        return "/images/rain.bmp"
    elif "snow" in weather_condition.lower():
        return "/images/snowy.bmp"
    elif "clear" in weather_condition.lower():
        return "/images/sunny.bmp"
    else:
        return "/images/sunny.bmp"
```

This function called `set_background()` takes two parameters: a weather condition and a tile grid for the background image. The function updates the background image based on the weather condition by replacing the bitmap used by the tile grid. These functions will be used in the main loop.

```python
def set_background(weather_condition, background_tile_grid):
    bitmap_path = get_weather_condition_icon(weather_condition)
    background_bitmap = displayio.OnDiskBitmap(bitmap_path)
    background_tile_grid.bitmap = background_bitmap
```

# The Main Loop

## Fetching weather data from OpenWeatherMap API

This line of code sends a GET request to the OpenWeatherMap API using the `requests` library and retrieves the response as a JSON object. I'll also print this JSON data to see what information is coming in from the console.

```python
print("Fetching json from", DATA_SOURCE)
response = requests.get(DATA_SOURCE)
print(response.json())
```

These values are then converted from Kelvin to Fahrenheit, and the converted current temperature is printed to the console for debugging purposes.

```python
current_temp = response.json()["main"]["temp"]
max_temp = response.json()["main"]["temp_max"]
min_temp = response.json()["main"]["temp_min"]
current_weather_condition = response.json()["weather"][0]["main"]

print("Weather condition: ", current_weather_condition)

# Convert temperatures to Fahrenheit
max_temp = (max_temp * 9 / 5) + 32
min_temp = (min_temp * 9 / 5) + 32
current_temp = (current_temp * 9 / 5) + 32

# Convert temperatures to Fahrenheit to Celsius
# max_temp = (max_temp - 32) * 5/9
# min_temp = (min_temp - 32) * 5/9
# current_temp = (current_temp - 32) * 5/9
print("Current temperature: {:.1f} °F".format(current_temp))
```

Update label for displaying temperature data

```python
text_area.text = "{}\n     {:.0f}°F\nH:{:.0f}°F   L:{:.0f}°F".format(
LOCATION, round(current_temp), round(max_temp), round(min_temp))
```

Finally, the code sleeps for a fixed interval before fetching and displaying updated weather data.

```python
set_background(current_weather_condition, tile_grid)

time.sleep(time_interval)
```

## Having Problems Getting Data?

If you have problems getting the data to display correctly, check your settings. The **settings**. **toml** &nbsp;file has the information noted [here](https://learn.adafruit.com/mini-weather-station-esp32-s2-tft/setting-up-your-credentials).


## Featured Products

### Adafruit ESP32-S3 TFT Feather - 4MB Flash, 2MB PSRAM, STEMMA QT

[Adafruit ESP32-S3 TFT Feather - 4MB Flash, 2MB PSRAM, STEMMA QT](https://www.adafruit.com/product/5483)
We've got a new machine here at Adafruit, it can uncover your deepest desires. Don't believe me? I'll turn it on right now to prove it to you! What, you want your very own soft serve ice cream machine? OK well, that's not something we can provide. But we can provide your...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5483)
[Related Guides to the Product](https://learn.adafruit.com/products/5483/guides)
### Adafruit ESP32-S2 TFT Feather - 4MB Flash, 2MB PSRAM, STEMMA QT

[Adafruit ESP32-S2 TFT Feather - 4MB Flash, 2MB PSRAM, STEMMA QT](https://www.adafruit.com/product/5300)
We've got a new machine here at Adafruit, it can uncover your deepest desires. Don't believe me? I'll turn it on right now to prove it to you! What, you want unlimited mozzarella sticks? OK well, that's not something we can provide. But we can provide your...

Out of Stock
[Buy Now](https://www.adafruit.com/product/5300)
[Related Guides to the Product](https://learn.adafruit.com/products/5300/guides)
### Lithium Ion Battery - 3.7V 2000mAh

[Lithium Ion Battery - 3.7V 2000mAh](https://www.adafruit.com/product/2011)
Lithium-ion polymer (also known as 'lipo' or 'lipoly') batteries are thin, light, and powerful. The output ranges from 4.2V when completely charged to 3.7V. This battery has a capacity of 2000mAh. If you need a larger (or smaller!) battery,&nbsp;<a...></a...>

In Stock
[Buy Now](https://www.adafruit.com/product/2011)
[Related Guides to the Product](https://learn.adafruit.com/products/2011/guides)
### USB Type A to Type C Cable - approx 1 meter / 3 ft long

[USB Type A to Type C Cable - approx 1 meter / 3 ft long](https://www.adafruit.com/product/4474)
As technology changes and adapts, so does Adafruit. This&nbsp;&nbsp; **USB Type A to Type C** cable will help you with the transition to USB C, even if you're still totin' around a USB Type A hub, computer or laptop.

USB C is the latest industry-standard connector for...

In Stock
[Buy Now](https://www.adafruit.com/product/4474)
[Related Guides to the Product](https://learn.adafruit.com/products/4474/guides)

## Related Guides

- [Adafruit ESP32-S2 TFT Feather](https://learn.adafruit.com/adafruit-esp32-s2-tft-feather.md)
- [Adafruit ESP32-S3 TFT Feather](https://learn.adafruit.com/adafruit-esp32-s3-tft-feather.md)
- [Playing Animated GIF Files in CircuitPython](https://learn.adafruit.com/using-animated-gif-files-in-circuitpython.md)
- [Feather ESP32-S3 TFT CircuitPython Day 2024 Countdown Clock](https://learn.adafruit.com/feather-esp32-s3-tft-circuitpython-day-2024-countdown-clock.md)
- [USB Host to BLE Keyboard Adapter](https://learn.adafruit.com/esp32-s3-usb-to-ble-keyboard-adapter.md)
- [CircuitPython Web Workflow Code Editor Quick Start](https://learn.adafruit.com/getting-started-with-web-workflow-using-the-code-editor.md)
- [Sensor-Locked Secrets with CircuitPython](https://learn.adafruit.com/sensor-locked-secrets-with-circuitpython.md)
- [Blinka Says Tabletop Arcade Game](https://learn.adafruit.com/blinka-says-tabletop-arcade-game.md)
- [Adafruit IO Basics: Color](https://learn.adafruit.com/adafruit-io-basics-color.md)
- [PyLeap ESP32-S3 TFT Boxing Glove Tracker w/ Adafruit IO](https://learn.adafruit.com/esp32-s2-tft-boxing-glove-tracker-w-adafruit-io.md)
- [HID Reporter](https://learn.adafruit.com/hid-reporter.md)
- [Adafruit IO Basics: Analog Input](https://learn.adafruit.com/adafruit-io-basics-analog-input.md)
- [Raspberry Pi Azure IoT Hub Dashboard with CircuitPython](https://learn.adafruit.com/raspberry-pi-iot-dashboard-with-azure-and-circuitpython.md)
- [Integrating Color Sensors with itsaSNAP and HomeKit](https://learn.adafruit.com/integrating-color-sensors-with-itsasnap-and-homekit.md)
- [Circuit Playground Gizmo Ornaments](https://learn.adafruit.com/display-ornaments-with-circuit-playground.md)
- [Yoga Pose Chime](https://learn.adafruit.com/yoga-pose-chime.md)
