Using CircuitPython is recommended for beginner to intermediate coders. It's more compact, easier to understand, and easy to change and debug.
Add CircuitPython Libraries
This page assumes your PyPortal is set up with the appropriate CircuitPython libraries and has been connected to the internet.
- If you have not done this, follow this page to install the correct libraries. Then, follow this page to connect the PyPortal to the internet.
Add CircuitPython Code
In the embedded code element below, click on the Download: Project Zip link, and save the .zip archive file to your computer.
Then, uncompress the .zip file, it will unpack to a folder named Adafruit_IO_Scheduled_Trigger.
Copy the contents of Adafruit_IO_Scheduled_Trigger directory to your PyPortal's CIRCUITPY drive.
# SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries # # SPDX-License-Identifier: MIT from os import getenv import time import board import busio from digitalio import DigitalInOut import adafruit_connection_manager from adafruit_esp32spi import adafruit_esp32spi from adafruit_esp32spi import adafruit_esp32spi_wifimanager import neopixel import adafruit_minimqtt.adafruit_minimqtt as MQTT from adafruit_io.adafruit_io import IO_MQTT # Get WiFi details and Adafruit IO keys, ensure these are setup in settings.toml # (visit io.adafruit.com if you need to create an account, or if you need your Adafruit IO key.) ssid = getenv("CIRCUITPY_WIFI_SSID") password = getenv("CIRCUITPY_WIFI_PASSWORD") aio_username = getenv("ADAFRUIT_AIO_USERNAME") aio_key = getenv("ADAFRUIT_AIO_KEY") if None in [ssid, password, aio_username, aio_key]: raise RuntimeError( "WiFi and Adafruit IO settings are kept in settings.toml, " "please add them there. The settings file must contain " "'CIRCUITPY_WIFI_SSID', 'CIRCUITPY_WIFI_PASSWORD', " "'ADAFRUIT_AIO_USERNAME' and 'ADAFRUIT_AIO_KEY' 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) # If you have an externally connected ESP32: # esp32_cs = DigitalInOut(board.D9) # esp32_ready = DigitalInOut(board.D10) # esp32_reset = DigitalInOut(board.D5) spi = busio.SPI(board.SCK, board.MOSI, board.MISO) esp = adafruit_esp32spi.ESP_SPIcontrol(spi, esp32_cs, esp32_ready, esp32_reset) """Use below for Most Boards""" status_pixel = neopixel.NeoPixel( board.NEOPIXEL, 1, brightness=0.2 ) # Uncomment for Most Boards """Uncomment below for ItsyBitsy M4""" # status_pixel = dotstar.DotStar(board.APA102_SCK, board.APA102_MOSI, 1, brightness=0.2) # Uncomment below for an externally defined RGB LED # import adafruit_rgbled # from adafruit_esp32spi import PWMOut # RED_LED = PWMOut.PWMOut(esp, 26) # GREEN_LED = PWMOut.PWMOut(esp, 27) # BLUE_LED = PWMOut.PWMOut(esp, 25) # status_pixel = adafruit_rgbled.RGBLED(RED_LED, BLUE_LED, GREEN_LED) wifi = adafruit_esp32spi_wifimanager.WiFiManager(esp, ssid, password, status_pixel=status_pixel) # Set up a pin for controlling the relay power_pin = DigitalInOut(board.D3) power_pin.switch_to_output() # Define callback functions which will be called when certain events happen. # pylint: disable=unused-argument def connected(client): # Connected function will be called when the client is connected to Adafruit IO. # This is a good place to subscribe to feed changes. The client parameter # passed to this function is the Adafruit IO MQTT client so you can make # calls against it easily. print("Connected to Adafruit IO!") def subscribe(client, userdata, topic, granted_qos): # This method is called when the client subscribes to a new feed. print("Listening for changes on relay feed...") def unsubscribe(client, userdata, topic, pid): # This method is called when the client unsubscribes from a feed. print("Unsubscribed from {0} with PID {1}".format(topic, pid)) # pylint: disable=unused-argument def disconnected(client): # Disconnected function will be called when the client disconnects. print("Disconnected from Adafruit IO!") # pylint: disable=unused-argument def on_message(client, feed_id, payload): # Message function will be called when a subscribed feed has a new value. # The feed_id parameter identifies the feed, and the payload parameter has # the new value. print("Feed {0} received new value: {1}".format(feed_id, payload)) def on_relay_msg(client, topic, message): # Method called whenever user/feeds/relay has a new value if message == "morning": print("Morning - turning outlet ON") power_pin.value = True elif message == "night": print("Night - turning outlet OFF") power_pin.value = False else: print("Unexpected value received on relay feed.") # Connect to WiFi print("Connecting to WiFi...") wifi.connect() print("Connected!") pool = adafruit_connection_manager.get_radio_socketpool(esp) ssl_context = adafruit_connection_manager.get_radio_ssl_context(esp) # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", username=aio_username, password=aio_key, socket_pool=pool, ssl_context=ssl_context, ) # Initialize an Adafruit IO MQTT Client io = IO_MQTT(mqtt_client) # Connect the callback methods defined above to Adafruit IO io.on_connect = connected io.on_disconnect = disconnected io.on_subscribe = subscribe io.on_unsubscribe = unsubscribe io.on_message = on_message # Connect to Adafruit IO print("Connecting to Adafruit IO...") io.connect() # Set up a message handler for the relay feed io.add_feed_callback("relay", on_relay_msg) # Subscribe to all messages on the relay feed io.subscribe("relay") # Get the most recent value on the relay feed io.get("relay") # Start a blocking loop to check for new messages while True: try: io.loop() except (ValueError, RuntimeError, ConnectionError, OSError) as e: print("Failed to get data, retrying\n", e) wifi.reset() io.reconnect() continue time.sleep(0.5)
Settings.toml Setup
Open the settings.toml file on your CircuitPython device using Mu or your favorite text editor. You're going to edit this file to enter your WiFi and Adafruit IO credentials.
-
Change
ssid
to the name of your WiFi network -
Change
password
to your WiFi network's password -
Change
your_aio_username
to your Adafruit IO Username -
Change
your_aio_key
to your Adafruit IO Key.
CIRCUITPY_WIFI_SSID = "ssid" CIRCUITPY_WIFI_PASSWORD = "password" CIRCUITPY_WEB_API_PASSWORD = "webpassword" TIMEZONE = "America/New_York", # http://worldtimeapi.org/timezones ADAFRUIT_AIO_USERNAME = "your_aio_username" ADAFRUIT_AIO_KEY = "your_aio_key"
Code Usage
The PyPortal should boot up. The code connects the PyPortal to your WiFi network. Then, it connects to Adafruit IO and subscribes to the feed you set up earlier.
This code continuously checks the relay feed for new values.
Every weekday at 8AM, the scheduled action publishes the value "morning" to your relay feed.
When the feed updates with a new value, the on_battery_msg()
function executes and checks if the value matches the text "morning".
If the feed's value matches the text "morning", the PyPortal's D3 pin is written high. This turns on the light connected to the outlet.
Every evening at 11PM, the scheduled trigger publishes the value "night" to your relay feed. The on_battery_msg()
will read the new value, check if it matches the text "night", and turns off the outlet.
First, check your wiring against the assembly and wiring page.
Next, make sure your Adafruit IO feed is named relay and your triggers are set up to send the value morning and night every weekday.
Then, navigate to your Feeds page and click the relay feed. If it's been a day since you set up the triggers, the values morning or night should be in the feed's value list. If they're not, check the action set up.
Page last edited March 13, 2025
Text editor powered by tinymce.