Template automation for my boiler

having read another thread here on the WAF, made me laugh somewhat, since just today I was ‘talking’ to my other half about the Boiler being on all the time, or only when we need it (when obviously it is too late…)

since we have solar panels and a ‘cheaper’ night rate, we met half way and I offered to do that automatically. Switch on when panels are above 1500 watts or rate is cheap. well, cheaper. fractionally :wink:

this is what I came up with, not sure if I need another conditional template to prevent it from keeping switching on/of on each watt change, which is of course continously.

- alias: Boiler switch
  id: 'Boiler switch'
  trigger:
    - platform: state
      entity_id: sensor.huidig_tarief
    - platform: numeric_state
      entity_id: sensor.zp_actuele_opbrengst
  condition: []
  action:
    - service_template: >
        switch.turn_{{'on' if states('sensor.zp_actuele_opbrengst') >'1500' or
        is_state('sensor.huidig_tarief', '1') else 'off'}}
      entity_id: switch.sw_boiler_bijkeuken_template  
    - condition: template
      value_template: >
        {{ is_state('input_boolean.notify_notify', 'on')}}
    - service: notify.notify
      data_template:
        message: >
          ZP {{states('sensor.zp_actuele_opbrengst')}}, Tarief {{states('sensor.huidig_tarief')}}: 
          Boiler: {{'on' if states('sensor.zp_actuele_opbrengst') >'1500' or
                     is_state('sensor.huidig_tarief', '1') else 'off'}}.

Please have a look if you find obvious stupidities?

I understand the idea in using templates to turn both on and off, but to me personally I find it makes things a lot more complicated to maintain and troubleshoot for the sake of a few lines of code.
I would personally have 2 automations, one to turn on, one to turn off.
Then you could easily add a condition to only turn on if boiler is off…
Also depending on your sensors you may need to convert the state to an int for your comparison to 1500:
if states('sensor.zp_actuele_opbrengst') | int > 1500

Thank you , i confess never to be certain when to use |int or not. I tried both in the dev-template and both work .

what I feared is happening, it keeps triggering with every power change … While I only want it to trigger when the threshold is met

this is why I would use 2 automations, one to turn on, one to turn off, then it’s fairly easy to add a condition to only turn on if the boiler is off…
Having a single automation makes this a lot more complicated to maintain and troubleshoot :wink:

while i do follow your thoughts about simplicity, I dont think this has to do with the action, but with the trigger. It simply shouldn’t trigger on each power state change. Even if id split this up into 2 automations that would still happen.

maybe adding a trigger above, and change the state trigger to a numeric_state? I had that first but thought to take it out because it has to be a threshold working with ways, not only above…

dilemma’s…

no, the automation will trigger every time the monitored sensors data change since you’ve not set a to or from state in the triggers
The way to stop the action actually running is to add an further condition to check the status of the boiler

will see to that, thanks.
In the mean time Ive made this as a trigger:

- platform: threshold
  name: 'ZP Opbrengst threshold'
  entity_id: sensor.zp_actuele_opbrengst
  upper: 1500
##########################################################################################
# binary sensors based on a threshold- 
# https://home-assistant.io/components/binary_sensor.threshold/

and use it as follows:

- alias: Boiler switch
  id: 'Boiler switch'
  trigger:
    - platform: state
      entity_id: sensor.huidig_tarief
    - platform: state
      entity_id: sensor.zp_opbrengst_threshold
  condition: []
  action:
    - service_template: >
        switch.turn_{{'on' if is_state('sensor.zp_opbrengst_threshold','on') or
                      is_state('sensor.huidig_tarief', '1') else 'off'}}
      entity_id: switch.sw_boiler_bijkeuken_template
    - condition: template
      value_template: >
        {{ is_state('input_boolean.notify_notify', 'on')}}
    - service: notify.notify
      data_template:
        message: >
          Threshold: {{states('binary_sensor.zp_opbrengst_threshold')}}, ZP {{states('sensor.zp_actuele_opbrengst')}}, Tarief {{states('sensor.huidig_tarief')}}: 
          Switching Boiler: {{'on' if is_state('binary_sensor.zp_opbrengst_threshold','on') or
                     is_state('sensor.huidig_tarief', '1') else 'off' }}.

will add a timer to prevent all to frequent changes around the threshold. Let’s see what this brings

It’s simple, really. All states – I said all states – are strings. Period. If you want to compare a state to a number, then you have to convert the state to a number first (int or float, whichever is more appropriate.) Period. Nope, sorry, I said period. :wink:

Now, you say, “but it worked comparing as a strings.” And that might work in some cases, if you’re unlucky. And I say unlucky because by getting into that habit you are going to get bitten sooner or later. And if you want an example that sheds some light on why you don’t want to do the comparison as strings, that’s easy…

'2' > '10' is true. :astonished:

1 Like

Turning a switch on when it’s already on (or off when it’s already off) typically isn’t a problem because, in general, nothing happens. Your problem has more to do with the notification I would guess. I.e., when a state first changes to turn the boiler on and a notification is sent, that’s ok. But if a state changes and the boiler should still be on, then you get another notification, which you don’t want or need. Again, turning the boiler on when it’s already on is probably not an issue.

I agree with @lolouk44. If you used two automations, then each could have a condition that only allows the actions to run if needed (i.e., when turning on only if the boiler is off, and when turning off only when the boiler is on.) Then you’ll only get one notification for each “direction.”

If you’d really rather stay with one automation, then this is still possible, but the condition would have to first determine if you’re about to turn the boiler on or off, and then compare that to the current state of the boiler to see if the actions should run.

I also tend to like fewer automations when possible and practical. But in this case, I think you’ll be better off with two.

EDIT: Oh, BTW, using a threshold binary sensor is a good idea, but note that even if it’s “state” (i.e., on or off) doesn’t change, it will still generate state change events whenever the entity_id it’s listening to changes. So using this sensor as you’re doing won’t solve your ultimate problem. I.e., when sensor.zp_actuele_opbrengst changes, your automation will still run. But you can solve that by using to:. E.g.,

    - platform: state
      entity_id: sensor.zp_opbrengst_threshold
      to: 'on'
    - platform: state
      entity_id: sensor.zp_opbrengst_threshold
      to: 'off'

Will only trigger the automation when the actual (on/off) state of the binary sensor changes.

2 Likes

If you want to be a bit less “trigger happy” you could add a bit of a buffer.
Switch on if it goes above 1500 but only switch it off if it goes below 1450.
So a little up and down around the 1500 will not result in on/off toggles.

Or you might add a minimum ON time. After all running the boiler for 2 minutes is possibly not achieving much. So once you determine it is the correct moment to switch it on, leave it on for x minutes, independent of what the usage is.

Or a combination of the two. You might want to monitor the usage a bit and find the right buffer and timings. But it should smoothen the on/off triggers a bit.

1 Like

of course! seeing a parallel to the presence automations where this is used in the conditions:

condition: template 
value_template: {{ trigger.to_state.state in ['home','not_home'] }}

would this be possible here too (mind you, considering i have more triggering entities, which dont fall into the to:‘on’ to:‘off’ category, so id have to use the entity_id in this condition.

 condition: template 
   value_template: {{ states('binary_sensor.zp_opbrengst_threshold')
   in ['on','off'] }}

adding that, and the timer to not have it toggle around the threshold, and a check it doesnt trigger to a state it came from, would then lead to this:

  - alias: Boiler switch
    id: 'Boiler switch'
    trigger:
      - platform: state
        entity_id: sensor.huidig_tarief
      - platform: state
        entity_id: binary_sensor.zp_opbrengst_threshold_input
    condition:
      - condition: template
        value_template: >
          {{ trigger.to_state.state is not none and
             trigger.from_state.state is not none and
             trigger.to_state.state != trigger.from_state.state }}
      - condition: template
        value_template: >
         {{ states('binary_sensor.zp_opbrengst_threshold_input') in ['on','off'] }}
      - condition: template
        value_template: >
          {{ (as_timestamp(now()) - 
              as_timestamp(state_attr('automation.boiler_switch','last_triggered')) 
              | default(0) | int > 240) }}
    action:
      - service_template: >
          switch.turn_{{'on' if is_state('binary_sensor.zp_opbrengst_threshold_input','on') or
                        is_state('sensor.huidig_tarief', '1') else 'off'}}
        entity_id: switch.sw_boiler_bijkeuken_template
      - condition: template
        value_template: >
          {{ is_state('input_boolean.notify_notify', 'on')}}
      - service: notify.notify
        data_template:
          message: >
            Threshold: {{states('binary_sensor.zp_opbrengst_threshold_input')}}, ZP {{states('sensor.zp_actuele_opbrengst')}}, Tarief {{states('sensor.huidig_tarief')}}: 
            Switching Boiler: {{'on' if is_state('binary_sensor.zp_opbrengst_threshold_input','on') or
                       is_state('sensor.huidig_tarief', '1') else 'off' }}.

thx! the being -on timer would be a nice addition indeed.
please see above, for I had just added a timer :wink:

how would you add this being_on timer into this?

I now use an input slider to set the threshold (i like to do that to be able to play with the values easily)
not sure if the binary_sensor template threshold sensor has the option of setting both above and below values, which the regular threshold binary does.

must explore that a bit further

this I like, getting to the fundamentals thx.
consuming this, I think i have to go through all my configuration files hunting for possible discrepancies.

might I post 2 of these here, which have all uncertainties on my part in them, please check where things need correction on this aspect.

  - alias: Vijverpomp moet aan
    id: 'Vijverpomp moet aan'
    trigger:
      platform: numeric_state
      entity_id: sensor.rsd_temperature
      above: 6
    condition:
      - condition: template
        value_template: >
          {{ 7 > states('sensor.rsd_temperature')|float > 5 }}

the float is there, but the numbers, should they be in quotes or not? both in the trigger and in the template.

and this one, where all is mixed up, but, as you say i might say, it works :wink:

    entity_picture_template: >
      {% if is_state('sensor.espresso_keuken_actueel', '0') %}
        /local/buttons/button_power_off.png
      {% elif 0 < states('sensor.espresso_keuken_actueel')|float < 1 %}
        /local/various/watertap.png
      {% else %}
        /local/activities/opstaan.png
      {% endif %}

Thought i’d share what it looks now in the frontend:
39

No, this is not the same. Using to: restricts the trigger based on both the from and to states, not just the to state. And you’re suggesting adding a condition that will always basically be true, so that really doesn’t help you.

This, though, could actually help. That would filter out any state change events that weren’t caused by one of the entities’ state actually changing.

Good idea, and since he’s using the threshold binary sensor, this is extremely easy to do by just defining hysteresis.

If you put a number in quotes, what do you think that does? It turns it into a string. Why would you want to make a number a string to compare against another number when I just explained why you shouldn’t do that? FWIW, it doesn’t matter with the above: parameter to the trigger, because when that is parsed it will be “coerced” into a float anyway. So you can try to mess it up by quoting it, but it won’t let you. :wink:

In your entity_picture_template, it pretty much looks ok. The one problem you might have is with:

is_state('sensor.espresso_keuken_actueel', '0')

It depends on how the sensor works. Again, the state is always going to be a string. But it’s probably a number before getting turned into a string. If it’s an int, then this will probably work. But if it’s a float, then converting a value of zero to string will end up with ‘0.0’, which is not equal to ‘0’. So you should probably change that to:

state('sensor.espresso_keuken_actueel')|int == 0
1 Like

you mean as in, if it going to a ‘to’ it should be coming from a ‘from’…? Which would of course only apply in case of a binary.

i did this, believing to be useful because Id be ruling out all the attributes changes triggering the state…
as with the set of trigger.to templates. see @petro s solution here : More than one to: in a state trigger? - #10 by petro

Mostly that rules out it fires when coming from a state is was in. A very elegant way of preventing it to fire on each value being above the threshold. Or being the same, as in people being home.

I understand how to do this with the regular threshold binary,

binary_sensor:
- platform: threshold
  name: 'ZP Opbrengst threshold'
  entity_id: sensor.zp_actuele_opbrengst
  upper: 1500
  hysteresis: 300

btw, does this go both ways?

but how to do that with the input i use:

- platform: template
  sensors:
    zp_opbrengst_threshold_input:
      friendly_name: 'ZP Opbrengst threshold input'
      value_template: >
        {{(states('sensor.zp_actuele_opbrengst') | float) >
          (states('input_number.zp_opbrengst_threshold') | float)}}

Im trying to understand 100%…
previously, when testing the templates. I changed the number and quoted it, (to compare it with the states, being a string…) but now see I should have made the strings into numbers with |int or |float.

cool, thanks for the very clear explanation!

There seems to be some confusion here. So let’s take a step back.

First, the term “state” has been (unfortunately) overloaded in HA. It sometimes refers to a state object, but it also sometimes refers to the state object’s state string. In fact, I believe in most cases when someone just says “state” they mean the state object’s state string. I’ll try to be very specific…

A state object represents (what I’ll call) the status of an entity at some point in time. As mentioned it contains a state string, which is, again, what most people call the “state” of the entity. But it also (typically) contains one or more attributes.

If any part of the state object changes (i.e., either the state string, or any of the attributes) it will cause a state_changed event. And since there’s a change, that means there’s an old state object that represents the status of the entity before the change, and a new state object that represents the status of the entity after the change.

The state trigger watches for state changes. It may or may not trigger on all state changes. If from: and to: are not specified, then it will trigger on every state change, even if that change was only in an attribute.

If from: and/or to: are specified, then the state trigger will only trigger when the state string changes as specified by from: and/or to:. (To be clear, just an attribute change will not cause a trigger in this case.) If to: is specified, then the new state string must match it. If from: is specified, then the old state string must match it. If both are specified then both the new and old state strings must match accordingly.

(Note that when the state trigger actually triggers, trigger.from_state contains a copy of the old state object, and trigger.to_state contains a copy of the new state object.)

Now getting back to your question, from: and/or to: can be used with any entity, not just a binary one. E.g., let’s say there’s a sensor whose state string can take on the values ‘a’, ‘b’ or ‘c’. If you specify to: a, then ‘b’->‘a’ will trigger, and ‘c’->‘a’ will also trigger, but ‘b’->‘c’ and ‘c’->‘b’ will not. And if you specify both from: a and to: b, then only ‘a’->‘b’ will trigger it, but no other state change will.

Specifying:

condition: template 
value_template: "{{ states('binary_sensor.zp_opbrengst_threshold') in ['on','off'] }}"

does not “filter out” attribute changes. It only does what it says. It allows the actions to run if the binary sensor is either ‘on’ or ‘off’ (which it almost always, and possibly always, is. I say almost always, because a binary sensor can sometimes take on other values such as ‘unknown’ or ‘unavailable’. It’s only “binary” in its usual values.)

You can always look at the code. :slight_smile: The threshold binary sensor doesn’t just look at the current value of the watched entity to decide if it should be ‘on’ or ‘off’. It also remembers whether the threshold has been crossed. And if you specify hysteresis, that threshold is not a fixed value. E.g., if you specify upper:, then on the way up the threshold is actually upper + hysteresis. But on the way back down it becomes upper - hysteresis. That’s the whole point (i.e., to implement hysteresis.)

3 Likes

great thanks,

before i make stupid changes:
Ive had an automation fire many times stating the person left home. Continuously.

could i prevent that from happening adding this:

trigger.from_state.state != trigger.from_state.state ?

Why not just use a state trigger with from: 'home'? That will only trigger when the device_tracker changes from ‘home’ to something else (i.e., only when leaving home.)

BTW, a != a will never be true.

FWIW, from: 'home' is effectively the same as having a template condition of:

trigger.from_state.state == 'home' and trigger.to_state.state != trigger.from_state.state

well, thats exactly why I don’t use it…Or think I shouldn’t.
I want it to show me where the device_trackers are, home, not_home, or in one of my zones.

hmm, That seems logic:-)

still, how to prevent it from triggering on the same “left zone.x” repeatedly.

this is the desired message:

  {% if trigger.to_state.state == 'not_home' %}
    {{ trigger.to_state.attributes.friendly_name }} left {{trigger.from_state.state}}
  {% elif trigger.from_state.state == 'not_home' %}
    {{ trigger.to_state.attributes.friendly_name }} arrived at {{trigger.to_state.state}}
  {% else %}
    {{ trigger.to_state.attributes.friendly_name }} left {{trigger.from_state.state}} and arrived at {{trigger.to_state.state}}
  {% endif %}

@petro helped me here to write it as:

      {% set name = trigger.to_state.attributes.friendly_name %}
      {% set to_state = trigger.to_state.state %}
      {% set from_state = trigger.from_state.state %}
      {% if to_state == 'not_home' %}
        {{ name}} left {{from_state}}
      {% elif from_state == 'not_home' %}
        {{ name }} arrived at {{to_state}}
      {% else %}
        {{ name }} left {{from_state}} and arrived at {{to_state}}

had a few more for testing purposes, but hope to get this right first…

since this is i another thread, if you would like to comment, maybe best to do it there?

thx for all your support.
Marius