Nested 'if' conditions in ESPhome action?

Similar here Tony, I like to have local fallback logic in some of my devices.
I’d prefer to have ESPhome convert degrees to cardials too (and print text to the 16x2 LCD), but if it’s not a convoluted twisted series of scripts and the like I’d be happy to use HA to start with…

I also take the stance that each device should be as self contained as possible. Home assistant should be the glue and handle inter device automation. But in this case I think it is a matter of taste, since it is purely a display issue. For automations that occur entirely within the device, there is a strong argument for keeping the logic self contained.

Given the new piece of info, I would softly suggest doing it in esphome if the LCD is also on this device. Then it will still display if, who am I kidding, when your home assistant server is down while you are fixing some breaking change issue.

This is the device. It’s effectively a weather station repeater display that sits on the wall in my bedroom, but it evolved to have a RGB HA system status LED and local temp/humidity sensor tacked on…

As I had no luck with the ESPhome compile errors I took your advice.

Here’s the solution:

- platform: template
  sensors:
    wind_direction:
      friendly_name: 'Wind direction'
      value_template: >-
        {% if states('sensor.wind_direction_north') | float >= 0.00 and states('sensor.wind_direction_north') | float <= 0.08 %}
          N
        {% elif states('sensor.wind_direction_north') | float >= 0.08 and states('sensor.wind_direction_north') | float <= 0.16 %}
          NE
        {% elif states('sensor.wind_direction_north') | float >= 0.16 and states('sensor.wind_direction_north') | float <= 0.24 %}
          E
        {% elif states('sensor.wind_direction_north') | float >= 0.24 and states('sensor.wind_direction_north') | float <= 0.32 %}
          SE
        {% elif states('sensor.wind_direction_north') | float >= 0.32 and states('sensor.wind_direction_north') | float <= 0.40 %}
          S
        {% elif states('sensor.wind_direction_north') | float >= 0.40 and states('sensor.wind_direction_north') | float <= 0.48 %}
          SW
        {% elif states('sensor.wind_direction_north') | float >= 0.48 and states('sensor.wind_direction_north') | float <= 0.56 %}
          W
        {% elif states('sensor.wind_direction_north') | float >= 0.56 and states('sensor.wind_direction_north') | float <= 0.64 %}
          NW
        {% endif %}
1 Like

Does that work ? you have overlaps. If the float is 0.08 it can be N or NE, need to make either the >= to just > or <= to just <, except the last one

- platform: template
  sensors:
    wind_direction:
      friendly_name: 'Wind direction'
      value_template: >-
        {% if states('sensor.wind_direction_north') | float >= 0.00 and states('sensor.wind_direction_north') | float < 0.08 %}
          N
        {% elif states('sensor.wind_direction_north') | float >= 0.08 and states('sensor.wind_direction_north') | float < 0.16 %}
          NE
        {% elif states('sensor.wind_direction_north') | float >= 0.16 and states('sensor.wind_direction_north') | float < 0.24 %}
          E
        {% elif states('sensor.wind_direction_north') | float >= 0.24 and states('sensor.wind_direction_north') | float < 0.32 %}
          SE
        {% elif states('sensor.wind_direction_north') | float >= 0.32 and states('sensor.wind_direction_north') | float < 0.40 %}
          S
        {% elif states('sensor.wind_direction_north') | float >= 0.40 and states('sensor.wind_direction_north') | float < 0.48 %}
          SW
        {% elif states('sensor.wind_direction_north') | float >= 0.48 and states('sensor.wind_direction_north') | float < 0.56 %}
          W
        {% elif states('sensor.wind_direction_north') | float >= 0.56 and states('sensor.wind_direction_north') | float <= 0.64 %}
          NW
        {% endif %}

Yes, it works, but not very clean like that and you are correct. I’ve changed it. That’s copy/paste for you!

The esphome code should be in the form

lambda: |-
  if (expression){statement}
  else if (expression){statement}
  else {statement}

Exactly like the example. I think it might only be valid code without the !lambda

1 Like

It compiles ok for me, with or without. It’s the missing brackets and extra semi colon that would have made it fail.

2 Likes

I got the Lambda to compile fine (after a full hour of debugging syntax) and display on the LCD the text wind direction, converted inside ESPhome.
Values come from the internal wind direction sensor (which in turn comes from HA via WU). North required two ‘if’ conditions to handle wrapping past 0 degrees.
Just did four cardinal points for a test, now need to expand the else if’s to a full sixteen…
Any suggestions to streamline it welcome.

text_sensor:
  - platform: template
    id: internal_winddir_conversion
    lambda: |-
      if ((id(wupws_wind_dir).state >= 0) and (id(wupws_wind_dir).state <= 11)) {
        return {"North"};}
      else if ((id(wupws_wind_dir).state >= 12) and (id(wupws_wind_dir).state <= 33)) {
        return {"N-N-E"};}
      else if ((id(wupws_wind_dir).state >= 34) and (id(wupws_wind_dir).state <= 56)) {
        return {"N-E"};}
      else if ((id(wupws_wind_dir).state >= 57) and (id(wupws_wind_dir).state <= 78)) {
        return {"E-N-E"};}
      else if ((id(wupws_wind_dir).state >= 79) and (id(wupws_wind_dir).state <= 101)) {
        return {"East"};}
      else if ((id(wupws_wind_dir).state >= 102) and (id(wupws_wind_dir).state <= 123)) {
        return {"E-S-E"};}
      else if ((id(wupws_wind_dir).state >= 124) and (id(wupws_wind_dir).state <= 146)) {
        return {"S-E"};}
      else if ((id(wupws_wind_dir).state >= 147) and (id(wupws_wind_dir).state <= 168)) {
        return {"S-S-E"};}
      else if ((id(wupws_wind_dir).state >= 169) and (id(wupws_wind_dir).state <= 191)) {
        return {"South"};}
      else if ((id(wupws_wind_dir).state >= 192) and (id(wupws_wind_dir).state <= 213)) {
        return {"S-S-W"};}
      else if ((id(wupws_wind_dir).state >= 214) and (id(wupws_wind_dir).state <= 236)) {
        return {"S-W"};}
      else if ((id(wupws_wind_dir).state >= 237) and (id(wupws_wind_dir).state <= 258)) {
        return {"W-S-W"};}
      else if ((id(wupws_wind_dir).state >= 259) and (id(wupws_wind_dir).state <= 281)) {
        return {"West"};}
      else if ((id(wupws_wind_dir).state >= 282) and (id(wupws_wind_dir).state <= 303)) {
        return {"W-N-W"};}
      else if ((id(wupws_wind_dir).state >= 304) and (id(wupws_wind_dir).state <= 326)) {
        return {"N-W"};}
      else if ((id(wupws_wind_dir).state >= 327) and (id(wupws_wind_dir).state <= 348)) {
        return {"N-N-W"};}
      else if ((id(wupws_wind_dir).state >= 349) and (id(wupws_wind_dir).state <= 359)) {
        return {"North"};}
      else {
        return {"invalid"};}
    update_interval: 30s

The particular internal sensor (of many)

  - platform: homeassistant
    id: wupws_wind_dir
    name: "Wind direction via WU-WH2900"
    entity_id: sensor.wupws_winddir
    internal: true 

The LCD display code (just that line).

        it.printf(0, 0, "Wind: %s", id(internal_winddir_conversion).state.c_str());
5 Likes

Glad its working, why are there some with and some without else ?

Yep that was an error, caused by my cut & pasting. Fixed it, still works fine…

You could replace both North if with:

      if ((id(wupws_wind_dir).state >= 0) and (id(wupws_wind_dir).state <= 11)) or 
         ((id(wupws_wind_dir).state >= 349) and (id(wupws_wind_dir).state <= 359)) {
        return {"North"};}

I also look at ESPHome devices as compartmentalized, meaning that if I need to translate the values from a connected device into human consumable values then I do so on the ESPHome device.

I want the device to look more like what it is supporting than have to glue things together on the Home Assistant side.

It’s also very hard for me get out of the habit of moving processing to the edge. So many years of performance optimizing large scaled services. :slight_smile:

Cheers :+1:

hi,
i am trying to have two conditions for a sensor value below 1 . First program to check first condition and take action and then check other condition and take action. Irrespective of first condition result and action program must check the second condition and take action.

I am getting this error while compiling.
error

my code below.

  sensor:
  - platform: adc
      pin: A0
      name: "intercom_adc_value"
      #      unit_of_measurement: 'v'
      update_interval: 100ms
      filters:
      - multiply: 3.3
      on_value_range:
        - above: 3
          then:
            - switch.turn_off: intercom_local_alerts
            - switch.turn_off: intercom_remote_alerts
        - below: 1.0
          then:
            if:
              condition:
                - switch.is_on: intercom_local_alerts_enable_disable
              then:
                - switch.turn_on: intercom_local_alerts
            if:
              condition:
                - switch.is_on: intercom_remote_alerts_enable_disable
              then:
                - switch.turn_on: intercom_remote_alerts

hi Usman, I just saw your post, did you manage to get it running in the time between then and now.

I am by no means a programmer or esphome wizard but i did manage to get a temperature sensor to do different actions on different values. Maybe it will help you or somebody else along. btw i did use substitutions for most values and id’s so i can quickly multiply and only have to change names in the top bit of the yaml.

# Temperature sensor, met temperatuur activatie?
  - platform: dallas
    address: $dallas_id_1
    name: "$temp_id"
    accuracy_decimals: 1
    id: $temp_id
    on_value:
      then:
          - if:
                condition:
                    and:
                      - lambda: return id($temp_id).state < $cold_temp;
                      - binary_sensor.is_on: esphome_fans_on_off
                then:
                  - fan.turn_on:
                      id: $fan_id
                      speed: 15
          - if:
                condition:
                    and:
                      - lambda: return id($temp_id).state > $cold_temp;
                      - lambda: return id($temp_id).state < $low_temp;
                      - binary_sensor.is_on: esphome_fans_on_off
                then:
                  - fan.turn_off:
                      id: $fan_id
          - if:
                condition:
                    and:
                      - lambda: return id($temp_id).state > $low_temp;
                      - lambda: return id($temp_id).state < $medium_temp;
                      - binary_sensor.is_on: esphome_fans_on_off
                then:
                  - fan.turn_on:
                      id: $fan_id
                      speed: 44
          - if:
                condition:
                    and:
                      - lambda: return id($temp_id).state < $high_temp;
                      - lambda: return id($temp_id).state > $medium_temp;
                      - binary_sensor.is_on: esphome_fans_on_off
                then:
                - fan.turn_on:
                    id: $fan_id
                    speed: 50
          - if:
                condition:
                    and:
                    - lambda: return id($temp_id).state > $high_temp;
                    - binary_sensor.is_on: esphome_fans_on_off
                then:
                - fan.turn_on:
                    id: $fan_id
                    speed: 80

Back to the original question, is it possible to write nested if statements in YAML?

My use case is a service to water plants, where I want also to check if the pump is actually working:

  services:
    - service: water_plants
      then:
        if:
          condition:
            and:
              - binary_sensor.is_off: esp32_garden_sensor_empty # tank empty sensor
              - sensor.in_range:
                  id: ep32_garden_daily_flow # flow sensor (integration)
                  below: 4.0
          then:
            - switch.turn_on: esp32_garden_relay1 # pump supply
            - delay: 10s
                if:
                  condition:
                    - sensor.in_range:
                      id: ep32_garden_flow_rate # instant flow sensor
                      below: 0.2
                  then:
                    - switch.turn_off: esp32_garden_relay1
                    - homeassistant.service:
                        service: notify.mobile_app
                        data:
                        message: 'The pump is not pumping!'
            - delay: 300s # time to water plants
            - switch.turn_off: esp32_garden_relay1 # stop watering

This would be straightforward in C/C++ or any other languages, but I’m trying to stick to YAML as the whole house is automated with esphome & YAML.
I know I could do that with lambdas, but I would prefer to keep everything in YAML.

It looks like I just had to fix lists and indentations, this is working:

services:
  - service: water_plants
    then:
      if:
        condition:
          and:
            - binary_sensor.is_off: esp32_garden_sensor_empty # tank empty sensor
            - sensor.in_range:
                id: ep32_garden_daily_flow # flow sensor (integration)
                below: 4.0
        then:
          - switch.turn_on: esp32_garden_relay1 # pump supply
          - delay: 10s
          - if:
              condition:
                - sensor.in_range:
                    id: ep32_garden_flow_rate # instant flow sensor
                    below: 0.2
              then:
                - switch.turn_off: esp32_garden_relay1
                - homeassistant.service:
                    service: notify.mobile_app
                    data:
                      message: 'The pump is not pumping!'
          - delay: 300s # time to water plants
          - switch.turn_off: esp32_garden_relay1 # stop watering
2 Likes

Someone has opened an issue about this: Switch Case Algorithm · Issue #824 · esphome/feature-requests · GitHub

Maybe you all want to join and therefore show the developers that this feature is a interesting one?

1 Like