# Smart Mailbox Author: Fatimah Ibrahim – fi222dq Time: Approximately 8-10 hours; might take less time if you are experienced. ## Overview This project shows how make your mailbox "smart" by incorporating a Raspberry Pi Pico W device, a tilt sensor and PIR (*passive infrared*) sensor to track new mail delivieries and send notifications over Wi-Fi connection when there are new mail deliveries. This project relies on the tilt sensor and the PIR sensor to know when there are new deliveries in the mailbox at specific intervals. :::info :information_source: This project is adapted to a mailbox model with a slot which is lifted to allow the delivery of letters, packages and more. ::: ## Objective Smart Mailbox is an IoT project that uses the Raspberry Pi Pico W including a tilt sensor and pir sensor to monitor and notify when there are new mail deliveries in your mailbox. The purpose of this project is to solve frequent, unnecessary checking of the mailbox when expecting a delivery. Another purpose of this project is to monitor exactly when mail deliveries arrive. This project can also be utilized for distant mailboxes that are far away where it would be inconvenient to do frequent check-ins. By completing this project, one would gain knowledge of using multiple sensors and communication between devices over Wi-Fi and data visualisation. This understanding can be utilized for creating more complex IoT devices which can help make mundane tasks or difficult easier. ## Material and Supplies :::success Tip By clicking the texts in the first column, you can go to the link where each components were bought. ::: | Component|Image| Description| Cost| | --------------------------------------------------------------------------------------------------------------- |:--------------------------------------------------:| --------------------------------------------------------------------------------------------------------------------------- | ------- | | [Raspberry Pi Pico W](https://www.electrokit.com/en/raspberry-pi-pico-wh)| ![image](https://hackmd.io/_uploads/H1WS3CH8A.png) | Microcontroller board with Wi-Fi which acts as the main control and processing unit of the project.|109 sek| | [Breadboard](https://www.electrokit.com/en/kopplingsdack-840-anslutningar)| ![image](https://hackmd.io/_uploads/ry-QaASL0.png) | Solderless breadboard for solderfree experiment circuits and prototype designs.|69 sek| | [Tilt sensor module](https://www.electrokit.com/en/tiltsensor)| ![image](https://hackmd.io/_uploads/BJ99a0HUA.png) | A module with a tilt switch for detecting when there is tilt or no tilt of an object or plane.|29 sek| | [PIR motion sensor HC-SR501](https://www.electrokit.com/pir-rorelsedetektor-hc-sr501)| ![image](https://hackmd.io/_uploads/HkAjpRBLA.png) | A sensor that detects the movement of a temperature higher than the surrounding area this includes also humans and animals.|50 sek| | [Resistor carbon film 0.25W 330ohm (330R)](https://www.electrokit.com/en/motstand-kolfilm-0.25w-330ohm-330r) ×3 | ![image](https://hackmd.io/_uploads/SJjn6Rr8A.png) | Used to limit the current and protect the Pico W's GPIO pins from potential damage| 3 sek| | [LED 5mm Red](https://www.electrokit.com/en/led-5mm-rod-diffus-1500mcd)| ![image](https://hackmd.io/_uploads/S1FRaCSLR.png) | Used as visual indicators to know when specific sensors or conditions are triggered.| 5 sek| | [LED 5mm Green](https://www.electrokit.com/en/led-5mm-gron-diffus-80mcd)| ![image](https://hackmd.io/_uploads/BJY1AAHU0.png) | Used as visual indicators to know when specific sensors or conditions are triggered.|5 sek| | [LED 5mm Yellow](https://www.electrokit.com/en/led-5mm-gul-diffus-1500mcd)| ![image](https://hackmd.io/_uploads/ryQg00HL0.png) | Used as visual indicators to know when specific sensors or conditions are triggered.|5 sek| | [Jumper wires 40-pin 30cm male/male](https://www.electrokit.com/en/labbsladd-40-pin-30cm-hane/hane)| ![image](https://hackmd.io/_uploads/ryiWCRB8R.png) | Used to connect the components together.|49 sek| | [Jumper wires 40-pin 30cm female/male](https://www.electrokit.com/en/labbsladd-40-pin-30cm-hona/hane)| ![image](https://hackmd.io/_uploads/BJk7RCSUC.png) | Used to connect the components together.|49 sek| | [USB cable A-male- microB-male](https://www.electrokit.com/en/usb-kabel-a-hane-micro-b-5p-hane-1.8m)| ![image](https://hackmd.io/_uploads/rJfV0RSUA.png) | Used for connecting the Raspberry Pi pico w to the or laptop/computer sources.| 39 sek| | [Powerbank Keep-Alive Device](https://www.electrokit.com/powerbank-keep-alive-device)| ![image](https://hackmd.io/_uploads/rkOLA0rI0.png) | A device used to keep powerbanks alive and prevent them from shutting down.|49 sek| | [PowerBank](https://www.biltema.se/kontor---teknik/mobiltillbehor/powerbanks/powerbank-10-000-mah-2000054284)|![image](https://hackmd.io/_uploads/ryGZ6IZvC.png)|Power source for the device|199 sek| | Box|-| Used for creating a mock-up/prototype mailbox to test the sensors before setting it up on the real thing.| -| :information_source: You are also going to need tape and blu tack to hold everything up together. --- ## Computer Setup The whole setup was done on a windows operating system so the following steps are specifically adapted to Windows OS and the steps might look different for other OS. - Set up your working environment in an IDE of your choice. You can either download [Visual Studio Code](https://code.visualstudio.com/Download) or [Thonny](https://thonny.org/) (I decided to go with VS Code) - **VS Code** - Install Pymakr plugin through VS Code by navigating to the extensioin bar and also install Node.js. - Pymakr plugin provides features that are useful during the project development; this includes device management (can be very useful if you are using other micro controllers), deployment and flashing project code into the Raspberry pi pico w. - **Thonny** - Add the MicroPython firmware to the Raspberry pi pico w (motivate each step by explaining their purpose). Download the MicroPython firmware [here](https://micropython.org/download/RPI_PICO_W/). - **VS Code** - Add the firmware by following the steps outlined in the image below. Detailed steps can be found [here](https://www.raspberrypi.com/documentation/microcontrollers/micropython.html). ![image](https://www.raspberrypi.com/documentation/microcontrollers/images/MicroPython-640x360-v2.gif =90%x) - **Thonny** - The firmware can be installed into the Raspberry pi pico w through Thonny IDE by setting the interpreter to the “MicroPython (Raspberry Pi Pico)”. This triggers a dialog box that prompts the installation of the Micropython firmware. Detailed steps can be found [here](https://projects.raspberrypi.org/en/projects/introduction-to-the-pico/3). - Create a new project called Smart Mailbox in your IDE - Connect the Raspberry pi pico w to the project (**VS Code**). - Ensure that the Pico W is connected to the computer through the USB cable. In VS Code, the Raspberry pi pico can be connected to the project code by clicking on the Pymakr logo and clicking on the “ADD DEVICES” section to add your to the project and by clicking on </> sign (developer mode) you are able to deploy and flash new updated codes onto the device. --- ## Putting everything together ### Circuit Diagram ![image](https://hackmd.io/_uploads/ByaSWZ2L0.png =90%x) :warning: Disconnect the Raspberry Pi Pico W from your laptop or any power source before wiring all the components together. All the components in the project are connected with jumper wires on a breadboard which means that it is only for a development setup. However, this setup is not suitable for production since the wire connections are loose and the components are not weatherproof or stable. It can be used in production if the connections are soldered and 3d printed components are incorporated. ![image](https://hackmd.io/_uploads/H1U_cr2UR.png) Modify the box by adding a slit to represent the mail slot. Then set up the wired components inside the prototype. The tilt sensor is mounted around the rotating joint of the opening slot of the “mailbox” and the PIR sensor is mounted on the walls of the mailbox to allow the detection of incoming objects into the mailbox. :::info :information_source: Pay attention to placement of the PIR sensor in the mailbox as the opening of the slot can expose the pir sensor to external environment thus leading to interference. This can also result in false positives where a mail entry is published even though the slot was opened but no letter or package was dropped in. ::: ## Platform Adafruit IO was the chosen platform for the project because it is free, easy and quick to setup considering the time constraint of the project. It is a cloud-based platform with a built in MQTT server that provide data visualization, control and monitoring features which allows for communication with IoT devices. Adafruit IO has a basic plan level which allows a user to create maximum 10 data feeds & dashboards and it also offers 30 days data retention of data published by the IoT device. Furthermore, webhooks can be integrated to create a notification functionality when there are new mail deliveries. ## The code :::info :information_source: [The full code for the project can be viewed here](https://github.com/OlamideIbrahim/Smart-Mailbox). ::: :::success The code relies on if statements as well as the readings of the tilt sensor and the PIR sensor to determine the state of the mailbox. If the value of the tilt sensor is triggered (i.e. if the value changes from 0 to 1) and the PIR sensor is not triggered then the mail was only opened and the open_mailbox_count counter variable increases. However, if both the tilt sensor and the PIR sensor was triggered then that indicates a new mail delivery and the new_mail_entry_value increases. The readings continue until the prescribed time interval is met and the counter values are published to their respective feeds on Adafruit IO. **Tip** When setting up and testing out the components keep an eye on the terminal for print statements which indicates when the sensors or certain conditions are triggered. ::: The **main.py** file which contains the main code required to run the Raspberry Pi Pico W imports from external libraries as well as files which are used to store credentials. This structure aims to keep the code neat and clean. The code in **mqtt.py** and **wifiConnection.py** are not self-written code but provided by the course [here](https://github.com/iot-lnu/pico-w/tree/main/network-examples/N2_WiFi_MQTT_Webhook_Adafruit/lib); the files can also be downloaded from the link above. **ntptime.py** is another microphyton library used to set the RTC (real-time clock) of the Raspberry Pi Pico W device; this is required to set the sleep functionality at a particular time. The ntptime library can be downloaded [here](https://github.com/micropython/micropython-lib/blob/f6723531802661e5a1fd3d63d3b7b68c38f40cd2/micropython/net/ntptime/ntptime.py). The **keys.py** file contains all the required credentials that includes the Wi-Fi SSID and password as well as Adafruit IO keys and username which are required to establish WiFi connection and publish data to Adafruit IO. Fill in your credentials in **keys.py** in order to connect to your Wi-Fi and Adafruit IO when you run the code in **main.py**. #### Required libraries ```python! from machine import Pin import machine import keys # imports the required credentials for wifi and adafruit io import time from mqtt import MQTTClient # For use of MQTT protocol to talk to Adafruit IO import wifiConnection # Contains functions to connect/disconnect from WiFi import ntptime # Used to set up the rtc time in the pico device in utc(doesnt account for time zones) ``` #### Main variables The first part of the code contains all the variables to set up time intervals for publishing messages to Adafruit IO, the intialization of the led lights and sensors connect to the Raspberry Pi Pico W and the configuration of the RTC on the device. Since the ntptime library does not address time zone differences, the UTC (Coordinated Universal Time) time might be different to the actual time in your location. In my case the time difference was 2 hours, however, since I only need the current hour to know when the device is going to sleep, I created the `time_offset` variable and added it to the current hour in UTC. ```python! # Configure time intervals and counters publish_message_interval = 1.2 * 10**6 # publish data to adafruit every 20 minutes last_sent_mail_entry = 0 # number of ms after the last sent message to adafruit last_sent_open_mailbox_entry = 0 # number of ms after the last sent message to adafruit new_mail_entry_count = 0 # delivery entries counter open_mailbox_count = 0 # number of times the mailbox was opened last_random_sent_ticks = 0 # milliseconds # Led lights red = Pin(14, Pin.OUT) green = Pin(15, Pin.OUT) yellow = Pin(13, Pin.OUT) led = Pin("LED", Pin.OUT) # Tilt and PIR sensor tilt = Pin(22, Pin.IN) pir = Pin(26, Pin.IN) # Configure the date and time of the pico using the ntp library # (yrs, mths, day, wkday, hrs, m, s, subseconds) format rtc = machine.RTC() ntptime.settime() # Check if the date and time is configure correctly on the device print("Current time: ", rtc.datetime()) # Enter time offset (ntp doesn't account for timezones) time_offset = 2 # +2 hours ``` #### Functions The following functions are used to publish data to Adafruit IO feeds and dashboard.` send_new_mail_entry` and `send_open_mailbox_entry` publish data every 20 minutes while `send_mailbox_activity` publish data whenever it is called. ```python! def send_new_mail_entry(counter_value: int): global last_sent_mail_entry global publish_message_interval if ((time.ticks_ms() - last_sent_mail_entry) < publish_message_interval): return False; print("Publishing: {0} new mail entry to {1} ... ".format(counter_value, keys.AIO_MAIL_ENTRY_FEED), end='') try: client.publish(topic=keys.AIO_MAIL_ENTRY_FEED, msg=str(counter_value)) print("DONE") except Exception as e: print("FAILED") finally: last_sent_mail_entry = time.ticks_ms() def send_open_mailbox_entry(counter_value: int): global last_sent_open_mailbox_entry global publish_message_interval if ((time.ticks_ms() - last_sent_open_mailbox_entry) < publish_message_interval): return False; print("Publishing: {0} open mail entry to {1} ... ".format(counter_value, keys.AIO_OPEN_MAIL_FEED), end='') try: client.publish(topic=keys.AIO_OPEN_MAIL_FEED, msg=str(counter_value)) print("DONE") except Exception as e: print("FAILED") finally: last_sent_open_mailbox_entry = time.ticks_ms() # Function to set the indicator on the Adafruit IO dashboard # Red means the device is asleep and Green means the device is awake and active def send_mailbox_activity(value): if value == 1: print("Publishing: {0} Mailbox is still active ... ".format(keys.AIO_SLEEP_FEED), end='') else: print("Publishing: {0} Mailbox is going to sleep ... ".format(keys.AIO_SLEEP_FEED), end='') try: client.publish(topic=keys.AIO_SLEEP_FEED, msg=str(value)) print("DONE") except Exception as e: print("FAILED") ``` #### Connectivity The following code uses the imported libraries to connect to the Wi_Fi and the MQTT server on Adafruit IO. When it the connection is complete, `send_mailbox_activity(1)` is called to tell publish to Adafruit IO that the device is awake and active. ```python! # WiFi Connection try: ip = wifiConnection.connect() except KeyboardInterrupt: print("Keyboard interrupt") # Connect to the MQTT server client.connect() print("Connected to %s" % (keys.AIO_SERVER)) print("Mailbox waking up.................") # Publish data to the sleep feed that the device is now awake send_mailbox_activity(1) # A short wait period to make sure the data was published time.sleep(3) ``` #### Main Logic The main logic accumulate the readings of the tilt sensor and the PIR sensor in the counter variables new_mail_entry_count and open_mailbox_count for 20 minutes before they are published to the server and set to zero again. The second part of this section checks to see if is within the hours 7-17 and if it is False then it turns on the led light, publish 0 to the sleep feed to indicate that the device is asleep befor it falls into deep sleep for the rest of the day until it is 7:00 again. The deep sleep hour is calculated by multiplying the remaining hour and converting into milliseconds. ```python! # MAIN LOGIC OF THE DEVICE IN A WHILE LOOP try: # Send to Adafruit that the device is awake while True: # Checks if the mail is open i.e the tilt sensor is triggered if tilt.value() == 1: print("Mail open !") # Led indicators green.off() red.on() pir.value(0) # intialize the pir sensor which might have been triggered by the tilt action # Added a time sleep to improve accuracy and reduce false positives time.sleep(1.5) # Logic for checking if there is a new mail delivery if pir.value() == 1 and (tilt.value() == 1 or tilt.value() == 0): # increases the new mail entry counter value by 1 new_mail_entry_count += 1 print("New drop in mailbox !") # Led indicators green.off() red.off() yellow.on() time.sleep(0.5) else: # counts the amount of time the mail has been opened within a time interval open_mailbox_count += 1 else: print("...", end='') # Led indicators red.off() yellow.off() green.on() time.sleep(0.5) # PUBLISHES THE DATA TO ADAFRUIT AT FIXED INTERVALS # Whenever the following if conditions are met, the counter starts from zero again if send_open_mailbox_entry(open_mailbox_count) != False: open_mailbox_count = 0 if send_new_mail_entry(new_mail_entry_count) != False: new_mail_entry_count = 0 # Checks if the current hour is between the 07:00 and 17:00 (common delivery hours) current_time = rtc.datetime() # used to get time in (yrs, mths, day, wkday, hrs, m, s, subseconds) format current_hour = tuple(current_time)[4] # gets the current hour from the current_time current_hour += time_offset # The hour interval in which the pico w device is active is 7-17 sleep_hour = 24 - (17-7) sleep_hour_ms = sleep_hour * 3600000 if (7 <= current_hour < 17) is False: # Changes the indicator in the dashboard to red i.e send_mailbox_activity(0) print("Mailbox going to sleep............") led.on() time.sleep(3) machine.deepsleep(sleep_hour_ms) ``` ## Transmitting the data and connectivity In terms of connectivity, the intial plan was to use LoRaWAN to reduce power consumption and make the device suitable for long range setup in mailboxes that might be located far away, however due to bad gateway coverage of connection, the device was unable to connect to a gateway most of the time (*it was able to connect to a gateway once but unable to connect it again*). Due to this limitation, Wi-Fi connection was used. Although Wi-Fi offers wireless connection it however consumes more power and than LoRaWAN. As stated earlier, Adafruit IO MQTT server, dashboards and webhooks are used to store and visualize the data read from the sensors and the Raspberry Pi Pico W. The readings are acummulated in a counter variable and are published every 20 minutes when the device is awake. When there are new mail deliveries, the notification for the mailEntries feed is triggered and a message is sent to a server on Discord. The interval was set to 20 minutes to ensure that new mail deliveries are immediately notified to the user directly through the Discord webhooks since the notification funtionality on Adafruit IO is limited to 15 minutes. ## Presenting the data Since the project utilizes the Basic Plan of the Adafruit IO platform it is limited to data storage(*data is only stored for 30 days*) and more personalization in the long run. Hence a self-hosted platform would be more suitable for production use. I plan to try out TIG-stack to for more flexiblility in terms of data retention and visualization and notification functionalities. Overall, data is published to Adafruit IO every 15 minutes and is stored up to 30 days. ![image](https://hackmd.io/_uploads/SJyS4m3UA.png) #### Building the dashboard The dashboard is built by using the feeds in the picture below. ![image](https://hackmd.io/_uploads/BJT3yQnIA.png =90%x) The linechart block is used to present the data in the opened-mailbox and maiboxentries feeds. An indicator block is used to visualize the data in the sleep feed, where 1 result in a green color and 0 results in a red color. And finally, the current mail deliveries is visualized using the icon block. ![image](https://hackmd.io/_uploads/SkUU17280.png =90%x) #### Webhooks The actions which implements the Discord notification functionality is only triggered when the number logged on the mailboxEntries feed is greater than 0. ![image](https://hackmd.io/_uploads/Hyffe728R.png =90%x) ![image](https://hackmd.io/_uploads/SyD2gm28A.png =90%x) ## Finalizing the design ![finished prototype](https://hackmd.io/_uploads/Hk_avHgwA.jpg =85%x) The final product is only a prototype and fragile due to the solderless connections made with jumper wires and breadboards. As stated earlier, soldering wire connections and incorporating 3d printing can improve the durability of the project thus making it suitable for production use. Given the time constraint of the project, there is definitely a lot of room for future improvement, that includes: - Reducing false positives which are triggered by external interference. This can done by investing in more specific and accurate sensors suitable for the mailbox. - Proper sealing and weatherproofing of the components to prevent damage external environment. - Using load cell to improve accuracy and reliablity as well as monitor the contents of the mailbox. - Opt for LoRaWAN if there is good coverage to improve the life span of the powerbank. My intial plan was to use LoRaWAN however I was only only to connect to a gateway once. I would definitely love to try out the LoRaWAN module. - Using a more flexible platform such as TIG stack Overall, I had a lot of fun doing this project, it was definitely a great eye opener to the world of IoT devices and and I would definitely love to improve this project for personal use and perhaps try out other IoT projects in the future. Video presentations here - [Prototype](https://youtu.be/124pg1q10yI). - [Mailbox](https://youtube.com/shorts/DEjGKBeoViI).