Elegant automation for 3 temperature input and 2 fans

There is a high level of ground water so in my house I cannot have “normal” cellar. So there is well isolated room on the ground level with two air connections. One take the air just from outside (called OUT), the second (called GWC) goes from 20 meter pipe buried in the ground (less then 1m deep). Air going through this pipe is getting cooled and thus making my cellar chilled. Each connecting has its own fan in the cellar and temperature sensor on the “input” side. There is also CEL temp sensor in the cellar.
I have a challenge to write an elegant automation (instead of several independent automations) based on the following assumptions:

  1. As long as temperature in CEL is beloe 12C do nothing

  2. With CEL temp > 12
    a) if the OUT temperature is lower then CEL by 2 degrees turn ON OUT fan. In case the OUT temperature rises above this 2 degrees limit turn the fan OFF.
    b) if the GWC temperature is lower then CEL by 2 degrees turn ON GWC fan. In case the GWC temperature rises above this 2 degrees limit turn the fan OFF.

  3. At any time if the temperature in CEL drops below 12C turn the fas OFF

  4. In case both air ways temps are OK to be turned on, the preference is for OUT

  5. At any give time only one fan should be ON

As my adventure with HA is just beginning I believe there is nice ans elegant way to write ideally one automation to cover my case. At this point I was thinking about several automations for each “simple” case but I am not sure if they will not interfere with each other.
Any help or suggestion will be appreciated.
Technically I have NodeMCU with 3 temp sensors and 2 relay board connected.

in this case I’d advise to start with something simple as you won’t be able to tweak a code written to you by someone else.

I wouldn’t be so optimistic, HA hasn’t won any beauty awards afaik :wink:
And your main goal is to get a working solution so focus on it.

think about your system and implement your idea. try it and see how it works.
ask for help here if you have any issues while doing that.

so my suggestion is to formalise your task and start implementing it, that’s all I can say without a code.

Thanks. Well, maybe I was too modest re my experience and understanding of coding… :wink:
Anyhow, here is what I have so far - 4 separate automations:

  1. Turn ON OUT fan
alias: Turn ON OUT fan
  description: ''
  trigger:
  - above: '12'
    entity_id: sensor.cel
    platform: numeric_state
  condition:
  - condition: template
    value_template: '{{ float(states(''sensor.cel'')) - float(states(''sensor.out''))
      > 2}}'
  action:
  - data: {}
    entity_id: switch.out
    service: switch.turn_on
  1. Turn OFF OUT fan
alias: Turn OFF OUT fan
  description: ''
  trigger:
  - below: '12'
    entity_id: sensor.cel
    platform: numeric_state
  - platform: template
    value_template: '{{ float(states(''sensor.cel'')) - float(states(''sensor.out''))
      < 2}}'
  condition: []
  action:
  - data: {}
    entity_id: switch.out
    service: switch.turn_off
  1. Turn ON GWC fan
alias: Turn ON GWC
  description: ''
  trigger:
  - above: '12'
    entity_id: sensor.cel
    platform: numeric_state
  condition:
  - condition: template
    value_template: '{{ float(states(''sensor.cel'')) - float(states(''sensor.out''))
      < 2}}'
  action:
  - data: {}
    entity_id: switch.gwc
    service: switch.turn_on
  1. Turn OFF GWC fan
alias: Turn OFF GWC fan
  description: ''
  trigger:
  - below: '12'
    entity_id: sensor.cel
    platform: numeric_state
  condition: []
  action:
  - device_id: 4cd24fa8683b4a8faed84702020ec386
    domain: switch
    entity_id: switch.gwc
    type: turn_off

Will observe how this works and tweak :slight_smile:

cool.
I’d advise you to take a look at the docs to make sure your config is following the requirements (just noticed that you quote values of above/below)

Looks like you’re using Automation editor… you can make your automations shorter and learn faster/more if you do it manually (but it’s absolutely fine if you like it) :wink:

Yes, I am using Automation editor to start with and then I am editing the file sometime checking with editor how it looks and if it is OK.
Also template editor in Developer tools is very helpful.
Qute values are coming from the editor. Is it wrong ?

My dream and target is to create ONE automation for this purpose. :slight_smile:

it seems like you don’t need to quote values for above and below but if it works, don’t bother.

could you explain why is it your dream?

UPDATE: actually, looking at your automations I can see some reasons. Well, if the separate automations work as expected, we’ll look into it.
Could you tell me why #3 and #4 use different ways to change state of the switch, is it intentional?

I believe it will be easier to troubleshoot in case something is wrong. Also if one piece of “code” is controlling behaviour of one solution it is easier to change and adjust (as opposite I can make some change in one automation, like some treshold, and then not notice that the other one there is older treshold or it does not correspond to changes made in first one.

No, not intentional. When using Automation editor initially i have used “call service” for action and then I realised I can use “Device” as action type. Is there any suggestion which one would be better ?

ok, let’s have a lot at your description and the automations.
this

and this

is a bit controversial, could you clarify? no fans should be running if CEL <= 12C?

Yes. 12C is the target temperature I would like to have in my cellar.
So, as long as it is below 12C (it may happen in the strong winter as the room does not have any heating) I do not need to cool it down - so do nothing.
The second quote you have made refers to the same target and I wanted to explain that while any of the fan is working and temperature drops below 12C then any fan (OUT and GWC( should be off as the target has been reached.

So here’s how I see it now:
Let’s talk temperature sensors and switches for clarity.

Is it correct to say that to decide what to do we need to observe the following rules:
0. if CEL <= 12, turn off both switch.out and switch.gwc

else:

  1. turn_OUT_on = (OUT+2) < CEL < (OUT-2)
  2. turn_GWC_on = (GWC+2) < CEL < (GWC-2)
  3. if turn_OUT_on is True, turn on switch.out and turn off switch.gwc
    else if turn_GWC_on is True, turn on switch.gwc and turn off switch.out
    else turn off both switch.out and switch.gwc

Does it sound correct?

Thanks.
rule 0 confirmed.
The rest I would write slightly different:

    1. turn_OUT_on = (OUT+2) < CEL
    2. turn_GWC_on = (GWC+2) < CEL 
    3. if turn_OUT_on is True,
          turn on switch.out and turn off switch.gwc
       else if turn_GWC_on is True
          turn on switch.gwc and turn off switch.out
      else
          turn off both switch.out and switch.gwc

Does this make sense ?

you just removed CEL < (OUT-2) and CEL < (GWC-2).
I don’t mind, but it was by your initial request, isn’t it?

Sorry, it seems I was not clear enough. My assumption

was related to the same condition. If OUT temperature is lower then CEL by 2 degrees turn the OUT fan ON. In case it is not lower (in my words: OUT temperature rises above this 2 degree limit) then turn the OUT fan off.
The same goes for GWC temperature and fan.
The idea is that fan should not pomp the air inside the cellar if the temperature outside (or in ground system) is higher then CEL temp - 2 degrees, as in that case cellar is not chilled any more.

Ok, now we’re clear with the algo and can discuss a code.
Are you ready to produce it now or need some help/hints?

From what I see it won’t be the most elegant automation at least because Jinja’s variables are limited by boundaries of a template and you’ll need at least 2 (to control both switches).
And you’ll probably need 2 automations - one for rule 0 and another for the rest (but I’m not sure without the actual code).

I think I would like to get some help/hints.
I have used/copied this one for controlling light:

alias: AUTO - lights
  trigger:
  - entity_id: binary_sensor.pir1_gospodarczy
    platform: state
    to: 'on'
  - entity_id: binary_sensor.pir1_gospodarczy
    for: 0:00:12
    platform: state
    to: 'off'
  action:
 entity_id: switch.swiatlo_gospodarczy
   service_template: |-
  {% if trigger.to_state.state == "on" %}
    homeassistant.turn_on
  {% elif trigger.to_state.state == "off" %}
    homeassistant.turn_off
  {% endif %} 

and I like it as it is one for turning the lights on and off and also have this nice feature that the light is ON for defined time after sensor has stopped detecting movement.

that’s all good and stuff but you have 2 switches, remember? :wink:
so it won’t be as elegant as this one.
have you tried modifying it yet?

Yeah… it is more challenging.
No, I have not tried to modify this.

Ok, try this and let me know how it goes.

- alias: elegant_automation
  trigger:
    platform: template
    value_template: >
      {% set normal_temp = 12 %}
      {% set delta = 2 %}
      {% set invalid_states = ['unknown', 'unavailable'] %}
      {% set cmd_out = 'off' %}
      {% set cmd_gwc = 'off' %}

      {% set temp_cel = states('sensor.cel') %}
      {% if temp_cel not in invalid_states and temp_cel|float > normal_temp %}
        {% set temp_out = states('sensor.out') %}
        {% set temp_gwc = states('sensor.gwc') %}

        {% if temp_out not in invalid_states and (temp_out|float + delta) < temp_cel|float %}
          {% set cmd_out = 'on' %}
        {% elif temp_gwc not in invalid_states and (temp_gwc|float + delta) < temp_cel|float %}
          {% set cmd_gwc = 'on' %}
        {% endif %}
      {% endif %}

      {{ states('switch.out') != cmd_out or states('switch.gwc') != cmd_gwc }}

  action:
    - service_template: >-
        switch.turn_
        {%- set normal_temp = 12 -%}
        {%- set delta = 2 -%}
        {%- set invalid_states = ['unknown', 'unavailable'] -%}
        {%- set cmd_out = 'off' -%}

        {%- set temp_cel = states('sensor.cel') -%}
        {%- if temp_cel not in invalid_states and temp_cel|float > normal_temp -%}
          {%- set temp_out = states('sensor.out') -%}

          {%- if temp_out not in invalid_states and (temp_out|float + delta) < temp_cel|float -%}
            {%- set cmd_out = 'on' -%}
          {%- endif -%}
        {%- endif -%}
        {{ cmd_out }}

      data:
        entity_id: switch.out

    - service_template: >-
        switch.turn_
        {%- set normal_temp = 12 -%}
        {%- set delta = 2 -%}
        {%- set invalid_states = ['unknown', 'unavailable'] -%}
        {%- set cmd_gwc = 'off' -%}

        {%- set temp_cel = states('sensor.cel') -%}
        {%- if temp_cel not in invalid_states and temp_cel|float > normal_temp -%}
          {%- set temp_out = states('sensor.out') -%}
          {%- set temp_gwc = states('sensor.gwc') -%}

          {%- if temp_out not in invalid_states and (temp_out|float + delta) < temp_cel|float -%}
          {%- elif temp_gwc not in invalid_states and (temp_gwc|float + delta) < temp_cel|float -%}
            {%- set cmd_gwc = 'on' -%}
          {%- endif -%}
        {%- endif -%}
        {{ cmd_gwc }}

      data:
        entity_id: switch.gwc

As I said, it’s not always the best idea to put everything in one automation, especially using Jinja.

2 Likes

OK. Great ! Had a time now to put it into automations file. Will see now, how it works.
Thank your for your help - it is for me also great learning as I love to do it on practical, live examples. Let ask few questions as the learning concerns:

  1. I “{%” string indicating that now we are entering a programming area (in python ?) ?
  2. What is the difference between {% , {%- and {{ ? I have tried to find it in google with little success. Maybe you can point me to good reference ?
  3. Can this be written the way that {% is at the beginning of first line and then at the end of last line, instead of the beginning and end of each line ?
  1. nope, it’s Jinja template
  2. no need to go so deep now. it just converts newlines/whitespaces into one whitespace or so (-). {% and {{ - read the link above
  3. no, each statement need its own one.

as I said, it won’t be elegant.
for more elegant stuff you can try python_script, but it’s not a proper python as well so… :\