Generic Emailer for all doors

I’ve added open / closed sensors to all my external doors. The first iteration of this burglar alarm is to simply email me when any of the doors changes state.

I have it set up and working, but the config is very repetitive. I wonder if there’s a generic way of doing it.

Here’s an example from my automations.yaml file which covers two of the four doors:

- alias: Side Door Opened
  trigger:
    - platform: state
      entity_id: binary_sensor.doorside
      to: 'on'
  action:
    - service: notify.smtp_ken
      data:
        title: "Door (Side) Opened"
        message: "Side door opened."

- alias: Side Door Closed
  trigger:
    - platform: state
      entity_id: binary_sensor.doorside
      to: 'off'
  action:
    - service: notify.smtp_ken
      data:
        title: "Door (Side) Closed"
        message: "Side door closed."

- alias: Patio Door Opened
  trigger:
    - platform: state
      entity_id: binary_sensor.doorpatio
      to: 'on'
  action:
    - service: notify.smtp_ken
      data:
        title: "Door (Patio) Opened"
        message: "Patio door opened."

- alias: Patio Door Closed
  trigger:
    - platform: state
      entity_id: binary_sensor.doorpatio
      to: 'off'
  action:
    - service: notify.smtp_ken
      data:
        title: "Door (Patio) Closed"
        message: "Patio door closed."

You can see that it’s the same template repeatedly. Can this be done in a more compact, less repetitive way? If the answer is “no” I’m OKay with that, because I’m poised to do it in Python anyway!

In the first instance, I don’t mind if the email doesn’t announce the door, so long as it tells me if it’s opened or closed.

Thanks!

Try this:

- alias: 'Door Opened/Closed'
  trigger:
    - platform: state
      entity_id: binary_sensor.doorside, binary_sensor.doorpatio
  action:
    - service: notify.smtp_ken
      data_template:
        title: "Door ({{ trigger.to_state.name }}) {{ 'Opened' if trigger.to_state.state == 'on' else 'Closed' }}."
        message: "{{ trigger.to_state.name }} door {{ 'opened' if trigger.to_state.state == 'on' else 'closed' }}."
  • trigger.to_state.name returns the Friendly Name of whichever binary_sensor triggered the automation.
  • trigger.to_state.state returns the current state (on or off) of whichever binary_sensor triggered the automation.

EDIT

If you have many doors to monitor, you may wish to list their binary_sensors in YAML format to avoid having an overly-long line.

    - platform: state
      entity_id:
        - binary_sensor.doorside
        - binary_sensor.doorpatio
        - binary_sensor.doorporch
        - binary_sensor.doorgarage
        - binary_sensor.doorattic
        - binary_sensor.doorshed
2 Likes

Love it. I think the thing that irritates me most is that it’s completely obvious after someone explains it!!
Thank you.

Help me a little more, please, with the “many doors to monitor”. I don’t quite get the idea of the state platform.

These are 433MHz transmitters to a device called “bridge”. At the moment, my binarysensors.yaml has many instances of:

- platform: mqtt
  state_topic: "bridge/tele/RESULT"
  name: "doorfront"    <--- or other door name as per previous post
  value_template: "{{value_json.RfReceived.Data}}"
  payload_on: "<unique hex code for closed>"
  payload_off: "<unique hex code for opened>"
  qos: 1

I don’t see where - platform: state fits in.

Thanks again.

There are twelve types of trigger and they are described here:

The one used in the automation is the State Trigger.

The following means to monitor the state of binary_sensor.doorside and trigger when the state changes.

  trigger:
    - platform: state
      entity_id: binary_sensor.doorside

A binary_sensor can have one of two states: on or off. The automation will trigger if the state of binary_sensor.doorside changes from on to off or from off to on.

If I wanted it to trigger only if binary_sensor.doorside changes from on to off then I would write it like this:

  trigger:
    - platform: state
      entity_id: binary_sensor.doorside
      from: 'on'
      to: 'off'

also look at Automation that checks for is doors are open before going to bed - this will iterate through all doors in a group…

1 Like

Was my explanation helpful?

I had a similar issue. Many of my doors have RF sensors on them, but their codes all follow a pattern, so I used that to my advantage: If they end in ‘E’, they’re closed, and if they end in ‘A’, they’re open. Ending in a ‘6’ means low battery, and ending in ‘7’ means that there’s been an intrusion into the case of the sensor.

The ‘doors’ dictionary relates the starting characters of the code to the friendly name of the door and the MQTT topic of the corresponding binary sensor. I made my own MQTT topics for the doors so I could avoid using the ‘result’ topic from my Sonoff RFBridge, and have it retained so that the door states persist across a restart of home assistant.

script:  
  rf_door_state:
    alias: rf_door_state
    sequence:
      - service_template: >-
          {%- set op = code[-1:] -%}
          {%- if ((op == 'A') or (op == 'E')) -%}
            script.rf_door_openclose
          {%- elif ((op == '6') or (op == '7')) -%}
            script.rf_door_problem
          {%- else -%}
          {%- endif -%}
        data_template:
          data: >
            {%- set doors = {
              "xxxxx": "[Friendly name],[MQTT_Topic]",
              "2D2A0": "Back door,BackDoor",
              "2D340": "Ensuite door,EnsuiteDoor",
              "2CA50": "Office door,OfficeDoor",
              "2C8D0": "Bedroom 1 door,Bedroom1Door",
              "307D0": "Hallway door,HallwayDoor",
              "33F60": "Bedroom 2 door,Bedroom2Door"
            } -%}
            
            {%- set door_code = code[:-1] -%}
            {%- set operation = code[-1:] -%}
            {{ door_code }},{{ operation }},{{ doors[door_code] }}

  rf_door_openclose:
    alias: rf_door_openclose
    sequence:
      - condition: template
        value_template: >
          {%- set parts = data.split(',') -%}
          {{ true if ((parts | length == 4) and (parts[3] != '')) else false }}
      - service: mqtt.publish
        data_template:
          topic: >
            {%- set topic = data.split(',')[3] -%}
            {{ topic }}/STATE
          payload: >
            {%- set operation = data.split(',')[1] -%}
            {{ 'ON' if (operation == 'A') else 'OFF' }}
          retain: true

  rf_door_problem:
    alias: rf_door_problem
    sequence:
      - condition: template
        value_template: >
          {%- set parts = data.split(',') -%}
          {{ true if ((parts | length == 4) and (parts[2] != '')) else false }}
      - service: notify.telegram_steve
        data_template:
          title: >
            {%- set name = data.split(',')[2] -%}
            {{ name }}
          message: >
            {%- set operation = data.split(',')[1] -%}
            {{ 'Low battery' if (operation == '6') else 'Intrusion' }}

automation:
  - alias: rf_door_state
    trigger:
      - platform: event
        event_type: rf_signal_received
        event_data:
          receiver: RFBridge
    condition:
      - condition: template
        value_template: >
          {% set operationCodes = ['A', 'E', '6', '7'] %}
          {% for op in operationCodes if trigger.event.data.code.endswith(op) %}
            {% if loop.first %}true{% endif %}
          {% endfor %}
    action:
      - service: script.rf_door_state
        data_template:
          code: >
            {{ trigger.event.data.code }}

Edit: My main motivation for this was to have a single, central place to maintain the RF code values for all the doors. The initial script is the only place I have to have those codes in all my YAML.

Here are my ‘door state’ automations. I have small kids, so I want to know if one of them manages to open one of the doors to outside, or leaves one open for an extended time.

automation:

  #######################################################
  # Announce when door is opened or closed
  #######################################################
  - id: announce_door_state
    alias: Door state announcement
    trigger:
      - platform: state
        entity_id:
          - binary_sensor.frontdoor
          - binary_sensor.backdoor
          - binary_sensor.garageinsidedoor
          - binary_sensor.garageoutsidedoor
    condition:
      condition: template
      value_template: >
        {{
          (trigger.to_state.state != "unavailable") and
          (trigger.from_state.state != "unavailable")
        }}
    action:
      - service: script.play_announcement
        data_template:
          entities: default
          media: 'http://10.1.1.4:8123/local/door_open.mp3'
          delay: '00:00:02'
          message: >
            {{ trigger.to_state.attributes.friendly_name }}
            {% if (trigger.to_state.state == 'on') %}
              open
            {% else %}
              closed
            {% endif %}

  #######################################################
  # Announce when door has been left open
  #######################################################
  - id: door_left_open
    alias: Door left open
    trigger:
      - platform: state
        entity_id:
          - binary_sensor.frontdoor
          - binary_sensor.backdoor
          - binary_sensor.garageinsidedoor
          - binary_sensor.garageoutsidedoor
        to: 'on'
        from: 'off'
        for: '00:10:00'
      - platform: state
        entity_id:
          - binary_sensor.garagedoor
        to: 'on'
        from: 'off'
        for: '00:30:00'
    action:
      - service: notify.telegram_steve
        data_template:
          message: >
            The {{ trigger.to_state.attributes.friendly_name }} has been left open.
      - service: script.play_announcement
        data_template:
          entities: default
          media: 'http://10.1.1.4:8123/local/notification.mp3'
          delay: '00:00:03'
          message: >
            The {{ trigger.to_state.attributes.friendly_name }} has been left open.

Not yet, but I’m familiar with your work and I know there’ll be a lightbulb moment soon!
Thanks!

Mine also have the A / E pattern. I wonder if they also tell me about low power / intrusion? I’m tempted to stick in a duff battery to see!!

I really like this. I think the thing that’s irritating me is that I grasp all the Pythonesque aspects of it, but this JSON nonsense just isn’t sinking in for me.