Security alarms: example of sensors grouping

Hi All,

I’m maintaining this security alarm component and recently we discussed lack of some features and sensors grouping was mentioned.
Here is the quote:

This helps prevents false alarms from triggering. All that is you would group sensors and set a time limit between them to see 8f the alarm should go off or not. For example you have two motion sensor in one room and one detects motion. With cross grouping you can set let’s say 30 seconds and if that second motion sensor detects motion the alarm would trigger otherwise it would not.

I think it’s relatively easy to implement such a concept in HA using template sensors and then use that sensor with any security alarm component.
Here is my version of PIRs grouping (actually, it works for any binary_sensor-based sensors like door contacts, smoke sensors etc):

binary_sensor.yaml

- platform: template
  sensors:
    pir_1_on_prolonged:
      value_template: "{{ is_state('binary_sensor.pir_1', 'on') }}"
      delay_off:
        seconds: 30

    pir_2_on_prolonged:
      value_template: "{{ is_state('binary_sensor.pir_2', 'on') }}"
      delay_off:
        seconds: 30

    pir_cross_sensor:
      entity_id:
        - binary_sensor.pir_1
        - binary_sensor.pir_2
        - group.cross_sensors_group
      value_template: >-
        {% set ns = namespace(found=0) %}
        {% for entity_id in states.group.cross_sensors_group.attributes.entity_id if is_state(entity_id, 'on') and (ns.found < 2) %}
          {% set ns.found = ns.found + 1 %}
        {% endfor %}
        {{ ns.found == 2 }}

group.yaml

cross_sensors_group:
  name: "cross-sensor grouping"
  entities:
    - binary_sensor.pir_1_on_prolonged
    - binary_sensor.pir_2_on_prolonged

The binary_sensor.pir_cross_sensor will be on from the moment there are at least 2 different on_prolonged sensors in on state until there is none of them.
The delay between individual sensors’ signals to make binary_sensor.pir_cross_sensor active is set by that delay_off and can be replaced by template so you can easily have user-configurable delays:

delay_off: "{{ states('input_number.cross_sensor_delay') }}

If you need to add sensor binary_sensor.doorcontact_1 to the group, complete the following steps:

  1. Create a corresponding on_prolonged template binary sensor by copying the declaration of binary_sensor.pir_1_on_prolonged and replacing binary_sensor.pir_1 with binary_sensor.doorcontact_1
  2. Add its entity_id to the cross_sensors_group group
  3. Add entity_id of the original (not on_prolonged!) sensor (binary_sensor.doorcontact_1 in this example) to the entity_id list of binary_sensor.pir_cross_sensor
    … and that’s it!

I’ve decided to combine all sensors in a group as I think it makes it easier to extend/maintain the config as without that we’d need an array of on_prolonged entities in the binary_sensor.pir_cross_sensor value_template to iterate over.

Would love to hear your feedback and any ideas how to improve it or alternative solutions.

UPDATE: it looks like instead of

{% for entity_id in states.group.cross_sensors_group.attributes.entity_id

we can use

{% for entity_id in expand('group.cross_sensors_group')
3 Likes

This is what I was looking for. Is there a simpler way to get the same result?
I mean to trigger the alarm when two or more sensor from the same group are activated in a certain period of time.

Thanks!

I have no idea if there is an easier way but this example isn’t too complicated, why don’t use it?

Actually is not… I was wondering if there were something more graphic (lazy me!!)

Sorry, I’m not aware of that.

Dude! I meant that the code is not complicated… I didn´t want to be an as*!
Sorry :slight_smile:

No worries at all, my comment was about

:rofl:

Hey, for some reason the pir_cross_sensor state do not change to on when I activate two or more of the included sensors. Here is the code:

binary_sensors.yaml

  - platform: template
    sensors:
      motion_arriba_on_prolonged:
        value_template: "{{ is_state('binary_sensor.motion_arriba_occupancy', 'on') }}"
        delay_off:
          seconds: 30

      motion_cocina_on_prolonged:
        value_template: "{{ is_state('binary_sensor.motion_cocina_occupancy', 'on') }}"
        delay_off:
          seconds: 30

      motion_comedor_on_prolonged:
        value_template: "{{ is_state('binary_sensor.motion_comedor_occupancy', 'on') }}"
        delay_off:
          seconds: 30

      motion_hall_on_prolonged:
        value_template: "{{ is_state('binary_sensor.motion_hall_occupancy', 'on') }}"
        delay_off:
          seconds: 30

      motion_living_on_prolonged:
        value_template: "{{ is_state('binary_sensor.motion_living_occupancy', 'on') }}"
        delay_off:
          seconds: 30

      motion_escalera_on_prolonged:
        value_template: "{{ is_state('binary_sensor.motion_escalera_occupancy', 'on') }}"
        delay_off:
          seconds: 30

      motion_pieza_on_prolonged:
        value_template: "{{ is_state('binary_sensor.motion_pieza_occupancy', 'on') }}"
        delay_off:
          seconds: 30

      pir_cross_sensor:
        entity_id:
          - binary_sensor.motion_arriba_occupancy
          - binary_sensor.motion_cocina_occupancy
          - binary_sensor.motion_comedor_occupancy
          - binary_sensor.motion_hall_occupancy
          - binary_sensor.motion_living_occupancy
          - binary_sensor.motion_escalera_occupancy
          - binary_sensor.motion_pieza_occupancy
          - group.cross_sensors_group
        value_template: >-
          {% set ns = namespace(found=0) %}
          {% for entity_id in expand('group.cross_sensors_group') if is_state(entity_id, 'on') and (ns.found < 2) %}
            {% set ns.found = ns.found + 1 %}
          {% endfor %}
          {{ ns.found == 2 }}

  - platform: group
    name: "cross sensors group"
    entities:
    - binary_sensor.motion_arriba_on_prolonged
    - binary_sensor.motion_cocina_on_prolonged
    - binary_sensor.motion_comedor_on_prolonged
    - binary_sensor.motion_hall_on_prolonged
    - binary_sensor.motion_living_on_prolonged
    - binary_sensor.motion_escalera_on_prolonged
    - binary_sensor.motion_pieza_on_prolonged

do I have to trigger the sensor or something? Please be kind, Remember I’m a noob. :grinning:

and also get this: