Adafruit_Learning_System_Gu.../Feather_ESP32-S2_TFT_Azure/code.py
2025-03-19 16:24:53 -07:00

236 lines
8.2 KiB
Python

# SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries
# SPDX-License-Identifier: MIT
from os import getenv
import time
import json
import supervisor
import simpleio
import vectorio
import board
import terminalio
import rtc
import socketpool
import wifi
import displayio
import adafruit_ntp
import adafruit_connection_manager
from adafruit_display_text import bitmap_label, wrap_text_to_lines
from adafruit_bitmap_font import bitmap_font
from adafruit_azureiot import IoTCentralDevice
import adafruit_max1704x
import adafruit_bme680
#from adafruit_lc709203f import LC709203F, PackSize
# 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."
)
print("Connecting to WiFi...")
wifi.radio.connect(ssid, password)
print("Connected to WiFi!")
# ntp clock - update tz_offset to your timezone
pool = adafruit_connection_manager.get_radio_socketpool(wifi.radio)
ssl_context = adafruit_connection_manager.get_radio_ssl_context(wifi.radio)
ntp = adafruit_ntp.NTP(pool, tz_offset=-4)
rtc.RTC().datetime = ntp.datetime
if time.localtime().tm_year < 2022:
print("Setting System Time in UTC")
rtc.RTC().datetime = ntp.datetime
else:
print("Year seems good, skipping set time.")
cal = ntp.datetime
year = cal[0]
mon = cal[1]
day = cal[2]
hour = cal[3]
minute = cal[4]
# To use Azure IoT Central, you will need to create an IoT Central app.
# You can either create a free tier app that will live for 7 days without an Azure subscription,
# Or a standard tier app that will last for ever with an Azure subscription.
# The standard tiers are free for up to 2 devices
#
# If you don't have an Azure subscription:
#
# If you are a student, head to https://aka.ms/FreeStudentAzure and sign up, validating with your
# student email address. This will give you $100 of Azure credit and free tiers of a load of
# service, renewable each year you are a student
#
# If you are not a student, head to https://aka.ms/FreeAz and sign up to get $200 of credit for 30
# days, as well as free tiers of a load of services
#
# Create an Azure IoT Central app by following these
# instructions: https://aka.ms/CreateIoTCentralApp
# Add a device template with telemetry, properties and commands, as well as a view to visualize the
# telemetry and execute commands, and a form to set properties.
#
# Next create a device using the device template, and select Connect to get the
# device connection details.
# Add the connection details to your settings.toml file, using the following values:
#
# 'id_scope' - the devices ID scope
# 'device_id' - the devices device id
# 'device_sas_key' - the devices primary key
#
# The adafruit-circuitpython-azureiot library depends on the following libraries:
#
# From the Adafruit CircuitPython Bundle
# (https://github.com/adafruit/Adafruit_CircuitPython_Bundle):
# * adafruit-circuitpython-minimqtt
# * adafruit-circuitpython-requests
# Create sensor object, communicating over the board's default I2C bus
i2c = board.I2C() # uses board.SCL and board.SDA
# i2c = board.STEMMA_I2C() # For using the built-in STEMMA QT connector on a microcontroller
bme680 = adafruit_bme680.Adafruit_BME680_I2C(i2c, debug=False)
# change this to match the location's pressure (hPa) at sea level
bme680.sea_level_pressure = 1013.25
# Create an IoT Hub device client and connect
esp = None
pool = socketpool.SocketPool(wifi.radio)
device = IoTCentralDevice(
pool, ssl_context, getenv("id_scope"), getenv("device_id"), getenv("device_primary_key")
)
print("Connecting to Azure IoT Central...")
device.connect()
print("Connected to Azure IoT Central!")
temperature_offset = -5
# Create sensor object, using the board's default I2C bus.
#battery_monitor = LC709203F(i2c)
battery_monitor = adafruit_max1704x.MAX17048(board.I2C())
# Update to match the mAh of your battery for more accurate readings.
# Can be MAH100, MAH200, MAH400, MAH500, MAH1000, MAH2000, MAH3000.
# Choose the closest match. Include "PackSize." before it, as shown.
#battery_monitor.pack_size = PackSize.MAH2000
temp = int((bme680.temperature * 9/5) + (32 + temperature_offset))
humidity = int(bme680.relative_humidity)
pressure = int(bme680.pressure)
battery = battery_monitor.cell_percent
# display setup
display = board.DISPLAY
palette0 = displayio.Palette(2)
palette0[0] = 0x00FF00
palette0[1] = 0xFF0000
# load bitmap
bitmap = displayio.OnDiskBitmap("/bmeTFT.bmp")
tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader)
group = displayio.Group()
group.append(tile_grid)
# rectangle for battery life monitor
# vectorio allows for resizing in the loop
rect = vectorio.Rectangle(pixel_shader=palette0, width=22, height=10, x=12, y=116, color_index = 0)
group.append(rect)
# bitmap font
font_file = "/roundedHeavy-26.bdf"
font = bitmap_font.load_font(font_file)
# text elements
temp_text = bitmap_label.Label(font, text="%0.1f° F" % temp, x=20, y=80, color=0xFFFFFF)
humid_text = bitmap_label.Label(font, text="%0.1f %%" % humidity, x=95, y=80, color=0xFFFFFF)
press_text = bitmap_label.Label(font, text="%0.2f" % pressure, x=170, y=80, color=0xFFFFFF)
time_text = bitmap_label.Label(terminalio.FONT,
text="\n".join(wrap_text_to_lines
("Data sent on %s/%s/%s at %s:%s" % (mon,day,year,hour,minute), 20)),
x=125, y=105, color=0xFFFFFF)
group.append(temp_text)
group.append(humid_text)
group.append(press_text)
group.append(time_text)
display.root_group = group
# clock to count down to sending data to Azure
azure_clock = 500
# clock to count down to updating TFT
feather_clock = 30
while True:
try:
# read BME sensor
temp = int((bme680.temperature * 9/5) + (32 + temperature_offset))
humidity = int(bme680.relative_humidity)
pressure = int(bme680.pressure)
# log battery %
battery = battery_monitor.cell_percent
# map range of battery charge to rectangle size on screen
battery_display = round(simpleio.map_range(battery, 0, 100, 0, 22))
# update rectangle to reflect battery charge
rect.width = int(battery_display)
# if below 20%, change rectangle color to red
if battery_monitor.cell_percent < 20:
rect.color_index = 1
# when the azure clock runs out
if azure_clock > 500:
print("getting ntp date/time")
cal = ntp.datetime
year = cal[0]
mon = cal[1]
day = cal[2]
hour = cal[3]
minute = cal[4]
time.sleep(2)
print("getting msg")
# pack message
message = {"Temperature": temp,
"Humidity": humidity,
"Pressure": pressure,
"BatteryPercent": battery}
print("sending json")
device.send_telemetry(json.dumps(message))
print("data sent")
clock_view = "%s:%s" % (hour, minute)
if minute < 10:
clock_view = "%s:0%s" % (hour, minute)
print("updating time text")
time_text.text="\n".join(wrap_text_to_lines
("Data sent on %s/%s/%s at %s" % (mon,day,year,clock_view), 20))
# reset azure clock
azure_clock = 0
# when the feather clock runs out
if feather_clock > 30:
print("updating screen")
temp_text.text = "%0.1f° F" % temp
humid_text.text = "%0.1f %%" % humidity
press_text.text = "%0.2f" % pressure
# reset feather clock
feather_clock = 0
# if no clocks are running out
# increase counts by 1
else:
feather_clock += 1
azure_clock += 1
# ping azure
device.loop()
# if something disrupts the loop, reconnect
# pylint: disable=broad-except
except (ValueError, RuntimeError, OSError, ConnectionError) as e:
print("Network error, reconnecting\n", str(e))
supervisor.reload()
continue
# delay
time.sleep(1)
print(azure_clock)