code.py
1 # SPDX-FileCopyrightText: 2022 Liz Clark for Adafruit Industries 2 # SPDX-License-Identifier: MIT 3 4 import json 5 import time 6 import digitalio 7 import supervisor 8 import simpleio 9 import vectorio 10 import board 11 import terminalio 12 import rtc 13 import socketpool 14 import wifi 15 import displayio 16 import adafruit_ntp 17 from adafruit_display_text import bitmap_label, wrap_text_to_lines 18 from adafruit_bitmap_font import bitmap_font 19 from adafruit_azureiot import IoTHubDevice 20 import adafruit_bme680 21 from adafruit_lc709203f import LC709203F, PackSize 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=0) 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 esp = None 48 pool = socketpool.SocketPool(wifi.radio) 49 # Create an IoT Hub device client and connect 50 device = IoTHubDevice(pool, esp, secrets["device_connection_string"]) 51 52 print("Connecting to Azure IoT Hub...") 53 54 # Connect to IoT Central 55 device.connect() 56 57 print("Connected to Azure IoT Hub!") 58 59 cal = ntp.datetime 60 year = cal[0] 61 mon = cal[1] 62 day = cal[2] 63 hour = cal[3] 64 minute = cal[4] 65 66 i2c = board.I2C() # uses board.SCL and board.SDA 67 bme680 = adafruit_bme680.Adafruit_BME680_I2C(i2c, debug=False) 68 69 # change this to match the location's pressure (hPa) at sea level 70 bme680.sea_level_pressure = 1013.25 71 72 temperature_offset = -5 73 74 # Create sensor object, using the board's default I2C bus. 75 battery_monitor = LC709203F(board.I2C()) 76 77 # Update to match the mAh of your battery for more accurate readings. 78 # Can be MAH100, MAH200, MAH400, MAH500, MAH1000, MAH2000, MAH3000. 79 # Choose the closest match. Include "PackSize." before it, as shown. 80 battery_monitor.pack_size = PackSize.MAH2000 81 82 temp = int((bme680.temperature * 9/5) + (32 + temperature_offset)) 83 humidity = int(bme680.relative_humidity) 84 pressure = int(bme680.pressure) 85 battery = battery_monitor.cell_percent 86 87 # setup boot button as input 88 button = digitalio.DigitalInOut(board.BUTTON) 89 button.switch_to_input(pull=digitalio.Pull.UP) 90 91 # display setup 92 display = board.DISPLAY 93 94 palette0 = displayio.Palette(2) 95 palette0[0] = 0x00FF00 96 palette0[1] = 0xFF0000 97 98 # load bitmap 99 bitmap = displayio.OnDiskBitmap("/bmeTFT.bmp") 100 tile_grid = displayio.TileGrid(bitmap, pixel_shader=bitmap.pixel_shader) 101 group = displayio.Group() 102 group.append(tile_grid) 103 # rectangle for battery life monitor 104 # vectorio allows for resizing in the loop 105 rect = vectorio.Rectangle(pixel_shader=palette0, width=22, height=10, x=12, y=116, color_index = 0) 106 group.append(rect) 107 # bitmap font 108 font_file = "/roundedHeavy-26.bdf" 109 font = bitmap_font.load_font(font_file) 110 # text elements 111 temp_text = bitmap_label.Label(font, text="%0.1f° F" % temp, x=20, y=80, color=0xFFFFFF) 112 humid_text = bitmap_label.Label(font, text="%0.1f %%" % humidity, x=95, y=80, color=0xFFFFFF) 113 press_text = bitmap_label.Label(font, text="%0.2f" % pressure, x=170, y=80, color=0xFFFFFF) 114 time_text = bitmap_label.Label(terminalio.FONT, 115 text="\n".join(wrap_text_to_lines 116 ("Data sent on %s/%s/%s at %s:%s" % (mon,day,year,hour,minute), 20)), 117 x=125, y=105, color=0xFFFFFF) 118 group.append(temp_text) 119 group.append(humid_text) 120 group.append(press_text) 121 group.append(time_text) 122 display.show(group) 123 124 # clock to count down to sending data to Azure 125 azure_clock = 500 126 # clock to count down to updating TFT 127 feather_clock = 30 128 # button debounce state 129 button_pressed = False 130 131 while True: 132 try: 133 if button.value and button_pressed: 134 button_pressed = False 135 if not button.value and not button_pressed: 136 print("getting msg") 137 # pack message 138 message = {"Temperature": temp, 139 "Humidity": humidity, 140 "Pressure": pressure, 141 "BatteryPercent": battery, 142 "FeatherConnected": 1} 143 print("sending json") 144 device.send_device_to_cloud_message(json.dumps(message)) 145 print("data sent") 146 # read BME sensor 147 temp = int((bme680.temperature * 9/5) + (32 + temperature_offset)) 148 humidity = int(bme680.relative_humidity) 149 pressure = int(bme680.pressure) 150 # log battery % 151 battery = battery_monitor.cell_percent 152 # map range of battery charge to rectangle size on screen 153 battery_display = round(simpleio.map_range(battery, 0, 100, 0, 22)) 154 # update rectangle to reflect battery charge 155 rect.width = int(battery_display) 156 # if below 20%, change rectangle color to red 157 if battery_monitor.cell_percent < 20: 158 rect.color_index = 1 159 # when the azure clock runs out 160 if azure_clock > 500: 161 print("getting ntp date/time") 162 cal = ntp.datetime 163 year = cal[0] 164 mon = cal[1] 165 day = cal[2] 166 hour = cal[3] 167 minute = cal[4] 168 time.sleep(2) 169 print("getting msg") 170 # pack message 171 message = {"Temperature": temp, 172 "Humidity": humidity, 173 "Pressure": pressure, 174 "BatteryPercent": battery} 175 print("sending json") 176 device.send_device_to_cloud_message(json.dumps(message)) 177 print("data sent") 178 clock_view = "%s:%s" % (hour, minute) 179 if minute < 10: 180 clock_view = "%s:0%s" % (hour, minute) 181 print("updating time text") 182 time_text.text="\n".join(wrap_text_to_lines 183 ("Data sent on %s/%s/%s at %s" % (mon,day,year,clock_view), 20)) 184 # reset azure clock 185 azure_clock = 0 186 # when the feather clock runs out 187 if feather_clock > 30: 188 print("updating screen") 189 temp_text.text = "%0.1f° F" % temp 190 humid_text.text = "%0.1f %%" % humidity 191 press_text.text = "%0.2f" % pressure 192 # reset feather clock 193 feather_clock = 0 194 # if no clocks are running out 195 # increase counts by 1 196 else: 197 feather_clock += 1 198 azure_clock += 1 199 # ping azure 200 device.loop() 201 # if something disrupts the loop, reconnect 202 # pylint: disable=broad-except 203 except (ValueError, RuntimeError, OSError, ConnectionError) as e: 204 print("Network error, reconnecting\n", str(e)) 205 time.sleep(60) 206 supervisor.reload() 207 continue 208 # delay 209 time.sleep(1)