Setting Up SwitchBot Webhook Trigger Automation with MQTT Sensors

Hi guys, in light of learning more about jinja2 templating and webhook automation in Home Assistant I’ve created an webhook automation using some SwitchBot sensors that I bought that is efficient in responding to Switchbot Webhook API for asynchronous event like door open, motion on.

Others solution that I found online and in HA forum usually parse the webhook payload on the mqtt sensor defined in configuration.yaml, whereas the service that I did will did all the parsing at the Automation script instead. It will then set the right state (as a string instead of JSON payload) to a dynamic topic depending on the type of the Switchbot sensor. The mqtt sensor defined in configuration.yaml will just have to specify a topic to subscribe for a state and just compare the string inside that topic. This method doesn’t require any restart since no changes is done in configuration.yaml.

Of course you could create a binary_sensor in configuration.yaml without having to use the webhook that periodially pool SwitchBot API for any status. In fact this is how I started, but then it’s not efficient since the event should be asynchronous, and that is exactly why Webhook is so important!

binary_sensor:
  # for switchbot motion sensor
  - platform: rest
    name: "Motion Sensor Staircase Downstair"
    device_class: motion
    resource: !secret switchbot_staircase_downstair_motion_sensor_status_url
    method: GET
    scan_interval: 1
    headers:
      Authorization: !secret switchbot_api
      Content-Type: "application/json"
    value_template: "{{ value_json.body.moveDetected }}"

Devices Used

  • Switchbot Hub Mini
  • SwitchBot Door Contact Sensor
  • SwitchBot Motion Sensor
  • Amazon Alexa

Prerequisite

  1. You need to install MQTT integration and created an Automation with Webhook as trigger. I setup my MQTT broker as another VM in my unRAID server rather than an Add-on to simplify my workflow.

  2. Register the Webhook URL that you received from Home Assistant Cloud (NabuCasa) and call Switchbot API. Note I’m still using Switchbot API v1 to simplify token auth :slight_smile:

curl example to register your HA webhook URL to Switchbot API server

curl -H "Content-Type: application/json" -H "Authorization: <YOUR_SWITCHBOT_TOKEN>" -X POST https://api.switch-bot.com/v1.0/webhook/setupWebhook -d '{"action":"setupWebhook", "url": "https://hooks.nabu.casa/<AUTO_GENERATED_URL_FROM_NABUCASE>", "deviceList": "ALL"}'

You should receive the following response code 100 if it works

{"statusCode":100,"body":{},"message":"success"}

How the Webhook works

  1. Your Switchbot sensor detected a state change and sent a message to Switchbot Hub.
  2. Your Switchbot hub sent an update to Switchbot API server
  3. Switchbot API server call registered web hook pointed to your HA (routed via NabuCasa server)
  4. The webhook JSON payload is then sent to HA Automation for that registered webhook
  5. Parse JSON payload and construct the right topic that is subscribed by each sensor defined in configuration.yaml, and update the value of that state. To keep it simple, the value is a string, rather than a JSON body that your mqtt sensor defined at configuration.yaml had to parse.
  6. SEnd the payload to the MQTT server that you setup in HA MQTT integration.
  7. mqtt sensor defined in configuration.yaml update its state value based on the payload (string) payload received from a subscribed topic from MQTT server

Implementation

What the Script Does

  1. Alexa announce the notification depending on the sensor type, e.g. door open for Contact Sensor, and motion on for Motion Sensor.
  2. The state is parsed from Switchbot Webhook JSON payload. The value depend on the sensor type, e.g. on/off for motion sensor and open/close for contact sensor.
  3. An additional availability is parse, not needed for these kind of sensor but just to demonstrate you could do it too
  4. The JSON received from Switchbot Webhook API is sent to another topic for debugging purpose.

MQTT Topic Design

The topic uses the following hierarchy:

/<HOME_NAME>/<SENSOR_LOCATION>/<MANUFACTURER>/<SENSOR_TYPE>/<DEVICE_ID>/{state,availability,json}

For Contact Sensor
Note: My motion sensor device ID is C8F7D45BB07B

State change (open/close): /home/staircase/switchbot/contact/C8F7D45BB07B/state
Availability (online/offline): /home/staircase/switchbot/contact/C8F7D45BB07B/availability
Full JSON from Switchbot Webhook API: /home/staircase/switchbot/contact/C8F7D45BB07B/json

For Motion Sensor
Note: My motion sensor device ID is D7F9AC484301

State change (open/close): /home/staircase/switchbot/motion/D7F9AC484301/state
Availability (online/offline): /home/staircase/switchbot/motion/D7F9AC484301/availability
Full JSON from Switchbot Webhook API: /home/staircase/switchbot/motion/D7F9AC484301/json

Paste the following YAML to the Automation Webhook trigger. You may change the topic accordingly.

alias: Webhook - Receive switchbot webhook
description: ""
trigger:
  - platform: webhook
    webhook_id: motion-detected-staircase-downstair
condition: []
action:
  - service: notify.alexa_media
    data_template:
      message: >-
        {% if trigger.json.context.deviceType == 'WoContact' %}
          {% if trigger.json.context.openState == 'open' %}
            Door opened
          {% else %}
            Door closed
          {% endif %}
        {% elif trigger.json.context.deviceType == 'WoPresence' %}
          {% if trigger.json.context.detectionState == 'DETECTED' %}
            Motion sensor on
          {% else %}
            Motion sensor off
          {% endif %}
        {% endif %}
      target: media_player.gary_s_echo_dot
      data:
        type: tts

  # update entity state
  - service: mqtt.publish
    data_template:
      # topic: /home/staircase/switchbot/motion/D7F9AC484301
      # payload_template: "{{ trigger.json | tojson }}"

      topic: >-
        {% if trigger.json.context.deviceType == 'WoContact' %}
          /home/staircase/switchbot/contact/{{ trigger.json.context.deviceMac }}/state
        {% elif trigger.json.context.deviceType == 'WoPresence' %}
          /home/staircase/switchbot/motion/{{ trigger.json.context.deviceMac }}/state
        {% endif %}
      payload: >-
        {% if trigger.json.context.deviceType == 'WoContact' %}
          {% if trigger.json.context.openState == 'open' %}
            open
          {% else %}
            close
          {% endif %}
        {% elif trigger.json.context.deviceType == 'WoPresence' %}
          {% if trigger.json.context.detectionState == 'DETECTED' %}
            on
          {% else %}
            off
          {% endif %}
        {% endif %}

  # update entity availability
  - service: mqtt.publish
    data_template:
      # topic: /home/staircase/switchbot/motion/D7F9AC484301/status
      topic: >-
        {% if trigger.json.context.deviceType == 'WoContact' %}
          /home/staircase/switchbot/contact/{{ trigger.json.context.deviceMac }}/availability
        {% elif trigger.json.context.deviceType == 'WoPresence' %}
          /home/staircase/switchbot/motion/{{ trigger.json.context.deviceMac }}/availability
        {% endif %}
      payload: online

  # display raw json response from Switchbot API server
  - service: mqtt.publish
    data_template:
      # topic: /home/staircase/switchbot/motion/D7F9AC484301/json
      topic: >-
        {% if trigger.json.context.deviceType == 'WoContact' %}
          /home/staircase/switchbot/contact/{{ trigger.json.context.deviceMac }}/json
        {% elif trigger.json.context.deviceType == 'WoPresence' %}
          /home/staircase/switchbot/motion/{{ trigger.json.context.deviceMac }}/json
        {% endif %}
      payload: "{{ trigger.json }}"
mode: single

Paste the following to configuration.yaml. Be sure to change the device ID to the one in your Switchbot Hub. You can run the following curl command to get a list of device ID currently connected to your SwitchBot Hub Mini.

curl -H "Authorization:<SWITCHBOT_TOKEN>" https://api-switch-bot.com/v1.0/devices/

configuration.yaml

# uses the MQTT message payload as the sensor value.
mqtt:
  binary_sensor:
    - name: "Switchbot Motion Sensor Staircase Downstair"
      unique_id: switchbot_D7F9AC484301
      icon: mdi:motion-sensor
      device_class: motion
      state_topic: "/home/staircase/switchbot/motion/D7F9AC484301/state"
      payload_on: "on"
      payload_off: "off"

    - name: "Switchbot Door Contact Sensor Living Room"
      unique_id: switchbot_C8F7D45BB07B
      icon: mdi:leak
      device_class: door
      state_topic: "/home/staircase/switchbot/contact/C8F7D45BB07B/state"
      payload_on: "open"
      payload_off: "close"
      # availability:
        # - topic: "/home/staircase/switchbot/contact/C8F7D45BB07B/availability"
          # payload_available: "online"
          # payload_not_available: "offline"

Check your configuration from Developer page, restart and profit!

References

1 Like

Hi. You have typo here. Should be api.switch-bot.com

curl -H "Authorization:<SWITCHBOT_TOKEN>" https://api-switch-bot.com/v1.0/devices/

this is brilliant, i’ve been looking for a while and i’m not sure if i’ve seen any other resource as detailed/accessible as this post on implementing switchbot with webhooks

a few questions for my understanding as a noob:

  1. as there’s an update sent to the API server, does this count towards the API quota? if so, do i understand correctly that if there’s no state change then there’s no update sent to the API server?
  2. does Step 3 under ‘How the Webhook works’ above require a paid subscription with HA?
  3. is the MQTT setup have any connection to how the HA server is run or how the Switchbot devices are recognised by HA? (i ask because i understand that if you don’t have a physical HA server with a bluetooth connection to the devices, the alternative integration of Switchbot is with HA on a virtual machine via API calls sent to the Switchbot Hub. This is my current setup).