Home Assistant Webhook Primer

Home Assistant Webhook Primer

I recently did a video talking through using web hooks in home Assistant to create some automations to monitor another home assistant instance. And while its not a universal use case, it did allow me to create a video showing how to create a web hook, and leverage automation triggers like the home assistant start event and time patterns, and even seem timestamp math which is extremely useful when building a smart home.

In any case, if you haven’t watched that video, you should probably watch it first. If you have seen it and you are looking for the YAML you are in the right place. 

First up, we need to create a web hook, and we do that by simply creating an automation. For example, if we want to create an automation that simply notifies us every time a web hook is touched, this is how we could do that: 

- id: just_a_test_webhook
  alias: Testing Webhooks
  description: ''
  trigger:
  - platform: webhook
    webhook_id: send_a_message
  action:
  - service: notify.mobile_app_jeffrey_ha_app
    data:
      message: Webhook Got Touched!
  mode: single

Once the “just a test web hook” automation is saved, Home Assistant will create a web hook with the name matching the value of webhook_id. Or in this case send_a_message

We can then access that web hook using the url: http://our_domain/api/webhook/send_a_message and if the http method we use is post then the home assistant automation will fire and notify my mobile app. 

Now you can use that URL in any service outside of home assistant capable of sending a “post” request. This could be a python script, or IFTTT, or even a IOS shortcut on your iPhone. The only trick is it needs to be a post request. Putting the URL in your web browser and hitting enter sends “get” request which will return a 405 error. 

If you are a Nabu Casa user, I suggest using Nabu Casa to host our web hook. You can enable that by visiting the Home Assistant cloud option under configuration. Scroll down to your list of Webhooks until you find the one you created. Then turn on the little toggle:

You will get a popup that contains the Nabu Casa url of your webhook and it will be randomized so it can’t be guessed. Making it perfect for sharing with third party services. 

Monitoring Home Assistant

My most recent use case for a web hook was setting up a monitoring system for my Brother’s instance of Home Assistant. He wanted to know when his instance was down, and that included when his internet was out. So we came up with a method in which his system would send a heartbeat to my home assistant instance on a set interval. And my system would check and send a notification if the heartbeat stopped. 

To set that I I created two helpers and an automation on my system. 

The first was an input_datetime helper that I created in the helpers menu under configuration in the Home Assistant UI. 

The next helper was a drop down. This one was to store the current status of the system so I could display it in my dashboard. 

This helper should have two options. One to denote the system is good, and one to denote the system is bad. 

Then after that I just needed an automation to handle the heartbeat when the web hook it hit from the remote system. This automation uses some templates so whether you start in the UI Automation editors or not you will ned up having to write some YAML. So here it is if you would rather copy:

- id: '1629578209876'
  alias: Remote System Heartbeat
  description: ''
  trigger:
  - platform: webhook
    webhook_id: remote_system_heartbeat
    id: heartbeat
  - platform: time_pattern
    id: update
    minutes: /30
  condition: []
  action:
  - choose:
    - conditions:
      - condition: trigger
        id: heartbeat
      sequence:
      - service: input_datetime.set_datetime
        target:
          entity_id: input_datetime.remote_system_heartbeat
        data:
          datetime: '{{ now().strftime(''%Y-%m-%d %H:%M:%S'') }}'
      - service: input_select.select_option
        target:
          entity_id: input_select.remote_system_status
        data:
          option: alive
    - conditions:
      - condition: trigger
        id: update
      - condition: template
        value_template: '{{ (as_timestamp(now()) - as_timestamp(states(''input_datetime.remote_system_heartbeat'')))
          < 3600 }}'
      sequence:
      - service: input_select.select_option
        target:
          entity_id: input_select.remote_system_status
        data:
          option: alive
    default:
    - service: input_select.select_option
      target:
        entity_id: input_select.remote_system_status
      data:
        option: unknown
    - service: notify.mobile_app_jeffrey_ha_app
      data:
        message: Remote System is Down!!

This automation uses two triggers and the choose action to combine three automations into one. 

First if the automation is kicked off by our web hook, we need to save the current time to our date time helper, and make sure that the alive option is selected in our status dropdown. 

Next we trigger the automation every 30 minutes. The /30 in the minute field of the trigger tells this automation to run every 30 minutes and not at the 30 minute each hour. 

But if this automation kicks off with the time pattern the remote system could be either up or not. So we need to first check to see if we have heard from the system in the last 30 minutes. We do that using a bit of jinja in the list of conditions for our second option. 

We just have to subtract the last value stored in our helper from the current time, and then check to see if the difference is less that 3600 seconds. 

If it is then we can mark our system as alive. 

But since the system could be down we will use the default action for that. The idea being if this automation fires, and it wasn’t the heartbeat, and the last reported heartbeat was more than an hour ago then the remote system was be down. 

So in that case we set the value of our status dropdown to unknown and send out a notification. 

The problem with this is the automation will fire every 30 minutes and the system is down we will get a notification. So a better option might be to separate the notification to its own automation. 

That way we can send the message once. 

So that we could use an automation like: 

- id: '1629581648846'
  alias: Remote System Alert
  description: ''
  trigger:
  - platform: state
    entity_id: input_select.remote_system_status
    from: alive
    to: unknown
    id: alert
  - platform: state
    entity_id: input_select.remote_system_status
    id: alive
    from: unknown
    to: alive
  condition: []
  action:
  - choose:
    - conditions:
      - condition: trigger
        id: alert
      sequence:
      - service: notify.mobile_app_jeffrey_ha_app
        data:
          message: Remote System is Down!!
    - conditions:
      - condition: trigger
        id: alive
      sequence:
      - service: notify.mobile_app_jeffrey_ha_app
        data:
          message: Remote System is Alive again
    default: []
  mode: single

This way we can send a notification only when the status changes from alive to unknown or unknown to alive. 

After that we need to setup our remote system to send the heartbeat, and unfortunately we will need to edit our configuration.yaml file. 

Simply open your configuration.yaml in the editor of your choice and add the following section. 

rest_command:
  remote_system_webhook:
    url: http://192.168.7.187:8123/api/webhook/remote_system_heartbeat
    method: POST

remote_system_webhook would be the name of this rest command. 

url would be the URL of the web hook. If you are saving your config to GitHub, be sure to hid it in your secrets.yaml file. 

And method will beed to be post. 

After that, be sure to save your changes and restart home assistant. Once it is back up you can add the automation to trigger the rest command. 

That automation could look like this:

- id: '1629837216637'
  alias: Send Heartbeat
  description: ''
  trigger:
  - platform: time_pattern
    minutes: /30
  - platform: homeassistant
    event: start
  condition: []
  action:
  - service: rest_command.remote_system_webhook
  mode: single

In this example I have two triggers. The time pattern of every 30 minutes followed by one that will execute this when home assistant starts up. That will mean that if the system goes down you won’t have to wait for 30 mins to get your first update. As soon as the instance starts back up it will send a message that bits alive.

Now web hooks have lots of uses beyond this specific one. For example, you could use it to integrate any IFTTT service with home assistant. Or you could interact with another platform all together as long as it can receive web hooks. 

In any case web hooks open a world of possible integrations for home assistant, and I hope to do more on how you could leverage these to make your smart home smarter. But thats it for now. 

Until next time, Automate the Boring Stuff.

Mastodon