/ Feather_Freezer_Alarm / code.py
code.py
1 # SPDX-FileCopyrightText: 2022 Matt Desmarais for Adafruit Industries 2 # 3 # SPDX-License-Identifier: MIT 4 5 import time 6 import ssl 7 import microcontroller 8 import socketpool 9 import wifi 10 import board 11 import adafruit_minimqtt.adafruit_minimqtt as MQTT 12 from adafruit_io.adafruit_io import IO_MQTT 13 import digitalio 14 from adafruit_debouncer import Debouncer 15 16 #setup buzzer1 17 buzzer1 = digitalio.DigitalInOut(board.D13) 18 buzzer1.direction = digitalio.Direction.OUTPUT 19 20 #setup buzzer2 21 buzzer2 = digitalio.DigitalInOut(board.D11) 22 buzzer2.direction = digitalio.Direction.OUTPUT 23 24 #setup left door switch 25 leftdoor = digitalio.DigitalInOut(board.D5) 26 leftdoor.direction = digitalio.Direction.INPUT 27 leftdoor.pull = digitalio.Pull.UP 28 leftswitch = Debouncer(leftdoor) 29 30 #setup right door switch 31 rightdoor = digitalio.DigitalInOut(board.D9) 32 rightdoor.direction = digitalio.Direction.INPUT 33 rightdoor.pull = digitalio.Pull.UP 34 rightswitch = Debouncer(rightdoor) 35 36 #setup motion sensor 37 pir = digitalio.DigitalInOut(board.D6) 38 pir.direction = digitalio.Direction.INPUT 39 motion = Debouncer(pir) 40 41 try: 42 from secrets import secrets 43 except ImportError: 44 print("WiFi and Adafruit IO credentials are kept in secrets.py - please add them there!") 45 raise 46 47 # Add your Adafruit IO Username and Key to secrets.py 48 # (visit io.adafruit.com if you need to create an account, 49 # or if you need to obtain your Adafruit IO key.) 50 aio_username = secrets["aio_username"] 51 aio_key = secrets["aio_key"] 52 53 # WiFi 54 try: 55 print("Connecting to %s" % secrets["ssid"]) 56 wifi.radio.connect(secrets["ssid"], secrets["password"]) 57 print("Connected to %s!" % secrets["ssid"]) 58 # Wi-Fi connectivity fails with error messages, not specific errors, so this except is broad. 59 except Exception as e: # pylint: disable=broad-except 60 print("Failed to connect to WiFi. Error:", e, "\nBoard will restart in 5 seconds.") 61 time.sleep(5) 62 microcontroller.reset() 63 64 # Create a socket pool 65 pool = socketpool.SocketPool(wifi.radio) 66 67 # Initialize a new MQTT Client object 68 mqtt_client = MQTT.MQTT( 69 broker="io.adafruit.com", 70 username=secrets["aio_username"], 71 password=secrets["aio_key"], 72 socket_pool=pool, 73 ssl_context=ssl.create_default_context(), 74 ) 75 76 # Define callback functions which will be called when certain events happen. 77 def connected(): 78 print("Connected to Adafruit IO! Listening for Freezer changes...") 79 80 # Initialize Adafruit IO MQTT "helper" 81 io = IO_MQTT(mqtt_client) 82 83 # Set up the callback methods above 84 io.on_connect = connected 85 86 #start time for timed uploads 87 start = int(time.time()/300) 88 #door timers set start times to now 89 start1 = time.monotonic() 90 start2 = time.monotonic() 91 #door alarms set to False 92 prealarm = False 93 alarm1 = False 94 alarm2 = False 95 96 door1feed = "unit-6.door1" 97 door2feed = "unit-6.door2" 98 motionfeed = "unit-6.motion" 99 alarmfeed = "unit-6.alarm" 100 resolvedfeed = "unit-6.resolved" 101 #reconnectedfeed = "unit-6.reconnected" 102 103 #initial publishes all zeros 104 try: 105 io.connect() 106 # Adafruit IO fails with internal error types and WiFi fails with specific messages. 107 # This except is broad to handle any possible failure. 108 except Exception as e: # pylint: disable=broad-except 109 print("Failed to get or send data, or connect. Error:", e, 110 "\nBoard will restart in 20 seconds.") 111 time.sleep(20) 112 microcontroller.reset() 113 io.publish(alarmfeed, 0) 114 io.publish(resolvedfeed, 0) 115 116 while True: 117 try: 118 # If Adafruit IO is not connected... 119 if not io.is_connected: 120 # Connect the client to the MQTT broker. 121 print("Connecting to Adafruit IO...") 122 io.connect() 123 124 time.sleep(1) 125 #update leftswitch 126 leftswitch.update() 127 #if door closed upload to IO 128 if leftswitch.fell: 129 print('left closed') 130 io.publish(door1feed, 1) 131 time.sleep(.25) 132 io.publish(door1feed, 0) 133 #if door opened upload to IO, set start1 to now 134 if leftswitch.rose: 135 print('left opened') 136 io.publish(door1feed, 1) 137 start1 = time.monotonic() 138 #if door remains open 139 if leftswitch.value: 140 print('still left open') 141 #if door remains closed, reset start1 142 else: 143 #door still closed reset timer 144 print('still left closed') 145 start1 = time.monotonic() 146 147 #update rightswitch 148 rightswitch.update() 149 #if door closed upload to IO 150 if rightswitch.fell: 151 print('right closed') 152 io.publish(door2feed, 1) 153 time.sleep(.25) 154 io.publish(door2feed, 0) 155 #if door opened upload to IO, set start2 to now 156 if rightswitch.rose: 157 print('right opened') 158 io.publish(door2feed, 1) 159 start2 = time.monotonic() 160 if rightswitch.value: 161 print('still right open') 162 #door still closed reset timer 163 else: 164 print('still right closed') 165 start2 = time.monotonic() 166 167 #if a door closes update both switches 168 if rightswitch.fell or leftswitch.fell: 169 rightswitch.update() 170 leftswitch.update() 171 #if both doors are closed 172 if not rightswitch.value and not leftswitch.value: 173 print('doors just closed') 174 #if prelarm is true then set it to False 175 if prealarm is True: 176 buzzer1.value = False 177 #if an alarm is true then upload to IO alarm resolved 178 if alarm1 or alarm2: 179 #publish 0 to alarm feed 180 io.publish(alarmfeed, 0) 181 #buzzers off/Alarms to False 182 buzzer1.value = False 183 buzzer2.value = False 184 alarm1 = False 185 alarm2 = False 186 #toggle alarm resolved feed to send email notification 187 io.publish(resolvedfeed, 1) 188 time.sleep(5) 189 io.publish(resolvedfeed, 0) 190 191 #check motion sensor if there is no alarm 192 if(not alarm1 and not alarm2 and not prealarm): 193 #update pir sensor 194 motion.update() 195 #if motion stopped 196 if motion.fell: 197 print('motion stopped') 198 #publish 0 to motion feed 199 io.publish(motionfeed, 1) 200 time.sleep(.25) 201 io.publish(motionfeed, 0) 202 #if motion started 203 if motion.rose: 204 print('motion detected') 205 #reset start times 206 start1 = time.monotonic() 207 start2 = time.monotonic() 208 #if continued motion 209 elif motion.value: 210 print('still motion') 211 io.publish(motionfeed, 1) 212 time.sleep(5) 213 #if continued no motion 214 else: 215 print('no motion') 216 217 print("\n") 218 219 # Explicitly pump the message loop to avoid MQTT timeouts. 220 io.loop() 221 222 #check difference between time now and start times if more than N seconds start beeping 223 if (((time.monotonic() - start1) >= 300) or ((time.monotonic() - start2) >= 300)): 224 prealarm = True 225 #beeping 226 buzzer1.value = True 227 time.sleep(.5) 228 buzzer1.value = False 229 230 #check if difference between time now and start1 if more than X seconds turn on buzzer2 231 if (alarm1 is False and ((time.monotonic() - start1) >= 600)): 232 alarm1 = True 233 buzzer2.value = True 234 #publish 1 to alarm feed 235 io.publish(alarmfeed, 1) 236 237 #check if difference between time now and start2 if more than X seconds turn on buzzer2 238 if (alarm2 is False and ((time.monotonic() - start2) >= 600)): 239 alarm2 = True 240 buzzer2.value = True 241 #publish 1 to alarm feed 242 io.publish(alarmfeed, 1) 243 244 #check if 300 seconds have passed compared to start time, if so publish values 245 if int(time.time()/300) > start: 246 print("PUBLISH EVERY FIVE MINUTES") 247 start = int(time.time()/300) 248 io.publish(door1feed, int(leftswitch.value)) 249 io.publish(door2feed, int(rightswitch.value)) 250 io.publish(motionfeed, int(motion.value)) 251 252 # Adafruit IO fails with internal error types and WiFi fails with specific messages. 253 # This except is broad to handle any possible failure. 254 except Exception as e: # pylint: disable=broad-except 255 print("Failed to get or send data, or connect. Error:", e, 256 "\nBoard will restart in 20 seconds.") 257 time.sleep(20) 258 microcontroller.reset()