Mode: restart and delays

Hi all,
I’m struggling to understand how to obtain an ‘off delay time’ given some calculated decision.
My situation is around humidity control for a bathroom fan (should be simple…), but I seem to be fighting against the HA automation engine.
For note: this is for a blueprint, so whilst my very first ‘design’ used two separate automations, that can’t be used here.

My action part is shown below:

action:
  - choose:
      # IF humidity above start setpoint
      - conditions: "{{difference|float > rising_threshold|float}}"
        alias: "Humidity above reference by more than start setpoint"
        sequence:
          - delay:
              minutes: !input rising_delay
          - service: homeassistant.turn_on
            entity_id: !input fan_switch
      # ELIF humidity below stop setpoint
      - conditions: "{{difference|float < falling_threshold|float}}"
        alias: "Humidity above reference by less than stop setpoint"
        sequence:
          - delay:
              minutes: !input falling_delay
          - service: homeassistant.turn_off
            entity_id: !input fan_switch

The issue being, if the humidity increases again, I want to cancel the off delay, and keep the fan on.
This seems to then require mode: restart. But if I do that, it seems that the timer restarts even when the humidity is still dropping below the setpoint.

There are obviously really bad work arounds that I could do, like manually capturing the time when the value cross the thresholds, and then use (now() - time_from_threshold) > delay time… but this seems like such a simple thing, it shouldn’t require that level of unpleasantness in my logic.

Is there a detail that I’m missing?
Does the delay not really restart in such situations and I’ve just been mistaken?
Or does mode: single really allow for me to abort the sequence path to turn the fan off if the humidity raises again?

There are 4 analog sensors feeding into the logic, and the off delay times are in the range of 10minutes… so restarts are reasonably likely during that time (as is the humidity going up again).

I’m assuming your trigger is just a state trigger for the humidity, which is why the automation gets restarted as the humidity continuously falls?

This is actually very similar to motion-activated light automations, which someone asks about almost daily, since the lights should stay on until motion hasn’t been detected for a set amount of time. You could search around for ideas along that path if you don’t like anything you hear here.

My recommendation is to trigger your automation when the humidity rises to a set point. Then, separate your on and off actions with a wait_for_trigger housing a state trigger at your cut off point with a for value of your delay time. You can leave the mode as single if you take this route.

The automation triggers are: humidity, temperature, reference humidity and reference temperature. Unfortunately the current state of any one of these is not an indicator of whether the fan should start/stop.

So there is a calculation which combines the humidity & temperature for each location (source and destination as it were) and then gets the difference (which is what is compared against the setpoints).

I’m unsure on the ‘state trigger’ aspect. I don’t believe there is a particular singular state trigger involved here, since relative humidity (the sensor) going > xx% is NOT used for the start condition [it would be f(relative humidity, temperature) > xx g/m2].

I’ve definitely looked at lots of the motion-activated light items, and all of them appear to come down to using a trigger with a for: clause to it, or some other kind of state transition (i.e. from: ‘on’ to: ‘off’ for: 5min) which does not apply for my case (I could not have from: < ‘xx’ to: > ‘yy’ for: 10min because there is no single entity that this state would apply for).

It looks like ideally having a template sensor would be the best way… but this doesn’t appear to be possible to have in a blueprint.

I see, that is certainly a bit more complicated.

What makes you say it isn’t possible to use a template sensor in a blueprint? You would define the sensor outside of the blueprint and just pass it in like a normal entity.

I mean it’s not possible to define a sensor as part of a blueprint. And having to create things like a sensor that performs all the calculations outside of the blueprint really defeats the purpose of having a blueprint.

Is there a reason that the delay is restarted for each triggered execution of the automation?
I would have expected the delay to only get restarted if it wasn’t executed in a particular pass of the automation (i.e. if a different choose was taken, or a prior condition wasn’t set etc).

I’m fully understanding of the delay restarting when the entire automation service is restarted, or the home assistant instance itself is restarted. But for it to get restarted on a retriggering of the automation seems strange to me.

Fair. Could just define it as a variable at the beginning of be blueprint?

Well, the delay is an action of the automation and the automation gets restarted when it is retriggered. Meaning the automation stops what it is currently doing, delaying in this case, and starts from the top. Your options are to move the delay outside the automation, as a timer, or to not restart the automation, like we’re discussing.

Since both of your choose conditions are templates, couldn’t you make those templates, the triggers?

How would I do this in a blueprint?

That calculation is exactly done as a variable within the blueprint (it’s what calculates the ‘difference’ referenced in the action).

If the automation doesn’t get restarted (via mode: single instead of restart) then how would it abort the current ‘delay’? (i.e. if the moisture content goes above the stop setpoint again).

Is it possible to move the delay outside of the automation but still have it defined within the blueprint? (I haven’t seen this anywhere… but I haven’t really looked exactly for this either).

It would still be the same as I described above, but with a template trigger instead of a state trigger.

Possible, yes, but starting to over-complicate things. I’d still recommend trying to get a wait_for_trigger working in this situation.

Thanks for the persistence :slight_smile:
Ok, so I’ve gone with the trigger_template system you’ve mentioned. And it turns on fine… but it’s not turning off (the trigger doesn’t seem to occur).

I’ll dump the whole thing in here incase someone can notice the error.
The error handling of the states needs tidying up, but they’re all valid at the moment.

I had the falling_delay set to 8 minutes originally, but dropped it to 1 minute for testing. I waited both periods of time, and nothing exciting happened (=fan continues to run).

blueprint:
  name: Humidity Management based on abs. humidity (g/m3)
  description:
    Turn a fan on or off based on the absolute humidity difference between a
    humidity sensor and a reference
  domain: automation
  input:
    humidity_sensor:
      name: Humidity Sensor
      description:
        A sensor that measures the humidity of the area to be vented, for
        example the shower
      selector:
        entity:
          domain: sensor
    temperature_sensor:
      name: Temperature Sensor
      description:
        A sensor that measures the temperature of the area to be vented,
        for example the shower
      selector:
        entity:
          domain: sensor
    reference_humidity_sensor:
      name: Reference Humidity Sensor
      description:
        A sensor that indicates the baseline humidity of the area outside
        of the vented, for example the walkway outside the shower
      selector:
        entity:
          domain: sensor
      default: []
    reference_temperature_sensor:
      name: Reference Temperature Sensor
      description:
        A sensor that indicates the baseline temperature of the area outside
        of the vented, for example the walkway outside the shower
      selector:
        entity:
          domain: sensor
      default: []
    fan_switch:
      name: Fan Switch
      description: A switch that turns the fan on and off
      selector:
        entity:
          domain: switch
    rising_threshold:
      name: Rising Threshold (in g/m3)
      description:
        How many gram/m3 above the reference humidity the sensor can rise
        before the fan is turned on
      selector:
        number:
          min: 0.0
          max: 3.0
          mode: slider
          step: 0.1
      default: 1.1
    rising_delay:
      name: Rising Delay
      description: Time delay once rising threshold is met prior to the fan turning on
      selector:
        number:
          min: 0
          max: 60
          step: 0.1
          unit_of_measurement: "min"
          mode: slider
      default: 0
    falling_threshold:
      name: Falling Threshold
      description:
        How many gram/m3 above the reference humidity the sensor must fall
        to before the fan is turned off
      selector:
        number:
          min: 0.0
          max: 3.0
          mode: slider
          step: 0.1
      default: 0.9
    falling_delay:
      name: Falling Delay
      description: Time delay once falling threshold is met prior to the fan turning off
      selector:
        number:
          min: 0
          max: 60
          step: 0.1
          unit_of_measurement: "min"
          mode: slider
      default: 5

trigger_variables:
  temperature_sensor: !input temperature_sensor
  humidity_sensor: !input humidity_sensor
  ref_temperature_sensor: !input reference_temperature_sensor
  ref_humidity_sensor: !input reference_humidity_sensor
  fan_switch: !input fan_switch
  rising_threshold: !input rising_threshold
  rising_delay: !input rising_delay
  falling_threshold: !input falling_threshold
  falling_delay: !input falling_delay

trigger:
  - platform: template
    id: high_humidity
    value_template: "{% set src_h = states(humidity_sensor)|float %} \
      \ {% set src_t = states(temperature_sensor)|float%} \
      \ {% set dst_h = states(ref_humidity_sensor)|float%} \
      \ {% set dst_t = states(ref_temperature_sensor)|float%} \
      \ {% if (not src_h) or (not src_t) or (not dst_h) or (not dst_t) -%}'unknown' \
      \ {%- else -%} \
      \ {{ ((src_h*6.112*2.1674*e**((src_t*17.67)/(src_t+243.5))/(src_t+273.15)) - \
      \ (dst_h*6.112*2.1674*e**((dst_t*17.67)/(dst_t+243.5))/(dst_t+273.15)))
      \ > rising_threshold|float}} \
      \ {%- endif %}"
    for:
      minutes: !input rising_delay
  - platform: template
    id: low_humidity
    value_template: "{% set src_h = states(humidity_sensor)|float %} \
      \ {% set src_t = states(temperature_sensor)|float%} \
      \ {% set dst_h = states(ref_humidity_sensor)|float%} \
      \ {% set dst_t = states(ref_temperature_sensor)|float%} \
      \ {% if (not src_h) or (not src_t) or (not dst_h) or (not dst_t) -%}'unknown' \
      \ {%- else -%} \
      \ {{ ((src_h*6.112*2.1674*e**((src_t*17.67)/(src_t+243.5))/(src_t+273.15)) - \
      \ (dst_h*6.112*2.1674*e**((dst_t*17.67)/(dst_t+243.5))/(dst_t+273.15)))
      \ < falling_threshold|float}} \
      \ {%- endif %}"
    for:
      minutes: !input falling_delay

action:
  - choose:
      # IF moisture content difference above start setpoint
      - conditions:
          condition: trigger
          id: high_humidity
        alias: "Humidity different above start setpoint"
        sequence:
          - service: homeassistant.turn_on
            entity_id: !input fan_switch
      # ELIF moisture content difference below stop setpoint
      - conditions:
          condition: trigger
          id: low_humidity
        alias: "Humidity difference below stop setpoint"
        sequence:
          - service: homeassistant.turn_off
            entity_id: !input fan_switch

I don’t see anything off the bat. Obviously, it’s just never evaluating to true, but I’m not sure why it wouldn’t since you just copy and pasted the formula, I assume. Maybe just try copy and pasting it again, to double check something didn’t get messes up along the way.

To help debug, can you copy and paste your value template into a template sensor and ensure it is reaching the shutoff point successfully? Just need someway to determine how it is broken.

You could also look around the automation run trace to make sure all of your inputs are showing up correctly; maybe the falling threshold is being weird or something. You’d probably want to add some sort of timeout for this, though.

I think potentially the trigger is not very reliable. I’ve had a few more tests of it, and it does seem to work if I have things all set and run through cleanly. But if I make a change which restarts either the full HA server, or even just the Automation around the time that whilst the ‘for’ would have expired is ‘timing’ it seems to just not occur… and hence never does that action, even if I trigger the automation manually.

Is there any plan for blueprints to get extended so that they could generate template sensors / template binary_sensors or similar?
Or perhaps delay timers that don’t reset unless the automation runs and that delay action is not executed (which is how common time delay relays work…)?

Yes, this is a common problem with any type of delay. I didn’t bring it up since you said that you were dealing with timers around ten minutes. Are you really planning on restarting HA or the automations in that ten minutes regularly? That’s the only time this should be a problem. There are a couple ways around this, but, again, starting to over-complicate a fairly simple automation.

Not that I know of, which is very little, but I’m not sure what this would solve that variables and template triggers don’t.

I’ll have to look into that a bit more. I had a quick dive through the backend python code for the script engine, unfortunately it didn’t look very easy to fix up. Not surprising given if it was easy, someone would have done it already.

It would move the timer out of the automation. Both the delay and the wait_template have the timeout as being associated with the instance of the script execution. If using a template sensor, then the hope is it could be decoupled from the script execution (so automation restarts wouldn’t be a problem… it would only be the HA restarts, which as you say, are much less frequent).

Thank you very much for the assistance. Unfortunately at this stage I’ve gone back to the original automation I had (with the delay) and just turning it into Single Mode. It has some non-ideal behaviours, but it is pretty predictable.