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()