First make sure you are running the latest version of Adafruit CircuitPython for your board.
Next you'll need to install the necessary libraries to use the hardware--carefully follow the steps to find and install these libraries from Adafruit's CircuitPython library bundle matching your version of CircuitPython. PyPortal requires at least CircuitPython version 4.0.0.
Before continuing make sure your board's lib folder has the following files and folders copied over:
- adafruit_aws_iot.mpy
- adafruit_esp32spi
- adafruit_requests.mpy
- adafruit_bus_device
- adafruit_logging.mpy
- adafruit_seesaw
- adafruit_display_text
- adafruit_minimqtt.mpy
- neopixel.mpy
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_AWS_IOT_Planter.
Copy the contents of PyPortal_AWS_IOT_Planter directory to your PyPortal CIRCUITPY drive.
# SPDX-FileCopyrightText: 2019 Brent Rubell for Adafruit Industries # # SPDX-License-Identifier: MIT """ PyPortal Amazon AWS IoT Plant Monitor ========================================================= Log your plant's vitals to AWS IoT and receive email notifications when it needs watering with your PyPortal. Author: Brent Rubell for Adafruit Industries, 2019 """ import os import time import json import board import busio from digitalio import DigitalInOut import neopixel import adafruit_connection_manager from adafruit_esp32spi import adafruit_esp32spi from adafruit_esp32spi import adafruit_esp32spi_wifimanager import adafruit_minimqtt.adafruit_minimqtt as MQTT from adafruit_aws_iot import MQTT_CLIENT from adafruit_seesaw.seesaw import Seesaw import aws_gfx_helper # Time between polling the STEMMA, in minutes SENSOR_DELAY = 15 secrets = { "ssid" : os.getenv("CIRCUITPY_WIFI_SSID"), "password" : os.getenv("CIRCUITPY_WIFI_PASSWORD"), } # Get device certificate try: with open("aws_cert.pem.crt", "rb") as f: DEVICE_CERT = f.read() except ImportError: print("Certificate (aws_cert.pem.crt) not found on CIRCUITPY filesystem.") raise # Get device private key try: with open("private.pem.key", "rb") as f: DEVICE_KEY = f.read() except ImportError: print("Key (private.pem.key) not found on CIRCUITPY filesystem.") raise # 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) # Verify nina-fw version >= 1.4.0 assert int(bytes(esp.firmware_version).decode("utf-8")[2]) >= 4, "Please update nina-fw to >=1.4.0." status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2) wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager( esp, secrets, status_light) # Initialize the graphics helper print("Loading AWS IoT Graphics...") gfx = aws_gfx_helper.AWS_GFX() print("Graphics loaded!") # Set AWS Device Certificate esp.set_certificate(DEVICE_CERT) # Set AWS RSA Private Key esp.set_private_key(DEVICE_KEY) # 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) # Soil Sensor Setup i2c_bus = busio.I2C(board.SCL, board.SDA) ss = Seesaw(i2c_bus, addr=0x36) # 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 AWS IoT!') print('Flags: {0}\nRC: {1}'.format(flags, rc)) # Subscribe client to all shadow updates print("Subscribing to shadow updates...") aws_iot.shadow_subscribe() def disconnect(client, userdata, rc): # This method is called when the client disconnects # from the broker. print('Disconnected from AWS IoT!') def subscribe(client, userdata, topic, granted_qos): # This method is called when the client subscribes to a new topic. print('Subscribed to {0} with QOS level {1}'.format(topic, granted_qos)) def unsubscribe(client, userdata, topic, pid): # This method is called when the client unsubscribes from a topic. print('Unsubscribed from {0} with PID {1}'.format(topic, pid)) def publish(client, userdata, topic, pid): # This method is called when the client publishes data to a topic. print('Published to {0} with PID {1}'.format(topic, pid)) def message(client, topic, msg): # This method is called when the client receives data from a topic. print("Message from {}: {}".format(topic, msg)) # Set up a new MiniMQTT Client client = MQTT.MQTT(broker = os.getenv("BROKER"), client_id = os.getenv("CLIENT_ID"), socket_pool=pool, ssl_context=ssl_context) # Initialize AWS IoT MQTT API Client aws_iot = MQTT_CLIENT(client) # Connect callback handlers to AWS IoT MQTT Client aws_iot.on_connect = connect aws_iot.on_disconnect = disconnect aws_iot.on_subscribe = subscribe aws_iot.on_unsubscribe = unsubscribe aws_iot.on_publish = publish aws_iot.on_message = message print('Attempting to connect to %s'%client.broker) aws_iot.connect() # Time in seconds since power on initial = time.monotonic() while True: try: gfx.show_aws_status('Listening for msgs...') now = time.monotonic() if now - initial > (SENSOR_DELAY * 60): # read moisture level moisture = ss.moisture_read() print("Moisture Level: ", moisture) # read temperature temperature = ss.get_temp() # Display Soil Sensor values on pyportal temperature = gfx.show_temp(temperature) gfx.show_water_level(moisture) print('Sending data to AWS IoT...') gfx.show_aws_status('Publishing data...') # Create a json-formatted device payload payload = {"state":{"reported":{"moisture":str(moisture), "temp":str(temperature)}}} # Update device shadow aws_iot.shadow_update(json.dumps(payload)) gfx.show_aws_status('Data published!') print('Data sent!') # Reset timer initial = now aws_iot.loop() except (ValueError, RuntimeError, ConnectionError, OSError) as e: print("Failed to get data, retrying", e) wifi.reset()
This is what the final contents of the CIRCUITPY drive will look like:
Install the Mu Editor
This guide requires you to edit and interact with CircuitPython code. While you can use any text editor of your choosing, Mu is a simple code editor that works with the Adafruit CircuitPython boards. 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!
Before proceeding, click the button below to install the Mu Editor. There are versions for PC, mac, and Linux.
Before you set up the settings.toml file for this project, you'll need to retrieve your AWS IOT's custom endpoint URL.
Navigate to your AWS IoT dashboard and click Settings on the sidebar. Your custom endpoint will be posted at the top of this page. Copy this value and save it somewhere safe, you'll need it in the next step.
Open the settings.toml file on your CIRCUITPY drive using Mu. You're going to edit the file to enter your local WiFi credentials along with data about your AWS IoT configuration.
Update the settings.toml file to include your WiFI credentials, and replace the BROKER value with the URL of your AWS IoT custom endpoint.
CIRCUITPY_WIFI_SSID = "your_wifi_ssid" CIRCUITPY_WIFI_PASSWORD = "your_wifi_password" TIMEZONE = "America/New_York" # http://worldtimeapi.org/timezones BROKER = "your_AWS_IOT_endpoint_url" CLIENT_ID = "PyPortal"
Adding your AWS IoT Device Certificate and Key to CIRCUITPY
CircuitPython makes loading your AWS IoT device certificate and private key as easy as drag and drop. Seriously - we're going to drag and drop the two files we downloaded earlier onto the filesystem.
AWS IoT names the certificate and RSA private key randomly (your private key file should look something like: 8a1018d558-private.pem.key
). You're going to rename the key/certificate so they'll be easier to reference them in the code.
Rename your key from RANDOMALPHANUMERICSTRING-private.pem.key
to private.pem.key
Rename your certificate from RANDOMALPHANUMERICSTRING-certificate.pem.crt
to aws_cert.pem.crt
.
Then, copy them over to the CIRCUITPY volume.
With the certificates copied over, you're good to go! Let's continue to the usage section.
Page last edited January 22, 2025
Text editor powered by tinymce.