Setup PyPortal with CircuitPython
We'll need to get our PyPortal board setup so it can run CircuitPython code. Let's walk through these steps to get the latest version of CircuitPython onto your board
Mu is a simple Python editor that works with Adafruit CircuitPython hardware. It's written in Python and works on Windows, MacOS, Linux and Raspberry Pi. The serial console is built right in, so you get immediate feedback from your board's serial output! While you can use any text editor with your code, Mu makes it super simple.
Installing or upgrading CircuitPython
You should ensure you have CircuitPython 4.0 or greater on your board. Plug your board in with a known good data + power cable (not the cheesy USB cable that comes with USB power packs, they are power only). You should see a new flash drive pop up.
If the drive is CIRCUITPY, then open the boot_out.txt file to ensure the version number is 4.0 or greater.
You can download everything that you need for the PyPortal code by downloading the following Zip file and copying its contents to your PyPortals CIRCUITPY folder.
Adafruit CircuitPython 5.0.0-beta.0 on 2019-11-19; Adafruit PyPortal with samd51g19
Upload the Code and Files
Click on the Download Project Bundle button below to grab the main code and other files noted (except the library files) directly from GitHub (the repository is here). Drop the files onto the CIRCUITPY main (root) directory (with the font file in a fonts directory). The code will run properly when all of the files have been uploaded including libraries.
Use any text editor or favorite IDE to modify the code. We suggest using Mu as noted above.
# SPDX-FileCopyrightText: 2020 Anne Barela for Adafruit Industries
#
# SPDX-License-Identifier: MIT
from os import getenv
import board
import displayio
import busio
from digitalio import DigitalInOut
from analogio import AnalogIn
import neopixel
import adafruit_adt7410
import adafruit_connection_manager
from adafruit_esp32spi import adafruit_esp32spi
from adafruit_esp32spi import adafruit_esp32spi_wifimanager
from adafruit_bitmap_font import bitmap_font
from adafruit_display_text.label import Label
from adafruit_button import Button
import adafruit_touchscreen
import adafruit_minimqtt.adafruit_minimqtt as MQTT
# Get WiFi details, ensure these are setup in settings.toml
ssid = getenv("CIRCUITPY_WIFI_SSID")
password = getenv("CIRCUITPY_WIFI_PASSWORD")
if None in [ssid, password]:
raise RuntimeError(
"WiFi settings are kept in settings.toml, "
"please add them there. The settings file must contain "
"'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', "
"at a minimum."
)
# ------------- WiFi ------------- #
# If you are using a board with pre-defined ESP32 Pins:
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_pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2)
wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel)
# ------- Sensor Setup ------- #
# init. the temperature sensor
i2c_bus = busio.I2C(board.SCL, board.SDA)
adt = adafruit_adt7410.ADT7410(i2c_bus, address=0x48)
adt.high_resolution = True
temperature = "blaa"
# init. the light sensor
light_sensor = AnalogIn(board.LIGHT)
# init. the motion sensor
movement_sensor = DigitalInOut(board.D3)
button1_state = 0
button2_state = 0
# ------------- Screen eliments ------------- #
display = board.DISPLAY
# Backlight function
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))
try:
board.DISPLAY.auto_brightness = False
except AttributeError:
pass
board.DISPLAY.brightness = val
# Touchscreen setup
ts = adafruit_touchscreen.Touchscreen(
board.TOUCH_XL,
board.TOUCH_XR,
board.TOUCH_YD,
board.TOUCH_YU,
calibration=((5200, 59000), (5800, 57000)),
size=(320, 240),
)
# ---------- Set the font and preload letters ----------
# Be sure to put your font into a folder named "fonts".
font = bitmap_font.load_font("/fonts/Helvetica-Bold-16.bdf")
# This will preload the text images.
font.load_glyphs(b"abcdefghjiklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890- ()")
# ------------- User Inretface Eliments ------------- #
# Make the display context
splash = displayio.Group()
board.DISPLAY.root_group = splash
# Make a background color fill
color_bitmap = displayio.Bitmap(320, 240, 1)
color_palette = displayio.Palette(1)
color_palette[0] = 0x3D0068
bg_sprite = displayio.TileGrid(color_bitmap, x=0, y=0, pixel_shader=color_palette)
splash.append(bg_sprite)
buttons = []
# Default button styling:
BUTTON_WIDTH = 100
BUTTON_HEIGHT = 100
BUTTON_MARGIN = 10
# Button Objects
button_1 = Button(
x=BUTTON_MARGIN,
y=BUTTON_MARGIN,
width=BUTTON_WIDTH,
height=BUTTON_HEIGHT,
label="Button 1",
label_font=font,
style=Button.SHADOWROUNDRECT,
label_color=0x505050,
fill_color=0x9E9E9E,
outline_color=0x464646,
)
buttons.append(button_1)
button_2 = Button(
x=BUTTON_MARGIN,
y=BUTTON_MARGIN * 2 + BUTTON_HEIGHT,
width=BUTTON_WIDTH,
height=BUTTON_HEIGHT,
label="Button 2",
label_font=font,
style=Button.SHADOWROUNDRECT,
label_color=0x505050,
fill_color=0x9E9E9E,
outline_color=0x464646,
)
buttons.append(button_2)
for b in buttons:
splash.append(b.group)
# Text Label Objects
temperature_label = Label(font, text="temperature", color=0xE300D2)
temperature_label.x = 130
temperature_label.y = 20
splash.append(temperature_label)
light_label = Label(font, text="lux", color=0xE300D2)
light_label.x = 130
light_label.y = 40
splash.append(light_label)
motion_label = Label(font, text="motion", color=0xE300D2)
motion_label.x = 130
motion_label.y = 60
splash.append(motion_label)
feed1_label = Label(font, text="MQTT feed1", color=0xE39300)
feed1_label.x = 130
feed1_label.y = 130
splash.append(feed1_label)
feed2_label = Label(font, text="MQTT feed2", color=0x00DCE3)
feed2_label.x = 130
feed2_label.y = 200
splash.append(feed2_label)
# ------------- MQTT Topic Setup ------------- #
mqtt_topic = "test/topic"
mqtt_temperature = "pyportal/temperature"
mqtt_lux = "pyportal/lux"
mqtt_PIR = "pyportal/pir"
mqtt_button1 = "pyportal/button1"
mqtt_button2 = "pyportal/button2"
mqtt_feed1 = "pyportal/feed1"
mqtt_feed2 = "pyportal/feed2"
# ------------- MQTT Functions ------------- #
# Define callback methods which are called when events occur
# pylint: disable=unused-argument, redefined-outer-name
def connect(client, userdata, flags, rc):
# This function will be called when the client is connected
# successfully to the broker.
print("Connected to MQTT Broker!")
print("Flags: {0}\n RC: {1}".format(flags, rc))
def disconnected(client, userdata, rc):
# This method is called when the client is disconnected
print("Disconnected from MQTT Broker!")
def subscribe(client, userdata, topic, granted_qos):
# This method is called when the client subscribes to a new feed.
print("Subscribed to {0} with QOS level {1}".format(topic, granted_qos))
def publish(client, userdata, topic, pid):
# This method is called when the client publishes data to a feed.
print("Published to {0} with PID {1}".format(topic, pid))
def message(client, topic, message):
"""Method callled when a client's subscribed feed has a new
value.
:param str topic: The topic of the feed with a new value.
:param str message: The new value
"""
print("New message on topic {0}: {1}".format(topic, message))
if topic == "pyportal/feed1":
feed1_label.text = "Next Bus: {}".format(message)
if topic == "pyportal/feed2":
feed2_label.text = "Weather: \n {}".format(message)
if topic == "pyportal/button1":
if message == "1":
buttons[0].label = "ON"
buttons[0].selected = False
print("Button 1 ON")
else:
buttons[0].label = "OFF"
buttons[0].selected = True
print("Button 1 OFF")
# ------------- Network Connection ------------- #
# Connect to WiFi
print("Connecting to WiFi...")
wifi.connect()
print("Connected to WiFi!")
pool = adafruit_connection_manager.get_radio_socketpool(esp)
ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp)
# Set up a MiniMQTT Client
client = MQTT.MQTT(
broker=getenv("mqtt_broker"),
port=1883,
username=getenv("mqtt_username"),
password=getenv("mqtt_password"),
socket_pool=pool,
ssl_context=ssl_context,
)
# Connect callback handlers to client
client.on_connect = connect
client.on_disconnect = disconnected
client.on_subscribe = subscribe
client.on_publish = publish
client.on_message = message
print("Attempting to connect to %s" % client.broker)
client.connect()
print(
"Subscribing to %s, %s, %s, and %s"
% (mqtt_feed1, mqtt_feed2, mqtt_button1, mqtt_button2)
)
client.subscribe(mqtt_feed1)
client.subscribe(mqtt_feed2)
client.subscribe(mqtt_button1)
client.subscribe(mqtt_button2)
# ------------- Code Loop ------------- #
while True:
# Poll the message queue
client.loop()
# Read sensor data and format
light_value = lux = light_sensor.value
light_label.text = "Light Sensor: {}".format(light_value)
temperature = round(adt.temperature)
temperature_label.text = "Temp Sensor: {}".format(temperature)
movement_value = movement_sensor.value
motion_label.text = "PIR Sensor: {}".format(movement_value)
# Read display button press
touch = ts.touch_point
if touch:
for i, b in enumerate(buttons):
if b.contains(touch):
print("Sending button%d pressed" % i)
if i == 0:
# Toggle switch button type
if button1_state == 0:
button1_state = 1
b.label = "ON"
b.selected = False
print("Button 1 ON")
else:
button1_state = 0
b.label = "OFF"
b.selected = True
print("Button 1 OFF")
print("Sending button 1 state: ")
client.publish(mqtt_button1, button1_state)
# for debounce
while ts.touch_point:
print("Button 1 Pressed")
if i == 1:
# Momentary button type
b.selected = True
print("Sending button 2 state: ")
client.publish(mqtt_button2, 1)
# for debounce
while ts.touch_point:
print("Button 2 Pressed")
print("Button 2 reliced")
print("Sending button 2 state: ")
client.publish(mqtt_button2, 0)
b.selected = False
# Publish sensor data to MQTT
print("Sending light sensor value: %d" % light_value)
client.publish(mqtt_lux, light_value)
print("Sending temperature value: %d" % temperature)
client.publish(mqtt_temperature, temperature)
print("Sending motion sensor value: %d" % movement_value)
client.publish(mqtt_PIR, "{}".format(movement_value))
The Font File
You will also need to create a folder named fonts on the PyPortal CIRCUITPY drive with the following bitmap font in it, available for download in the project zip or the GitHub repo:
-
Helvetica-Bold-16.bdf
Settings.toml file
You will also need a file named settings.toml that will contain your WiFi credentials as well as your MQTT server credentials.
CIRCUITPY_WIFI_SSID="your-wifi-ssid" CIRCUITPY_WIFI_PASSWORD="your-wifi-password" mqtt_broker="your-mqtt-broker-url-or-ip" mqtt_username="your-mqtt-broker-username" mqtt_password="your-mqtt-broker-password"
When you are finished the CIRCUITPY drive should look something like this:
Required Libraries
You will need the following Libraries installed for this project to run:
- adafruit_adt7410.mpy
- adafruit_connection_manager.mpy
- adafruit_pixelbuf.mpy
- adafruit_ticks.mpy
- adafruit_logging.mpy
- adafruit_minimqtt.mpy
- adafruit_pyportal.mpy
- adafruit_requests.mpy
- adafruit_touchscreen.mpy
- neopixel.mpy
- adafruit_bitmap_font
- adafruit_bus_device
- adafruit_display_shapes
- adafruit_button
- adafruit_display_text
- adafruit_esp32spi
- adafruit_minimqtt
- adafruit_io
- adafruit_register
Page last edited April 14, 2025
Text editor powered by tinymce.