Code Setup

CircuitPython Library Installation

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_azureiot
  • adafruit_binascii
  • adafruit_bitmap_font
  • adafruit_bus_device
  • adafruit_display_text
  • adafruit_esp32spi
  • adafruit_logging
  • adafruit_minimqtt
  • adafruit_ntp
  • adafruit_requests
  • adafruit_seesaw
  • neopixel

Add CircuitPython Code and Project Assets

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 PyPortal_Azure_Plant_Monitor.

Copy the contents of the PyPortal_Azure_Plant_Monitor directory to your PyPortal's CIRCUITPY drive.

PyPortal Azure IoT Plant Monitor
Log plant vitals to Microsoft Azure IoT Central with
your PyPortal

Authors: Brent Rubell for Adafruit Industries, 2019
       : Jim Bennett for Microsoft, 2020
import time
import json
import board
import busio
from digitalio import DigitalInOut
from adafruit_esp32spi import adafruit_esp32spi, adafruit_esp32spi_wifimanager
import adafruit_esp32spi.adafruit_esp32spi_socket as socket
import neopixel
from adafruit_ntp import NTP
from adafruit_azureiot import IoTCentralDevice
from adafruit_seesaw.seesaw import Seesaw

# gfx helper
import azure_gfx_helper

# init. graphics helper
gfx = azure_gfx_helper.Azure_GFX(is_celsius=True)

# Get wifi details and more from a file
    from secrets import secrets
except ImportError:
    print("WiFi secrets are kept in, 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)

# Set up the WiFi manager with a status light to show the WiFi connection status
status_light = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.2)
wifi = adafruit_esp32spi_wifimanager.ESPSPI_WiFiManager(esp, secrets, status_light)
print("WiFi connecting...")
print("WiFi connected!")

# Time setup, needed to authenticate with Azure IoT Central
ntp = NTP(esp)
while not ntp.valid_time:
    print("Failed to obtain time, retrying in 5 seconds...")

# Soil Sensor Setup
i2c_bus = busio.I2C(board.SCL, board.SDA)
ss = Seesaw(i2c_bus, addr=0x36)

# Create an instance of the Azure IoT Central device
device = IoTCentralDevice(

# Connect to Azure IoT Central

# Hide the splash screen and show the telemetry values

while True:
        # read moisture level
        moisture_level = ss.moisture_read()
        # read temperature
        temperature = ss.get_temp()
        # display soil sensor values on pyportal

        print('Sending data to Azure')
        gfx.display_azure_status('Sending data...')

        # send the temperature and moisture level to Azure
        message = {
            "Temperature": temperature,
            "MoistureLevel": moisture_level

        gfx.display_azure_status('Data sent!')
        print('Data sent!')
    except (ValueError, RuntimeError) as e:
        print("Failed to get data, retrying\n", e)

    # Sleep for 10 minutes before getting the next value

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

The content of the CIRCUITPY drive showing the code, azure_gfx_helper and secrets python files, a fonts folder, an images folder, as well as a list of libraries in a lib folder.ntents.png
The contents of the CIRCUITPYTHON device

Install an editor

This guide requires you to edit and interact with CircuitPython code. While you can use any text editor of your choosing, two recommended editors are Visual Studio Code and Mu.

Visual Studio Code is a free, open source code editor with a huge range of extensions to support multiple languages and technologies. It runs on Windows, MacOS, and Linux.

After installing Visual Studio Code, you will need to install the Python extension if you want intellisense and code completion. You can read about this in the the Python in Visual Studio Code documentation.

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!

Secrets File Setup

First, use Visual Studio Code or Mu to open up a file on your CIRCUITPY drive. Next, you're going to edit the file to enter your local WiFi credentials along with data about your Azure IoT Central Device.

Make the following changes to the code below in the file:

  • ReplaceMY_WIFI_SSID with the name of your WiFi SSID
  • ReplaceMY_WIFI_PASSWORD with your WiFi's password
  • ReplaceMY_AZURE_IOT_CENTRAL_ID_SCOPE with the ID Scope of your Azure IoT Central device from the connection dialog.
  • ReplaceMY_AZURE_IOT_CENTRAL_DECVICE_IDwith the Device ID of your Azure IoT Central device from the connection dialog.
  • Replace MY_AZURE_IOT_CENTRAL_PRIMAEY_KEY with the Primary Key of your Azure IoT Central device from the connection dialog.
Download: file
# This file is where you keep secret settings, passwords, and tokens!
# If you put them in the code you risk committing that info or sharing it

secrets = {
    'ssid' : 'MY_WIFI_SSID',
    'password' : 'MY_WIFI_PASSWORD',
    'id_scope' : 'MY_AZURE_IOT_CENTRAL_ID_SCOPE',
    'device_id' : 'MY_AZURE_IOT_CENTRAL_DEVICE_ID',

You can then close, saving the updated file onto the device.


Setting up the PyPortal with the Azure IoT Central is finished! You do not need to repeat this process again unless you change your IoT Central device.

This guide was first published on May 24, 2019. It was last updated on May 24, 2019.
This page (Code Setup ) was last updated on Aug 08, 2020.