Saturday, June 12, 2021

You've got mail! A mailbox sensor for Home Assistant


Would you like to have an announcement made, or to receive a notification on your phone when the mailman has visited and left your daily delivery?  There are now commercial options available, but you can easily build your own local device for around $35 and integrate it into Home Assistant with voice announcements via Google Home or Amazon Alexa.
I don't know about where you live, but our mail delivery is very inconsistent from day to day.  Some days, the mail may be delivered by 10:30 am, but on others it can be after 6:00 pm.  I don't know why.  But probably like many of you, we do a lot of online ordering.  I wanted to find a way to know when the mail had arrived so I could snag it without making multiple daily trips to the box to see if it had arrived yet.  I originally designed and built this a little over a year ago, so different options are available today that you may want to consider if you want less "DIY"... but what fun is that?  Read on if you'd like to know more about a fun little project that will natively integrate into Home Assistant.

Before you begin

This design uses WiFi to connect to your home network.  Check to see if you have an acceptable WiFi signal at your mailbox.  The sensor is only going to send a very small amount of data a couple of times a day, so it's not like you need a super strong signal to stream video or anything, but the device must be able to connect.  Take your phone out to your mailbox and check your WiFi signal.

Note that there are other wireless communication methods, such as Zigbee and ZWave that could be used (and would be better on battery life), but these will require additional hardware in terms of hubs that will connect these protocols to your WiFi.  I wanted to keep the design cheap, so I sacrificed battery life in exchange for not needing an additional hub.

Next, consider where and how you will mount the sensor and battery pack.  If you have a metal mailbox, you will likely not be able to place the sensor in the mailbox as it will kill any WiFi signal you might have.  I'm fortunate to have a mailbox on 4x4 posts.

The area highlighted was a perfect spot to mount both the sensor and battery, and offered the additional advantage of offering some protection from the elements.

Parts List

 Here are the major parts you will need.

Qty

Description

1

ESP32 Development Board

1

7.4V Lithium-Ion Battery (2 pk) and charger

1

5V Step up/step down voltage regulator

1

Mini SPDT Slide Switch (50 pk) - optional

1

Electrocookie Protoboard (5pk)

-

Assorted Spade Connectors

1

Magnetic Reed Switch (for mailbox door)

1

20-gauge solid and 20-gauge stranded wire

1

10 kΩ & 15 kΩ resistors

Note: Some links may be Amazon affiliate links.  This does not affect your pricing, but this blog may earn a small commission towards future projects if you use these links for your purchase.

You will also need the standard tools for working on electronic projects, e.g. soldering iron, wire stripper, etc.

Assembly

(Note: Before beginning assembly, it is recommended that you load the ESPHome binary onto the ESP32 development board.  See the section below for information on ESPHome and the code needed).

There are two parts to the assembly; the primary control board and the battery pack. We'll start with the primary control board.

Primary Control Board Assembly

Here's the schematic for assembly:


And a photo of the assembled board for additional reference:


Since the battery we will be using is a 7.4V Li-ion battery pack and the ESP board runs off of 5V, a 5-volt step-up/step-down voltage regulator is needed.  In addition, to be able to monitor battery power and know when it is time to replace it, a voltage divider is created with two resistors that feed into the analog pin on the ESP.

Here are a few additional notes:
Not all ESP32 boards have the same pin layout.  I'll note the actual GPIO pins I used below and you may need either adjust your wiring to match the same GPIO pins, or adjust your code to match the pins you do use.

Keep your wiring leads (with the spade connectors) fairly short as as the leads from the battery and reed switch will feed into the enclosure and connect within the enclosure.  This just helps a bit with weather protection and not exposing the actual connections directly to the elements.

First, solder the ESP32 development board to the protoboard.  I aligned the first pin of the ESP32 to column 1 of the protoboard, so I'll reference the column numbers and row letters for other connections.  You should adjust accordingly if you board is different or you solder in a different location.

Next, solder the voltage regulator to the protoboard.  I used columns 23-25 of row G.

Connect a short lead to the Vin (+) connection of the voltage regulator (column 25) and another short lead to the com/gnd of the regulator (column 24).  This will connect to the positive/negative leads from the battery.

Solder a short connection wire (I use solid core wire for onboard connections) between the com/gnd of the voltage regulator (column 24) and the negative power rail at the top of the board.  Solder another short connection between the Vout of the regulator (column 23) and the positive power rail.

Next connect the VIn (5V) pin from the ESP32 (column 1) to the positive power rail and a ground (GND) pin to the negative rail.  For my board, this was column 6, but double check your board and adjust as necessary to make a connection to any ground pin.

Now we will create the voltage divider.  To calculate the resistor values, I used an online voltage divider calculator.  Remember that the maximum input voltage on any of the pins on the ESP32 is 3.3v.  If we exceed this voltage, there is a risk of creating some 'magic blue smoke' and frying the board.  Even though the battery I'm using is rated at 7.4V, when fully charged, I measured right at 8V.  So, to be safe I used 8V as my source.


With a 15K and 10K resistor, it brings me in at a max of 3.2 volts.  If you are using a battery with a different voltage, measure at full charge and adjust your resistors accordingly to stay under the 3.3V max.

Connect one end your first resistor to the same column as the input voltage and the regulator Vin (column 25 for me).  Connect the other end to an unused column (I used column 21).

Connect the second resistor to this same column and the negative (ground) power rail.

Now run a connection between the divider column and GPIO 34 (column 15 on my ESP board).  If you use a different GPIO, assure it support analog input and you'll need to adjust the ESPHome file to match the pin you used.

Lastly connect a short lead to GPIO 13 (column 5) and another lead to any available ground pin (I used column 19 on row A).  These will connect to the magnetic reed switch and will 'wake' the ESP32 from deep sleep when the switch is opened by pulling GPIO 13 low.  If you use a different pin, assure this pin is listed as one that will wake the ESP32 from sleep... and adjust ESPHome accordingly.

Battery Pack Assembly

As mentioned above, I opted to use 7.4V Li-ion batteries.  I selected these particular batteries for a few reasons.


These are actually made for use in RC cars, but provide two connectors... one for connecting to the charger and another for the power output.  This allowed me to cut off the power output connector and add spade connectors, while maintaining the original connector for recharging.



The wiring for the battery is pretty straightforward.

Again, you want the leads from the battery fairly short, so that the actual spade connections fit within whatever enclosure you opt to use for the battery.  The mini switch is entirely optional, but does allow you to cut the power to the ESP board when swapping batteries.

The length of the leads from the battery to the ESP32 board will be dependent upon your mounting location.  The goal in the entire battery wiring and mounting is to protect it from the weather as much as possible, while at the same time making it easy to replace the battery when needed.  Here's the final design that I used in a 3D printed enclosure:


When it comes time to swap batteries, the enclosure slides out from the mount under the mailbox.  I disconnect the two leads, slide out the battery, slide in a fresh battery and reconnect the leads.  The enclosure then slides back into the mount.  The whole process takes about 45 seconds.

Magnetic Reed Switch

There really isn't much to do here.  You will likely need to extend the length of wiring from the switch to reach the ESP32 board and add the appropriate spade connectors to the end.  The only thing to note here is if your reed switch has 3 wires (mine had 2 white and 1 brown), you want to use the two wires that result in the switch being normally open (NO) and not normally closed (NC).

Installation and Mounting

The actual installation is going to be dependent on the design of your mailbox.  But there are a few key objectives to keep in mind:

  • As much as possible, try to protect the electronic components from the elements.  You could optionally place the components in waterproof enclosures.  I used 3D printed enclosures, so I added hot glue to all the 'non-removable connections (e.g. solder joints, ESP pins, etc.) to protect and help prevent corrosion.
  • The battery should be easily accessible for swapping with a fully charged battery when necessary.
  • The reed switch must be positioned so that it shows an open state when the mailbox door is opened and consistently closed when the door is closed.  It may be necessary to use spacers for alignment.  Also I'd recommend running the wiring from the switch on an upper corner of the interior of the mailbox if possible.  You want to assure the wires don't get snagged when inserting or removing packages.
Here are some photos of how I mounted mine:


I used 3D printed brackets that screw into the wood structure of the mailbox post.  Both the control board and battery enclosures slide into these brackets.  There is enough slack wire that I can easily slide out the battery enclosure and swap out the battery when necessary.  In addition, if necessary, I can also slide out the control board enclosure and disconnect the spade connector leads if I need to work on (or replace) the control board.


For the reed switch, I needed to 3D print a small spacer so that the wired portion of the reed switch aligned with the non-wired section, which is attached to the door.  I used a simple wire clip and tape to keep the wiring at the top of the box to avoid any snags with packages.  

ESPHome, Home Assistant and Google Voice Announcements


If ESPHome is not installed in Home Assistant, or if you have not created a new node before, you can find information on how to do so at Getting Started with ESPHome and Home Assistant.  Using the wizard, you will enter a name for your new node, select the platform (e.g. ESP32), enter your WiFi credentials and set an optional over-the-air update password.  This will create a starting .yaml file that so far will only connect the board to your WiFi.  Now you have to define the sensors and other options for the binary.

For this project, we will create two binary sensors for the connection status and door status and a sensor for the battery voltage.  We also need to add deep sleep and MQTT.  Here's the full code that I added to the default ESPHome node:

binary_sensor:
  - platform: status
    name: "Mailbox Sensor Status"

  - platform: gpio
    filters:
      - delayed_on_off: 200ms
    pin:
      number: GPIO13
      mode: INPUT_PULLUP
    name: "Mailbox"
    device_class: door

sensor:
  - platform: adc
    pin: GPIO34
    name: "Mailbox Battery"
    attenuation: 11db
    update_interval: 30s
    filters:
      - calibrate_linear:
        - 3.05 -> 6.8
        - 3.30 -> 7.0
        - 3.45 -> 7.2
        - 3.60 -> 7.4
        - 3.75 -> 7.6
        - 3.90 -> 8.0

deep_sleep:
  run_duration: 90s
  wakeup_pin: GPIO13
  wakeup_pin_mode: INVERT_WAKEUP
  id: mail_deep_sleep

mqtt:
  broker: 192.168.1.108
  username: My_MQTT_User
  password: my_mqtt_password
  discovery: false
  discovery_retain: false

The first binary sensor will return the current status of the ESP32.  When active and connected, this will return a state of "on" and when in deep sleep will show a state of "off".

The second binary sensor is the state of the door (or technically the magnetic reed switch).  It will report a state of 'on' (open) or 'off' (closed).  However, when the ESP32 is in deep sleep (off), the door will report a state of unavailable.  For this reason, we will be using the status binary sensor in our automations.

The battery sensor may take some testing and adjusting depending upon your particular battery.  As you recall from earlier, we are using a voltage divider to scale down the incoming battery voltage to the maximum 3.3V that the ESP32 can handle on an input pin.  The filter defined here will scale that value back up to the approximate true voltage of the battery.  Note that this will only be an estimate at best, but the value is simply used as a source to let you know when it is time to replace the battery.  See the ESPHome documentation on using Analog to Digital Sensors for more details on how to define the attenuation and filters.

deep_sleep enables deep sleep on the ESP32 board.  You specify the pin that will wake the board from deep sleep (GPIO pin 13 that is connected to the reed switch) and how long the board should remain awake before returning to deep sleep.  This value may also vary in your case, but you should make it as short as possible to conserve battery.  But you need to allow enough time for the board to wake, connect to your wifi and transmit the data.  If you find that the board is not consistently sending status and voltage, you may need to increase the wake time.

Finally, we define a connection to our MQTT broker.  This is needed so that we can retain the most recent values of the sensors when the ESP32 goes into deep sleep.  If Home Assistant is restarted when the ESP32 is in deep sleep, the values for the door status and the battery voltage will be reported as unavailable since Home Assistant cannot connect to the board.  By enabling MQTT, the ESP32 will published all the latest sensor values to the broker with a RETAINED flag.  This means the latest reported values are always available to Home Assistant for use in our other sensors, scripts and automations.

Once you've added the necessary code, verify, compile and download the binary (.bin) file to your computer.  You can then upload the binary to the ESP32 via a tools such as ESPHome Flasher or NodeMC- PyflasherIF YOU HAVE ALREADY CONNECTED YOUR ESP32 TO A BATTERY, DISCONNECT FROM THE BATTERY PRIOR TO CONNECTING THE ESP32 WITH A USB CABLE!  Never connect two power sources to your board at the same time or you will likely fry the board.

Once you upload the code and the board reboots, Home Assistant will auto-detect a new integration and prompt you to add it.  When you do so, the sensors you defined in the ESPHome node will automatically be added to Home Assistant.  In addition, the current sensor values will be sent and stored in your MQTT broker.

There are a few other entities we need to create for our use in scripts and automations.  

Sensors
# ================================
# Mailbox Battery Voltage via MQTT
# ================================
# Gets voltage value from MQTT retained value
  - platform: mqtt
    name: "Mailbox Battery MQTT"
    state_topic: "mailbox_sensor/sensor/mailbox_battery/state"
    value_template: "{{ (value | float) | round(2) }}"
    unit_of_measurement: "V"
    qos: 2
    icon: mdi:battery-70

This will create sensor for the battery voltage based on the retained MQTT value instead of from the ESP32.  This avoids the 'unavailable' status seen on a Home Assistant reboot and assures the battery voltage is always available.  This MQTT value will be updated each time the ESP32 wakes up.

Binary_Sensors
# =============================
#  Mailbox Battery Low
# =============================
- platform: template
  sensors:
    mailbox_battery_low:
      value_template: "{{ states('sensor.mailbox_battery_mqtt')|float < 6.00 }}"

This is a simple "true/false" sensor that will be set to true when the battery voltage drops below a certain value.  It can be used in an automation to notify you that it is time to swap out the battery.  You can adjust the voltage to your particular battery and preference.

Input_Boolean
#######################
# Mail Delivered
#######################
mail_delivered:
  name: Mail Delivered
  initial: off
  icon: mdi:mailbox

This is a simple boolean value used to indicate whether mail has been delivered (true) or that the mail has been picked up (false).

Scripts
Two scripts are needed for the automation.  One for when the mail is delivered and one for when it is picked up.

mail_delivery:
  alias: Mail Delivered
  sequence:
    - service: input_boolean.turn_on
      data:
        entity_id: input_boolean.mail_delivered
    - service: media_player.play_media
      data_template:
        entity_id: media_player.all_home_devices
        media_content_id: '{{"http://192.168.1.108:8123/local/sounds/mail0"~(range(1, 6)|random)~".mp3"}}'
        media_content_type: music

mail_pickup:
  alias: Mail Picked Up
  sequence:
    - service: input_boolean.turn_off
      data:
        entity_id: input_boolean.mail_delivered

Both scripts toggle the status of the input_boolean defined above to indicate whether the mail has been delivered or picked up.  But the Mail Delivered script also plays an announcement using the media_player entity.  For me, 'all_home_devices' is defined as all my Google speakers.  I also have it play one of five random .mp3 files stored in my \www folder in Home Assistant.  This is optional and you can just as easily use the tts.google_say service and provide a standard message:

    - service: tts.google_say
      entity_id: 
        - media_player.my_google_speaker_name
      data:
        message: "The mail has been delivered"

Automations
Now we are finally ready to create the automation that pulls everything together and will notify us when the mail is delivered or when the battery needs to be replaced.

# =====================================
# Mail Delivered
# =====================================
- alias: mailbox_activated
  trigger: 
    platform: state
    entity_id: binary_sensor.mailbox_sensor_status
    from: 'off'
    to: 'on'
  mode: single                # Assures only one instance runs at a time (new default)
  action:
    - service: script.turn_on
      data_template:
        entity_id: >
          {% if is_state('input_boolean.mail_delivered', 'off') %}
            script.mail_delivery
          {% else %}
            script.mail_pickup
          {% endif %}
    - delay: '00:02:00'          # add 2 min delay until deep sleep kicks in.
    # update low battery sensor
    - service: homeassistant.update_entity
      entity_id: binary_sensor.mailbox_battery_low
      
# =============================
#  Low battery notification
# =============================
- alias: 'Mailbox Battery Low'
  id: 5bb73b56-7e02-4fa4-8854-de2fb0898635
  trigger: 
    platform: state
    entity_id: binary_sensor.mailbox_battery_low
    from: 'off'
    to: 'on'
    for: '00:15:00'
  action: 
    service: notify.mobile_app_galaxy_s10
    data:
      message: "Mailbox battery is low"

The first automation is triggered each time the ESP32 wakes up due to the mailbox door opening.  It calls either the mail_delivery script or the mail_pickup script based on the status of the input_boolean.

The low battery notification send a push notification to my phone whenever the low battery binary_sensor is true (less than 6V in my case).

You can use the sensors and other entities as desired to add cards to your Lovelace front end:


This has been one of my favorite Home Assistant automations and has been in use for about a year.  Let me know in the comments if you have thoughts or questions.  In addition, you can view a YouTube video of the build and installation on my YouTube channel Resinchem Tech.


Supporting this blog and related YouTube channel

If you'd like to support future content on this blog and the related YouTube channel, or just say thanks for something that helped you out, you can use any of my Amazon links to make a purchase at absolutely no cost to you.  Or if you prefer to say thanks directly, you can buy me a one-off cup of coffee at:


2 comments:

  1. Late to the party here, but great project!
    I appreciate the details you have provided and sharing the code.
    This is a great starting point for a similar project I wanted to make.

    Thanks!

    ReplyDelete
  2. Thanks. Glad you found it helpful. However, I should say that after struggling with battery life (and even after attempting to improve the battery.. I have a YouTube video on that attempt as well), I eventually swapped out the wifi system for a Zigbee door sensor inside the mailbox. The original system worked great.. but unfortunately it ended up requiring a battery swap about once a month... where the Zigbee sensor battery lasts 6-8 months. I just felt like I should let you know that this was the eventual result of this project. Good luck with your project!

    ReplyDelete

To help eliminate spam and to keep all conversations civil, submitted comments are moderated. Therefore your post may not show up immediately. Please be patient as most reviews are completed within a few hours.