If one thing winds our dog up it’s people ringing the doorbell and then walking away. He doesn’t mind if they wait and come in, but when they walk off, cue bark central. So to combat this I decided to combine all of my hobby skills (home automation, CNC machining and electronics) into a single project for the first time and make a quiet way for delivery drivers to alert us that they have left a package in the porch. I present - Package Monitor:
Features:
- Laser-cut and engraved multi-layer housing
- ESP32 & ESPHome powered
- Single button user interface (press for delivery, hold to reset)
- Visual and audio confirmation cues for set and reset
- Ring camera snapshot taken on activation
- Mobile app notification with snapshot
- Mobile app reset action
Housing
The body is made of 4 layers of 5mm plyboard (basswood or similar) which can easily be cut with the 10W laser on my Snapmaker Artisan. Each layer is cut to allow space for the components and wiring, then the top layer is engraved with the instructions. Then the electronics are installed and the whole thing glued together. If anyone would like the SVG stencils for the cuts/engraving, message me.
Electronics
Parts:
- ESP 32 Mini
- Momentary Push Button
- Green LED
- Active Piezo Buzzer
- 270 Ohm Resistor
Nothing too fancy here. The button sits between a GPIO and Ground, the buzzer between a GPIO and Ground and the LED in series with the resistor between another GPIO and ground. I powered it with a USB cable as I had one with a long tail hanging around, if I did it again I’d probably use some bell-wire straight to the terminals as it’s a lot thinner and less obtrusive. Using the USB does give me a failsafe if the WiFi ever changes however, as getting the ESP32 out of the housing is impossible once glued!
Software
ESPHome Config:
esphome:
name: package-monitor
friendly_name: package-monitor
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "<<REDACTED>>"
ota:
password: "<<REDACTED>>"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
domain: .lan
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Package-Monitor Fallback Hotspot"
password: "<<REDACTED>>"
time:
- platform: homeassistant
id: my_time
output:
- platform: gpio
pin: GPIO32
id: led
- platform: gpio
pin: GPIO25
id: buzzer
globals:
- id: cool_down_timestamp
type: int
restore_value: no
initial_value: '0'
script:
- id: buzzer_set
then:
- output.turn_on: buzzer
- delay: 100ms
- output.turn_off: buzzer
- delay: 50ms
- output.turn_on: buzzer
- delay: 100ms
- output.turn_off: buzzer
- delay: 50ms
- id: buzzer_reset
then:
- output.turn_on: buzzer
- delay: 300ms
- output.turn_off: buzzer
light:
- platform: binary
id: package_waiting
name: "Package Waiting"
output: led
icon: mdi:package-variant-closed
number:
platform: template
icon: mdi:package-variant-closed
id: package_count
name: "Package Waiting Count"
step: 1
min_value: 0
max_value: 1000
optimistic: true
binary_sensor:
- platform: gpio
pin:
number: GPIO33
mode:
input: true
pullup: true
inverted: true
id: button
filters:
- delayed_on: 50ms
on_press:
then:
- if:
condition:
lambda: |-
return (id(cool_down_timestamp) < (millis() - 5000));
then:
- lambda: |-
id(cool_down_timestamp) = millis();
- output.turn_on: led
- script.execute: buzzer_set
- delay: 2s
- if:
condition:
binary_sensor.is_on: button
then:
- light.turn_off: package_waiting
- script.execute: buzzer_reset
- logger.log: "Indicator Reset"
- number.to_min: package_count
else:
- light.turn_on: package_waiting
- logger.log: "Package Waiting"
- number.increment: package_count
Notification Automation:
alias: PMON
description: ""
trigger:
- platform: state
entity_id:
- number.package_monitor_package_waiting_count
condition:
- condition: numeric_state
entity_id: number.package_monitor_package_waiting_count
above: 0
action:
- service: button.press
data: {}
target:
entity_id: button.take_snapshot
- delay:
hours: 0
minutes: 0
seconds: 2
milliseconds: 0
- service: camera.snapshot
data:
filename: /config/www/tmp/snapshot_package.jpg
target:
device_id: 16f2f3732f512cd6c293fec3bf8ca5f1
- service: notify.mobile_app_iphone
data:
title: A package has been delivered
data:
attachment:
url: /local/tmp/snapshot_package.jpg
content_type: JPEG
actions:
- action: pmon_reset
title: Reset
message: >-
There are {{ states('number.package_monitor_package_waiting_count') |
int }} packages waiting in the porch.
mode: single
Reset Automation:
alias: PMON Reset Notification
description: ""
trigger:
- platform: event
event_type: mobile_app_notification_action
event_data:
action: pmon_reset
condition: []
action:
- service: light.turn_off
data: {}
target:
entity_id: light.package_monitor_package_waiting
- service: number.set_value
data:
value: "0"
target:
entity_id: number.package_monitor_package_waiting_count
mode: single
If you want to re-create this and need info on any of the parts/design - happy to help!
Thanks for reading.