This project's code utilizes the Azure IoT Library which currently does not work with AirLift hardware, such as the Adafruit PyPortal. As a result, this project does not currently work (but may in the future).
For a more updated guide using CircuitPython and Microsoft Azure IoT, visit https://learn.adafruit.com/getting-started-with-microsoft-azure-and-circuitpython
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
The code first imports all of the modules required to run the code. Some of these libraries are CircuitPython core modules (they're "burned into" the firmware) and some of them you dragged into the library folder.
The code for this project imports a special adafruit_azureiot
library. To help simplify communication between your device and Azure IoT Central, we wrote a CircuitPython helper module called Adafruit_CircuitPython_AzureIoT.
- For more information about how the MQTT requests behind the API work - check out our All The Internet of Things guide on this topic here.
We've also included an azure_gfx_helper.py file which handles displaying the status of the code on the PyPortal's display.
Configuring the Graphical Helper
The graphics helper, which manages' the PyPortal's display is created. Once created it shows a splash screen whilst the device connects to WiFi and Azure IoT Central. If you want to show the temperature in Fahrenheit instead of Celsius, change is_celsius=True
to is_celsius=False
.
# init. graphics helper gfx = azure_gfx_helper.Azure_GFX(is_celsius=True)
Configuring the PyPortal's WiFi
The next chunk of code grabs information from a secrets.py file including wifi configuration. Then, it sets up the ESP32's SPI connections for use with the PyPortal. The wifi
object is set up here too to manage the WiFi connection.
Finally a Network Time Protocol, or NTP object is set up to synchronize the current time from a server.
# 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...") wifi.connect() 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...") time.sleep(5) ntp.set_time()
Configuring the Soil Sensor
An I2C busio device is set up and linked to the soil sensor's address (0x36
)
# Soil Sensor Setup i2c_bus = busio.I2C(board.SCL, board.SDA) ss = Seesaw(i2c_bus, addr=0x36)
Configuring the Azure IoT Central Module
Next, we'll create an instance of the Azure IoT Central device client called device
. It takes in the ESP network socket, socket
, the ESP object, esp
, and the IoT Central connection details from the secrets file. Once created, the device connects to IoT Central.
# Create an instance of the Azure IoT Central device device = IoTCentralDevice( socket, esp, secrets["id_scope"], secrets["device_id"], secrets["key"] ) # Connect to Azure IoT Central device.connect()
Hide the splash screen and show the telemetry
Once the device is connected, the graphical helper can hide the splash screen and start displaying the telemetry values on screen.
# Hide the splash screen and show the telemetry values gfx.show_text()
Main Loop
The first part of the main loop reads the soil sensor's (ss
) moisture level and temperature. It then calls gfx.display_moisture
and gfx.display_temp
to display the moisture and temperature values on the PyPortal's display
while True: try: # read moisture level moisture_level = ss.moisture_read() # read temperature temperature = ss.get_temp() # display soil sensor values on pyportal gfx.display_moisture(moisture_level) gfx.display_temp(temperature)
The next block of code changes the displays status to indicate that data is about to be sent. It then builds a JSON object, message
, containing the temperature and soil moisture.
This message is then sent to Azure IoT Central as telemetry data using the device.send_telemetry()
call. The device.loop()
method is then called to process any communication back and further between the Azure IoT Central module and the Azure IoT Central application.
Finally the display status is changed to show data has been sent.
# send the temperature and moisture level to Azure message = { "Temperature": temperature, "MoistureLevel": moisture_level } device.send_telemetry(json.dumps(message)) device.loop() gfx.display_azure_status('Data sent!') print('Data sent!')
All of this code is wrapped in a try
/except
control flow block. If connection is lost at any point, then the except
code will be run before going back to the try
.
This except
code block will reset and reconnect the wifi
object, then reconnect to Azure IoT Central.
except (ValueError, RuntimeError) as e: print("Failed to get data, retrying\n", e) wifi.reset() wifi.connect() device.reconnect() continue
Finally the loop sleeps for 10 minutes, represented as 600 seconds. This is to ensure IoT Central doesn't receive too much data - the S1 tier is limited to 5,000 messages a month, and one message every 10 minutes is a maximum of 4,464 messages a month.
# Sleep for 10 minutes before getting the next value time.sleep(600)
Text editor powered by tinymce.