Hey all, pretty new to Home Assistant but getting the hang of it and wanted to share a cool thing I built.
Little background for me, I am a very long-time and very heavy user of Tasker and a long-time and very heavy user of IFTTT. I made the conversion to HA for a variety of reasons I won’t go into here but the point is thus far I’ve spent most of my time moving my existing automations from being patchwork processes with logic and state spread across Tasker, Apilio and IFTTT into HA automations.
One of my favorite (and most important) automations was my Home emergency SOS set up. It’s effectively a dead man’s switch (shout out to this helpful topic). The basic process is this:
- When one of my nest protects starts shouting emergency (CO or Smoke) send out an alert to my wife and I asking us to confirm we are ok
- Alert should mention it will ask our designated emergency contact to check in on us if we don’t respond within a few minutes. Alert must provide a clear way to interact with said alert and cancel this
- If we don’t respond within 2 minutes then reiterate the alert, expressing urgency
- If we still don’t respond within 2 minutes then alert our emergency contact and ask them to check in. Alert us that this happened
- When the emergency is resolved send us a notification. And if the emergency contact was texted, remind us that so we know to call them or something.
And since I’m now doing this on HA I thought it was important to add two new requirements to the mix:
6. Zero reliance on my phone (in other words, tasker is not involved in this process at all so it can work even if I’m out of service or my phone is dead)
7. Restart resilient (i.e. if a restart somehow happens during this it should pick up right where it left off). Since the core process takes only 4 minutes this isn’t super crucial but I wanted to consider it.
I wanted to write this up because I think its a great pattern that could be applied to any number of things. I choose to use my smoke detectors as my emergency signal but you can make that anything you want, so long as you can write a binary sensor out of the situation.
For my notification platforms I choose:
- Push notifications (HTML5 for me, IOS for my wife)
- Twilio SMS (to text the emergency contact)
Again, you can choose whatever. Other platforms like Pushbullet, Telegram or FB Messenger work fine and are free as long as your emergency contact actively checks those. I didn’t want to ask them to sign up for a service they use just for this since it’s a rare event and they’ll forget about it so I choose SMS. Twilio isn’t free but its cheap enough given the rarity of this event and it lets me use my own number.
Now for the nitty gritty. The “it’s an emergency!” flag is my emergency_at_home
sensor. It’s a template sensor not a binary sensor in my case but for purposes of this discussion its effectively binary (it either says emergency
or it doesn’t). The reason its not a true binary sensor is because I also wanted to know when one them said warning
for other potential automations. Here’s that sensor:
# Aggregates emergency status from across all nest protects (CO and Smoke)
home_emergency:
friendly_name: "Home emergency"
value_template: >
{% set sensors = [
states.sensor.office_nest_protect_co_status,
states.sensor.kids_room_nest_protect_co_status,
states.sensor.family_room_nest_protect_co_status,
states.sensor.dining_room_nest_protect_co_status,
states.sensor.bedroom_nest_protect_co_status,
states.sensor.office_nest_protect_smoke_status,
states.sensor.kids_room_nest_protect_smoke_status,
states.sensor.family_room_nest_protect_smoke_status,
states.sensor.dining_room_nest_protect_smoke_status,
states.sensor.bedroom_nest_protect_smoke_status ] %}
{% if sensors | selectattr('state', 'eq', 'Emergency') | list | count > 0 %}
emergency
{% elif sensors | selectattr('state', 'eq', 'Warning') | list | count > 0 %}
warning
{% else %}
none
{% endif %}
icon_template: >-
{% if is_state('sensor.home_emergency', 'emergency') %}
mdi:alert-decagram
{% elif is_state('sensor.home_emergency', 'warning') %}
mdi:alert
{% else %}
mdi:shield-check
{% endif %}
Like I said, this part can be anything you want, you just need a sensor that determines when it is emergency. If you are interested in specifically aggregating status from protects though, this does that. (Thanks to @123 for the improved version!)
Next up was the backbone of the process - my home_emergency
alert. The alert integration was really perfect for this - it fires alerts based on states, it allows fine-grained control over the repeat schedule (first two are 2 min apart, after that longer), it has a built-in acknowledgement functionality, and it survives a restart. Although in reality there were quite a few ‘gotchas’ but I’ll get there. For now, here’s the alert:
home_emergency:
name: Emergency at home
entity_id: sensor.home_emergency
title: "Smoke/CO emergency at home"
message: >
{% if is_state('counter.emergency_checkin_attempts', '0') %}
Will ask emergency contact to check in with you in 4 minutes. Cancel the alert if everything is fine
{% elif is_state('counter.emergency_checkin_attempts','1') %}
Will ask emergency contact to check in with you in 2 minutes. Cancel the alert if everything is fine
{% else %}
Emergency contact messaged and asked to check in
{% endif %}
done_message: "Smoke/CO emergency ended{% if (states('counter.emergency_checkin_attempts')|int) > 1 %}. You should checkin with emergency contact{% endif %}"
state: 'emergency'
can_acknowledge: true
repeat:
- 2
- 2
- 15
notifiers:
- 'all'
- 'track_home_emergency_alerts'
data:
tag: home_emergency
badge: <an alert image>
icon: <an alert image>
priority: high
requireInteraction: true
acknowledge_alert: 'yes'
subtitle: Long press and click cancel to dismiss alert
push:
thread-id: home_emergency
category: acknowledgeable_alert
action_data:
alert_id: home_emergency
So you can see that ticks off a number of my requirements right there. We have an alert schedule and the messaging gets more urgent as it repeats. It also lets us know if the emergency contact was texted when done.
Now I mentioned gotchas so lets go through them. The first (and definitely biggest) one is that alerts don’t actually have a way to tell you how many times they have repeated without being acknowledged. Would really love to see this feature added. In the meantime, I handled that with a special second notifier, track_home_emergency_alerts
. That notifier looks like this:
name: track_home_emergency_alerts
platform: rest
method: POST_JSON
verify_ssl: false
resource: https://127.0.0.1:<HA Port>/api/webhook/track_home_emergency_alerts
Tricky, right? This way every time the alert goes out it calls back into HA with a specific webhooks event track_home_emergency_alerts
. I can then write an automation for that event to increment a counter and keep track of how many times the alert has repeated:
id: '1567202462897'
alias: Emergency at home - Track alert attempts
trigger:
- platform: webhook
webhook_id: track_home_emergency_alerts
- entity_id: alert.home_emergency
platform: state
to: idle
condition: []
action:
- data:
entity_id: counter.emergency_checkin_attempts
service_template: '{% if is_state(''alert.test_alert'', ''on'') %}counter.increment{% else %}counter.reset{% endif %}'
Since I have a done_message specified it will also hit this automation when the emergency is done so this is also my counter.reset
automation (hence the service_template
)
Once I had this, the emergency text was pretty easy. Just a simple state trigger based on the counter:
id: '1567146785757'
alias: Emergency at home - text contacts
trigger:
- above: '2'
entity_id: counter.emergency_checkin_attempts
platform: numeric_state
condition:
- condition: state
entity_id: sensor.home_emergency
state: emergency
action:
- data_template:
target: !secret emergency_contacts
data:
message: < whatever message you want to send to your emergency contact(s) >
service: notify.emergency_contacts
I also learned as part of this that you can have an array in secrets which is pretty cool so I could text multiple people here if I wanted to. The condition is kind of a ‘just in case’ if timing of emergency end is super close since I really only want to send out the text if I have to.
So that covers everything except one key thing - how does the alert get acknowledged? I said it was important that the alert be acknowledgeable from the alert itself. I don’t want people opening up HA and finding a toggle in the middle of an emergency. Clicking the notification needs to acknowledge the alert.
Turns out this is a huge pain but I did get it done. And even better I figured out a generic way to do it that works for all my alerts so I can always click the alert to acknowledge it if I want the alert acknowledgeable (side note: HA please add this feature to alerts ). If you notice in my alerts there’s a lot of data. Here it is again for reference with the unimportant parts omitted:
data:
tag: home_emergency
acknowledge_alert: 'yes'
The key is that with HTML5 notifications when someone clicks the notification you get an event back with this data. So if I want an alert to be acknowledgeable by clicking on it I add a special acknowlege_alert
field that I can filter on and I set the tag to the name of the alert so I know which one is being acknowledged.
IOS is unfortunately a bit trickier since you don’t get an event just for clicking on the notification. So I had to settle on a generic action that can be used to acknowledge any alert:
data:
subtitle: Long press and click cancel to dismiss alert
push:
thread-id: home_emergency
category: acknowledgeable_alert
action_data:
alert_id: home_emergency
The category is reusable for any acknowledgeable alert. The key in this case is to put the name of the alert in the alert_id
field of action_data since that is the dictionary you get back when an IOS notification action is clicked. This way when the action is clicked I know which alert is being acknowledged. The subtitle is just there to remind people since IOS actions are kind of hidden.
And this leads to the final automation, the one that handles actually acknowledging alerts when these notification actions are used:
id: '1567142124005'
alias: Alert - acknowledge alert
trigger:
- event_data:
acknowledge_alert: 'yes'
event_type: html5_notification.clicked
platform: event
- event_data:
actionName: ACKNOWLEDGE_ALERT
event_type: ios.notification_action_fired
platform: event
condition:
- condition: template
value_template: "{% if trigger.event.event_type == 'html5_notification.clicked' %}{{ is_state('alert.' ~ trigger.event.data.tag, 'on') }}{% else %}{{ is_state('alert.' ~ trigger.event.data.action_data.alert_id, 'on') }}{% endif %}"
action:
- data_template:
entity_id: alert.{% if trigger.event.event_type == 'html5_notification.clicked'%}{{ trigger.event.data.tag }}{% else %}{{ trigger.event.data.action_data.alert_id }}{% endif %}
service: alert.turn_off
Basically, when a notification action comes in that says its supposed to be acknowledging an alert then I check and make sure that alert is in fact on and if so turn it off. I use it in many of my alerts (and seriously, would love this just be an HA feature).
Anyway that’s it! If you got this far thanks for reading! Hopefully you find it useful