Home emergency SOS system

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:

  1. 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
  2. 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
  3. If we don’t respond within 2 minutes then reiterate the alert, expressing urgency
  4. 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
  5. 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:

  1. Push notifications (HTML5 for me, IOS for my wife)
  2. 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 :wink: ). 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 :smile:

11 Likes

This is a great project and I think I and others will find it useful. Now I’ve got some more things to look into.

Home automation for stuff like lights is generally convenient but I think automating emergency related stuff is the most important aspect of any automation system. I wrote up a NWS severe weather alert project a while back for the same reason. I finally got around to adding smart smoke detectors (first alert brand) and I think I needed something like this. Right now it’s just a simple pushbullet notification.

And a great write-up too. It looks like you get as “wordy” as I do on this kind of thing. :laughing: (see my previously mentioned NWS alerts or even better my time conversion thread for examples). But in cases like this it’s better to possibly over-explain things than to not explain things enough.

Thanks for the contribution!

1 Like

Hi Mike, Thanks for the shout out, I’m glad you found my old concept usefull. I like the idea of implementing a dead man’s switch as part of a security/emergency system, very cool. :bearded_person::+1:

Thanks for posting this write-up. The webhook trick was great.
I now have this implemented in my system.

For your consideration, this version’s template uses a different technique.

# 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 %}

NOTE:
When the sensors are clearly listed in the template, Home Assistant can identify them so it’s not necessary to explicitly list them in entity_id.

Also, In your example’s icon_template, it contains this:

    {% if is_state('home_emergency', 'emergency') %}

I believe it should appear like this:

    {% if is_state('sensor.home_emergency', 'emergency') %}

EDIT
Correction: Changed emergency to Emergency and warning to Warning in selectattr()

Thanks @123, I like that. I knew that you didn’t necessarily have to list the entity_ids but I found the docs confusing on that front. The docs say this:

The template engine will attempt to work out what entities should trigger an update of the sensor. This can fail, for example, if your template loops over the contents of a group. In this case, you can use entity_id to provide a list of entity IDs that will cause the sensor to update

Since its not particularly specific on what its looking for in its automatic analysis I decided to just always play it safe and always list out my entity_ids. Thanks for clarifying that though, that makes sense that its just literally looking for known entity_ids in the text.

Also you’re right about the icon_template, that’s a bug, I’ll update that.

@123 So I was just doing some testing with your template and I actually couldn’t get it to work without listing the entity_ids. I used the developer tools panel to manually change some of the nest protects status to warning or emergency and the home_emergency sensor wouldn’t update. As soon as I listed the entity_ids though it worked again.

Do you think maybe there’s a limit to the number of entity_ids it will identify automatically during analysis? I can’t think of why else it would be doing this. I even tried switching the template to this to use the syntax suggested in the templating guide of states('<id>') and still it wouldn’t update:

home_emergency:
  friendly_name: "Home emergency"
  value_template: >-
    {% set sensors = [
        states('sensor.basement_nest_protect_co_status') | lower,
        states('sensor.guest_room_nest_protect_co_status') | lower,
        states('sensor.kids_room_nest_protect_co_status') | lower,
        states('sensor.family_room_nest_protect_co_status') | lower,
        states('sensor.dining_room_nest_protect_co_status') | lower,
        states('sensor.bedroom_nest_protect_co_status') | lower,
        states('sensor.hallway_nest_protect_co_status') | lower,
        states('sensor.basement_nest_protect_smoke_status') | lower,
        states('sensor.guest_room_nest_protect_smoke_status') | lower,
        states('sensor.kids_room_nest_protect_smoke_status') | lower,
        states('sensor.family_room_nest_protect_smoke_status') | lower,
        states('sensor.dining_room_nest_protect_smoke_status') | lower,
        states('sensor.bedroom_nest_protect_smoke_status') | lower,
        states('sensor.hallway_nest_protect_smoke_status') | lower
       ] %}
    {% if sensors | select('eq', 'emergency') | list | count > 0 %}
      emergency
    {% elif sensors | select('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 %}

Anyway I’m not really sure but its making me feel uncomfortable about relying on the automatic analysis again so I think I’m just going to go back to listing out all my IDs. I’m not a huge fan of magic, I prefer to know exactly what’s going on even if it requires a bit more effort on my part.

I definitely like the piping with the select and selectattr though that looks a lot nicer. I’m getting decent at jinja at this point but I still have a lot of learning to do.

I currently have three Template Sensors that use the same technique, for reporting the number of active lights, appliances, and open doors, and all three work perfectly (without listing them in entity_id).

It’s not “magic” but a regex pattern that Home Assistant uses when it evaluates Template Sensors (and Template Binary Sensors and Template Switches) at startup. It extracts anything that matches the appearance of an entity_id then creates a listener to monitor that entity’s state-changes. If the pattern fails to match anything (and nothing is explicitly listed in the entity_id: option) then Home Assistant simply evaluates the template once and never again (until the next restart).

I believe what I failed to take into account was that your smoke sensors report their status with a leading capitalized letter, like Emergency as opposed to emergency. That means I’ve supplied the selectattr() function with the wrong value.

I’ve revised my previous post and changed the function’s value so that it matches for Emergency and Warning. Let me know if it makes a difference,

Yea I caught that when I was trying it out. That’s why in my post above I changed it to explicitly lowercase the value of each state so I could check in a case insensitive way.

Of course now today I just tried to delete the entity_ids without changing the template I was using at all and suddenly this time its working fine. So now I guess idk what was going on yesterday.

Ok I don’t know what was happening to me last night but its clearly working fine now. I’ll update the main post with the new template. Thanks for your help!

1 Like