#How to add second notification to automation if template sensor changes value?

1 messages · Page 1 of 1 (latest)

ember cedar
#

Hello everyone,
I have a bunch of Shelly devices that tend to run hot and sometimes then shut down.

I created a template sensor that lists all Shellys that exceed 85 °C

template:
  - sensor:
      - name: Shelly High Temperature
        state: >
            {% set ns = namespace(list=[]) %}
            {% for item in states.sensor                    
                | selectattr('entity_id', 'contains', 'analog_temperature')
                | selectattr("state", 'is_number')
            %}
              {% if item.state | float > 85 %}
                {% set ns.list = ns.list + [ item.entity_id ] %}
              {% endif %}
            {% endfor %}
            {{ ns.list | to_json }}

I then created an automation to notify me.

automation:
  - alias: Shelly High Temperature
    id: shelly_high_temperature
    description: ''
    mode: parallel   
    triggers:
      - trigger: state
        entity_id:
          - sensor.shelly_high_temperature
    conditions:
      - and:
        - condition: template
          value_template: "{{ trigger.to_state.state | from_json | count > trigger.from_state.state | from_json | count }}"   
    actions:
      - action: notify.mobile_app_sm_g975f
        data:
          message: "Warning! Temperature of {{ trigger.to_state.state | from_json | reject('in', trigger.from_state.state) | join }} high"

I would like to modify the automation so it notifies me when a Shelly exceeds 85 °C (stating the actual temperature it measures) and then again, when/if the temperature exceeds 90 °C.

Does anybody know how to do this without creating additional sensor+automation pairs?

Thank you
Alex

steel rover
#

I would create two template sensors: one for >85 and the second for >90. The state of each sensor would be the total count of devices that exceed the respective temperature, and you can have an entities attribute which is a list of all the sensor entity_id’s of the devices that qualify.

For the automation, you can use a state trigger, and then use a condition where {{ trigger.to_state.state | int > trigger.from_state.state | int }}

#

There are, of course, ways to do this in a single template sensor. Heck, you can even do the notification in the action part of the template sensor. But, since template sensors have to be created in YAML, it makes it more difficult to maintain the automation part of it. And just putting the 2 sensors in one will cause some complexity like having the state being a list of values.

ember cedar
#

Thank you for your ideas 🙂
I have to say that I find it more convenient, for maintainability to have as little sensors and automations as possible. I prefer one complex yaml (within reason) to 10 simple ones.

I created a second template sensor and am using the original automation with a second trigger.
I did not even know that template sensors support actions. So I looked it up, seems to be "new" but also seems to not be compatible with my classical template sensor approach. I think it only works for trigger based template sensors.

steel rover
#

Yes, actions are only possible with trigger-based template sensors

steel rover
#

Here's a template sensor I made:

template:
  - sensor:
      - name: High Temperature Entities
        unique_id: 01976273-0902-7015-b7cd-0fb4266c8eb7
        state: >
            {{ states.sensor | selectattr('entity_id', 'search', 'temperature$') | selectattr('state', 'is_number') | map(attribute='state') | map('float') | select('>', 85) | list | count }}
        attributes:
          gt85: >
            {% set sensors = states.sensor | selectattr('entity_id', 'search', 'temperature$') | selectattr('state', 'is_number') | map(attribute='entity_id') | list %}
            {% set sensor_dict = zip(sensors, sensors | map('states') | map('float')) | list %}
            {{ dict(sensor_dict | selectattr(1, '>', 85) | list | sort(attribute=0, reverse=false)).keys() | list }}
          gt95: >
            {% set sensors = states.sensor | selectattr('entity_id', 'search', 'temperature$') | selectattr('state', 'is_number') | map(attribute='entity_id') | list %}
            {% set sensor_dict = zip(sensors, sensors | map('states') | map('float')) | list %}
            {{ dict(sensor_dict | selectattr(1, '>', 95) | list | sort(attribute=0, reverse=false)).keys() | list }}
#

When I make one of my sensors change from 84 to 86 deg, the template sensor actually gets updated several times in rapid succession. Changing the gt85 attribute first, and then another update to change the state.

So, it's still possible to do it this way, but the automation has to be triggered off a specific attribute changing, rather than any state or attribute, or even just looking at the state only.

And so there's just a whole lot of duplication of code doing it this way. You can even see in my template sensor above how much duplication there is in the sensor. The automation is even worse.

#
alias: Test Automation
description: ""
triggers:
  - trigger: state
    entity_id:
      - sensor.high_temperature_entities_8
    attribute: gt85
  - trigger: state
    entity_id:
      - sensor.high_temperature_entities_8
    attribute: gt95
conditions:
  - condition: or
    conditions:
      - condition: template
        value_template: >-
          {{ trigger.to_state.attributes.gt85 | count >
          trigger.from_state.attributes.gt85 | count }}
      - condition: template
        value_template: >-
          {{ trigger.to_state.attributes.gt95 | count >
          trigger.from_state.attributes.gt95 | count }}
actions:
  - variables:
      gt85_new_entities: >-
        {{ difference(trigger.to_state.attributes.gt85,
        trigger.from_state.attributes.gt85) }}
      gt95_new_entities: >-
        {{ difference(trigger.to_state.attributes.gt95,
        trigger.from_state.attributes.gt95) }}
      all_new_entities: "{{ gt85_new_entities + gt95_new_entities }}"
  - action: persistent_notification.create
    metadata: {}
    data:
      message: |
        Warning! Temperature of {{ all_new_entities | join(', ') }} too high!
      title: Test Automation
mode: single
steel rover
#

here's a trigger-based template sensor example:

template:
  - triggers:
      - trigger: time_pattern
        seconds: '/5'
    variables:
      gt85_entities: >
        {% set sensors = states.sensor | selectattr('entity_id', 'search', 'temperature$') | selectattr('state', 'is_number') | map(attribute='entity_id') | list %}
        {% set sensor_dict = zip(sensors, sensors | map('states') | map('float')) | list %}
        {{ dict(sensor_dict | selectattr(1, '>', 85) | list | sort(attribute=0, reverse=false)) | to_json }}
    sensor:
      - name: High Temperature Entities Triggered
        unique_id: 019762de-2cbc-747d-8f84-f56d5c1dae15
        state: >
          {{ gt85_entities | count }}
        attributes:
          gt85: >
            {{ gt85_entities | list }}
          gt95: >
            {{ gt85_entities.items() | selectattr(1, '>', 95) | map(attribute=0) | list }}
ember cedar
#

Nice 🙂
The downside with using trigger in this case is that there is no useful trigger available. A template trigger would probably work. But a time based trigger creates lots of redundant checks. I am filtering the broadcast so updates to the values do not occur very often and this criteria is reached maybe once a day, if that.

I chose

template:
  - sensor:
      - name: Shelly 85°C
        unique_id: shelly_85degC
        state: >
            {% set ns = namespace(list=[]) %}
            {% for item in states.sensor                    
                | selectattr('entity_id', 'contains', 'analog_temperature')
                | selectattr("state", 'is_number')
            %}
              {% if item.state | float > 85 %}
                {% set ns.list = ns.list + [ item.entity_id ] %}
              {% endif %}
            {% endfor %}
            {{ ns.list | to_json }}

  - sensor:
      - name: Shelly 90°C
        unique_id: shelly_90degC
        state: >
            {% set ns = namespace(list=[]) %}
            {% for item in states.sensor                    
                | selectattr('entity_id', 'contains', 'analog_temperature')
                | selectattr("state", 'is_number')
            %}
              {% if item.state | float > 90 %}
                {% set ns.list = ns.list + [ item.entity_id ] %}
              {% endif %}
            {% endfor %}
            {{ ns.list | to_json }}            
#

and the very simple automation

automation:
  - alias: Shelly High Temperature
    id: shelly_high_temperature
    description: ''
    mode: parallel   
    triggers:
      - trigger: state
        entity_id:
          - sensor.shelly_85degC
      - trigger: state
        entity_id:
          - sensor.shelly_90degC          
    conditions:
      - condition: template
        value_template: >
          {{ trigger.to_state.state | from_json | count > trigger.from_state.state | from_json | count }}
    actions:
      - action: notify.mobile_app_sm_g975f
        data:
          message: >
            {% set new_sensor = (trigger.to_state.state | from_json | reject('in', trigger.from_state.state | from_json) | first) %}
            Warning! {{ state_attr(new_sensor, 'friendly_name') or new_sensor }} reached {{ states(new_sensor) }}°C