/ Feather_ESP32-S2_TFT_Azure / code.py
code.py
1 # SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries 2 # SPDX-License-Identifier: MIT 3 4 import time 5 import json 6 import supervisor 7 import simpleio 8 import vectorio 9 import board 10 import terminalio 11 import rtc 12 import socketpool 13 import wifi 14 import displayio 15 import adafruit_ntp 16 from adafruit_display_text import bitmap_label, wrap_text_to_lines 17 from adafruit_bitmap_font import bitmap_font 18 from adafruit_azureiot import IoTCentralDevice 19 import adafruit_bme680 20 from adafruit_lc709203f import LC709203F, PackSize 21 22 23 # Get wifi details and more from a secrets.py file 24 try: 25 from secrets import secrets 26 except ImportError: 27 print("WiFi secrets are kept in secrets.py, please add them there!") 28 raise 29 30 print("Connecting to WiFi...") 31 wifi.radio.connect(secrets["ssid"], secrets["password"]) 32 33 print("Connected to WiFi!") 34 35 # ntp clock - update tz_offset to your timezone 36 pool = socketpool.SocketPool(wifi.radio) 37 ntp = adafruit_ntp.NTP(pool, tz_offset=-4) 38 rtc.RTC().datetime = ntp.datetime 39 40 if time.localtime().tm_year < 2022: 41 print("Setting System Time in UTC") 42 rtc.RTC().datetime = ntp.datetime 43 44 else: 45 print("Year seems good, skipping set time.") 46 47 cal = ntp.datetime 48 year = cal[0] 49 mon = cal[1] 50 day = cal[2] 51 hour = cal[3] 52 minute = cal[4] 53 54 # To use Azure IoT Central, you will need to create an IoT Central app. 55 # You can either create a free tier app that will live for 7 days without an Azure subscription, 56 # Or a standard tier app that will last for ever with an Azure subscription. 57 # The standard tiers are free for up to 2 devices 58 # 59 # If you don't have an Azure subscription: 60 # 61 # If you are a student, head to https://aka.ms/FreeStudentAzure and sign up, validating with your 62 # student email address. This will give you $100 of Azure credit and free tiers of a load of 63 # service, renewable each year you are a student 64 # 65 # If you are not a student, head to https://aka.ms/FreeAz and sign up to get $200 of credit for 30 66 # days, as well as free tiers of a load of services 67 # 68 # Create an Azure IoT Central app by following these 69 # instructions: https://aka.ms/CreateIoTCentralApp 70 # Add a device template with telemetry, properties and commands, as well as a view to visualize the 71 # telemetry and execute commands, and a form to set properties. 72 # 73 # Next create a device using the device template, and select Connect to get the 74 # device connection details. 75 # Add the connection details to your secrets.py file, using the following values: 76 # 77 # 'id_scope' - the devices ID scope 78 # 'device_id' - the devices device id 79 # 'device_sas_key' - the devices primary key 80 # 81 # The adafruit-circuitpython-azureiot library depends on the following libraries: 82 # 83 # From the Adafruit CircuitPython Bundle 84 # (https://github.com/adafruit/Adafruit_CircuitPython_Bundle): 85 # * adafruit-circuitpython-minimqtt 86 # * adafruit-circuitpython-requests 87 # Create sensor object, communicating over the board's default I2C bus 88 i2c = board.I2C() # uses board.SCL and board.SDA 89 bme680 = adafruit_bme680.Adafruit_BME680_I2C(i2c, debug=False) 90 91 # change this to match the location's pressure (hPa) at sea level 92 bme680.sea_level_pressure = 1013.25 93 94 # Create an IoT Hub device client and connect 95 esp = None 96 pool = socketpool.SocketPool(wifi.radio) 97 device = IoTCentralDevice( 98 pool, esp, secrets["id_scope"], secrets["device_id"], secrets["device_primary_key"] 99 ) 100 101 print("Connecting to Azure IoT Central...") 102 device.connect() 103 104 print("Connected to Azure IoT Central!") 105 106 temperature_offset = -5 107 108 # Create sensor object, using the board's default I2C bus. 109 battery_monitor = LC709203F(board.I2C()) 110 111 # Update to match the mAh of your battery for more accurate readings. 112 # Can be MAH100, MAH200, MAH400, MAH500, MAH1000, MAH2000, MAH3000. 113 # Choose the closest match. Include "PackSize." before it, as shown. 114 battery_monitor.pack_size = PackSize.MAH2000 115 116 temp = int((bme680.temperature * 9/5) + (32 + temperature_offset)) 117 humidity = int(bme680.relative_humidity) 118 pressure = int(bme680.pressure) 119 battery = battery_monitor.cell_percent 120 121 # display setup 122 display = board.DISPLAY 123 124 palette0 = displayio.Palette(2) 125 palette0[0] = 0x00FF00 126 palette0[1] = 0xFF0000 127 128 # load bitmap 129 bitmap = displayio.OnDiskBitmap("/bmeTFT.bmp") 130 tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) 131 group = displayio.Group() 132 group.append(tile_grid) 133 # rectangle for battery life monitor 134 # vectorio allows for resizing in the loop 135 rect = vectorio.Rectangle(pixel_shader=palette0, width=22, height=10, x=12, y=116, color_index = 0) 136 group.append(rect) 137 # bitmap font 138 font_file = "/roundedHeavy-26.bdf" 139 font = bitmap_font.load_font(font_file) 140 # text elements 141 temp_text = bitmap_label.Label(font, text="%0.1f° F" % temp, x=20, y=80, color=0xFFFFFF) 142 humid_text = bitmap_label.Label(font, text="%0.1f %%" % humidity, x=95, y=80, color=0xFFFFFF) 143 press_text = bitmap_label.Label(font, text="%0.2f" % pressure, x=170, y=80, color=0xFFFFFF) 144 time_text = bitmap_label.Label(terminalio.FONT, 145 text="\n".join(wrap_text_to_lines 146 ("Data sent on %s/%s/%s at %s:%s" % (mon,day,year,hour,minute), 20)), 147 x=125, y=105, color=0xFFFFFF) 148 group.append(temp_text) 149 group.append(humid_text) 150 group.append(press_text) 151 group.append(time_text) 152 display.show(group) 153 154 # clock to count down to sending data to Azure 155 azure_clock = 500 156 # clock to count down to updating TFT 157 feather_clock = 30 158 159 160 while True: 161 try: 162 # read BME sensor 163 temp = int((bme680.temperature * 9/5) + (32 + temperature_offset)) 164 humidity = int(bme680.relative_humidity) 165 pressure = int(bme680.pressure) 166 # log battery % 167 battery = battery_monitor.cell_percent 168 # map range of battery charge to rectangle size on screen 169 battery_display = round(simpleio.map_range(battery, 0, 100, 0, 22)) 170 # update rectangle to reflect battery charge 171 rect.width = int(battery_display) 172 # if below 20%, change rectangle color to red 173 if battery_monitor.cell_percent < 20: 174 rect.color_index = 1 175 # when the azure clock runs out 176 if azure_clock > 500: 177 print("getting ntp date/time") 178 cal = ntp.datetime 179 year = cal[0] 180 mon = cal[1] 181 day = cal[2] 182 hour = cal[3] 183 minute = cal[4] 184 time.sleep(2) 185 print("getting msg") 186 # pack message 187 message = {"Temperature": temp, 188 "Humidity": humidity, 189 "Pressure": pressure, 190 "BatteryPercent": battery} 191 print("sending json") 192 device.send_telemetry(json.dumps(message)) 193 print("data sent") 194 clock_view = "%s:%s" % (hour, minute) 195 if minute < 10: 196 clock_view = "%s:0%s" % (hour, minute) 197 print("updating time text") 198 time_text.text="\n".join(wrap_text_to_lines 199 ("Data sent on %s/%s/%s at %s" % (mon,day,year,clock_view), 20)) 200 # reset azure clock 201 azure_clock = 0 202 # when the feather clock runs out 203 if feather_clock > 30: 204 print("updating screen") 205 temp_text.text = "%0.1f° F" % temp 206 humid_text.text = "%0.1f %%" % humidity 207 press_text.text = "%0.2f" % pressure 208 # reset feather clock 209 feather_clock = 0 210 # if no clocks are running out 211 # increase counts by 1 212 else: 213 feather_clock += 1 214 azure_clock += 1 215 # ping azure 216 device.loop() 217 # if something disrupts the loop, reconnect 218 # pylint: disable=broad-except 219 except (ValueError, RuntimeError, OSError, ConnectionError) as e: 220 print("Network error, reconnecting\n", str(e)) 221 supervisor.reload() 222 continue 223 # delay 224 time.sleep(1) 225 print(azure_clock)