If you have not yet set up a settings.toml file in your CIRCUITPY drive and connected to the internet using it, follow the directions in the Create Your settings.toml File and Internet Connect! pages in this guide.

You will need your Adafruit IO username, and Adafruit IO key. Head to io.adafruit.com and simply click the View AIO Key link on the left hand side of the Adafruit IO page to get this information.

Then, add them to the settings.toml file:

CIRCUITPY_WIFI_SSID = "your_wifi_ssid"
CIRCUITPY_WIFI_PASSWORD = "your_wifi_password"
AIO_USERNAME = "your_aio_username"
AIO_KEY = "your_aio_key"

Add CircuitPython Code and Project Assets

In the embedded code element below, click on the Download Project Bundle button, and save the .zip archive file to your computer.

Then, uncompress the .zip file, it will unpack to a folder named PyPortal_Smart_Thermometer.

Copy the contents of the PyPortal_Smart_Thermometer directory to your PyPortal CIRCUITPY drive.

Make sure to save the fonts (Ninito-Black-17.bdf and Ninito-Light-75.bdf) into the fonts folder on the CIRCUITPY volume and save pyportal_splash.bmp into the icons folder.

# SPDX-FileCopyrightText: 2019 Brent Rubell for Adafruit Industries
# SPDX-License-Identifier: MIT

PyPortal Smart Thermometer
Turn your PyPortal into an internet-connected
thermometer with Adafruit IO

Author: Brent Rubell for Adafruit Industries, 2019
import time
import board
import neopixel
import busio
from digitalio import DigitalInOut
from analogio import AnalogIn
import adafruit_adt7410

from adafruit_esp32spi import adafruit_esp32spi, adafruit_esp32spi_wifimanager
from adafruit_io.adafruit_io import IO_HTTP, AdafruitIO_RequestError

# thermometer graphics helper
import thermometer_helper

# rate at which to refresh the pyportal screen, in seconds

# Get wifi details and more from a secrets.py file
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in secrets.py, please add them there!")

# PyPortal ESP32 Setup
esp32_cs = DigitalInOut(board.ESP_CS)
esp32_ready = DigitalInOut(board.ESP_BUSY)
esp32_reset = DigitalInOut(board.ESP_RESET)
spi = busio.SPI(board.SCK, board.MOSI, board.MISO)
esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset)
status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2)
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)

# Set your Adafruit IO Username and Key in secrets.py
# (visit io.adafruit.com if you need to create an account,
# or if you need your Adafruit IO key.)
    ADAFRUIT_IO_USER = secrets['aio_username']
    ADAFRUIT_IO_KEY = secrets['aio_key']
except KeyError:
    raise KeyError('To use this code, you need to include your Adafruit IO username \
and password in a secrets.py file on the CIRCUITPY drive.')

# Create an instance of the IO_HTTP client

# Get the temperature feed from Adafruit IO
temperature_feed = io.get_feed('temperature')

# init. graphics helper
gfx = thermometer_helper.Thermometer_GFX(celsius=False)

# init. adt7410
i2c_bus = busio.I2C(board.SCL, board.SDA)
adt = adafruit_adt7410.ADT7410(i2c_bus, address=0x48)
adt.high_resolution = True

# init. the light sensor
light_sensor = AnalogIn(board.LIGHT)

def set_backlight(val):
    """Adjust the TFT backlight.
    :param val: The backlight brightness. Use a value between ``0`` and ``1``, where ``0`` is
                off, and ``1`` is 100% brightness.
    val = max(0, min(1.0, val))
        board.DISPLAY.auto_brightness = False
    except AttributeError:
    board.DISPLAY.brightness = val

while True:
    # read the light sensor
    light_value = light_sensor.value
    print('Light Value: ', light_value)
    # read the temperature sensor
    temperature = adt.temperature
    try: # WiFi Connection
        if light_value < 1000: # turn on the backlight
            print('displaying temperature...')
            # Get and display date and time form Adafruit IO
            print('Getting time from Adafruit IO...')
            datetime = io.receive_time()
            print('displaying time...')
        else: # turn off the backlight
        try: # send temperature data to IO
            gfx.display_io_status('Sending data...')
            print('Sending data to Adafruit IO...')
            io.send_data(temperature_feed['key'], temperature)
            print('Data sent!')
            gfx.display_io_status('Data sent!')
        except AdafruitIO_RequestError as e:
            raise AdafruitIO_RequestError('IO Error: ', e)
    except (ValueError, RuntimeError, ConnectionError, OSError) as e:
        print("Failed to get data, retrying\n", e)

This is what the final contents of the CIRCUITPY drive will look like:

If you run into any errors, such as "ImportError: no module named `adafruit_display_text.label`" be sure to update your libraries to the latest release bundle!

Libraries Used

The following libraries are used in this project. So grab them and install them into CIRCUITPY/lib now!

  • adafruit_esp32spi - This is the library that gives you internet access via the ESP32 using (you guessed it!) SPI transport. You need this for anything Internet
  • adafruit_requests - This library allows us to perform HTTP requests and get responses back from servers. GET/POST/PUT/PATCH - they're all in here!
  • adafruit_pyportal - This is our friendly wrapper library that does a lot of our projects, displays graphics and text, fetches data from the internet. Nearly all of our projects depend on it!
  • adafruit_touchscreen - a library for reading touches from the resistive touchscreen. Handles all the analog noodling, rotation and calibration for you.
  • adafruit_io - this library helps connect the PyPortal to our free datalogging and viewing service
  • adafruit_imageload - an image display helper, required for any graphics!
  • adafruit_display_text - not surprisingly, it displays text on the screen
  • adafruit_bitmap_font - we have fancy font support, and its easy to make new fonts. This library reads and parses font files.
  • adafruit_slideshow - for making image slideshows - handy for quick display of graphics and sound
  • neopixel - for controlling the onboard neopixel
  • adafruit_adt7410 - library to read the temperature from the on-board Analog Devices ADT7410 precision temperature sensor
  • adafruit_sdcard - support for reading/writing data from the onboard SD card slot.
  • adafruit_bus_device - low level support for I2C/SPI

Code Usage

Your PyPortal will boot up to a splash screen displaying the PyPortal logo along with the Analog Devices and Adafruit IO logos.

While the PyPortal seems like it's just displaying a splash screen - it is doing a lot of work behind the scenes! The PyPortal is loads in the two fonts this project requires and sets up labels for displaying text.

Wave your hand in front of the PyPortal's light sensor to turn on the display's backlight!

Your PyPortal Thermometer will display the current temperature reading, pull in the date and time from Adafruit IO (based off of your IP address), and send the data to Adafruit IO.

When it finishes sending data, it'll turn the display back off but continue to send data to Adafruit IO.

Why is the backlight off by default?

When the backlight is turned on, it produces heat. This interferes with the ADT7410's ambient temperature readings. 

Adafruit IO Usage

While the PyPortal thermostat can display its temperature along with the current date/time on its screen - what if you're physically away from the thermostat?

How do we know that the temperature data is being sent from the thermostat to Adafruit IO?

Open the Adafruit IO Dashboard you created earlier. Notice that the fill and values of the gauge changes as values are sent from your PyPortal to Adafruit IO.

Then, leave the PyPortal running for a while and come back later to see new data appear on the line graph.

PyPortal Customization

Displaying temperature in Fahrenheit 

Live in a region where Fahrenheit is the standard? The thermometer_helper can handle displaying the temperature as either Fahrenheit or Celsius.

To display the temperature in Fahrenheit, modify the following line in code.py from:

gfx = thermometer_helper.Thermometer_GFX()


gfx = thermometer_helper.Thermometer_GFX(celsius=False)

Changing fonts

Want to use a different font? The fonts for this project are referenced at the top of the thermometer_helper.py file as info_font and temperature_font

The PyPortal reads .BDF (bitmap distribution format) fonts, so you'll need to convert a font into this format, and then modify the code to use the new font.

For more information about converting fonts, read the learning guide here...

Custom Wall Mount

The wall mount used in this project PyPortal was created by the Ruiz Brothers. For detailed instructions about how to print your own, check out the learning system guide here.

This guide was first published on Mar 22, 2019. It was last updated on May 22, 2024.

This page (Code PyPortal with CircuitPython) was last updated on May 21, 2024.

Text editor powered by tinymce.