Template binary_sensor with reset on the hour

I’ve set up a set of automations that reduce power consumption (by setting a set of thermostats from heat to eco when power consumption is high). The reason for doing this is that Norwegian grid companies are soon to implement grid tariffs that depend on the highest amount of electric power consumed (by you) during a single hour during the last month. Typically, grid tariffs will depend on whether your maximum consumption was below 2, 5 or 10 kWh during the hour that you consumed the most - if you consume 5.01 kWh during one single hour, you have to pay the 10 kWh tariff…

I’ve set up the following template binary sensor to active power reduction:

template:
  - binary_sensor:
    - name: Activate power reduction
      unique_id: activate_power_reduction
      state: >
        {% set energy = states('sensor.estimated_consumption_current_hour') | float(0.0) %}
        {% set minutes = now().minute %}
        {% set threshold = states('input_number.power_threshold') | float(0.0) %}
        {{ (energy > threshold) and (minutes > 15) and (states('input_boolean.limit_power') == 'on') }}
      delay_off: 
        minutes: 2
      delay_on: 
        minutes: 1

So, if the forecasted consumption for the current hour is higher than a threshold (to be input by the user, 5 kWh/h in my case), and we’re more than 15 minutes into the hour, and the whole ‘limit power’ setup is enabled (input_boolean.limit_power), the binary sensor is set - otherwise unset - with the indicated on and off delays.

It works well, but to make it perfect (I know; if it works, I shouldn’t fix it, but still…), I would like the binary sensor to reset to off on the hour (when minutes go from 59 to 0), and it would if it weren’t for the off delay of 2 minutes. How can I force the binary sensor to reset on the hour, essentially skip the off delay on that occassion? I’ve looked at the trigger option, but I can’t figure out how to combine that with what I have and the off and on delays. Any pointers would be highly appreciated.

Try this:

      state: >
        {% set minutes = now().minute %}
        {% if minutes == 0 %}
          {{ false }}
        {% else %}
          {% set energy = states('sensor.estimated_consumption_current_hour') | float(0.0) %}
          {% set threshold = states('input_number.power_threshold') | float(0.0) %}
          {{ (energy > threshold) and (minutes > 15) and (states('input_boolean.limit_power') == 'on') }}
        {% endif %}

Rather than using the delay on/off options use for: in your state triggers. e.g.

trigger:
  - platform: state
    entity_id: binary_sensor.activate_power_reduction
    from: 'off'
    to: 'on'
    for:
      minutes: 1
trigger:
  - platform: state
    entity_id: binary_sensor.activate_power_reduction
    from: 'on'
    to: 'off'
    for:
      minutes: 2

Thank you for your suggestion!

However, before testing it, I must ask two questions:

  1. In the state section, isn’t the separate {% if minutes == 0 %} {{ false }} redundant? In the {% else %} part, (minutes > 15) accomplishes the same thing

  2. In the trigger sections, the triggers only trigger a state change when the binary_sensor has changed state and stayed that way for 1 or 2 minutes, but the change will never happen because the trigger is waiting for itself (a type of circular reference)?

  1. No, not redundant. minutes = 0 ensures it resets on the hour as you asked for:

The minutes > 15 ensures it can’t turn on until 15 minutes past the hour.

  1. The triggers aren’t for the sensor. The are for wherever you are using the sensor (in automations).

Thank you for taking the time to explain this and excuse my ignorance, I really don’t want to come across as impertinent or querulous, I just want to understand :face_with_monocle:

  1. That’s great, but I don’t understand why (minutes > 15) doesn’t accomplish the same thing? When minutes is 59, (minutes > 15) is true and when minutes becomes 0, (minutes > 15) becomes false and as a result the entire {{ (energy > threshold) and (minutes > 15) and (states('input_boolean.limit_power') == 'on') }} becomes false. Please help me understand why a separate test for minutes == 0 is necessary

  2. The sensor is used for triggering automations. I didn’t spell it out in my OP, but the purpose of resetting the sensor on the hour is to trigger an automation (to reset thermostats from eco to heat) on the hour. So just resetting the sensor without it triggering the related automations is only partly satisfying :slight_smile:

You’re right, it is not necessary.

1 Like

Thanks for an interesting discussion. :+1:

In order to achieve what I want, and inspired by our discussions, I figured making two binary_sensors is the easiest way for this particular challenge:

  • One that just detects high power consumption. This has delays for turning on or off in order to avoid high frequency toggling of the sensor
  • Another one that ANDs the first with (minutes > 15) and whether or not the whole scheme is active. This one has no on or off delays, so I get instant reset on the hour
template:
  - binary_sensor:
    - name: Activate power reduction
      unique_id: activate_power_reduction
      state: >
        {% set minutes = now().minute %}
        {{ (states('binary_sensor.high_power_forecast') == 'on') and (minutes > 15) and (states('input_boolean.limit_power') == 'on') }}
  - binary_sensor:
    - name: High power forecast
      unique_id: high_power_forecast
      state: >
        {% set energy = states('sensor.estimated_consumption_current_hour') | float(0.0) %}
        {% set threshold = states('input_number.power_threshold') | float(0.0) %}
        {{ (energy > threshold) }}
      delay_off: 
        minutes: 2
      delay_on: 
        minutes: 1