ESPHome conditonal config parts (yaml templating engine)

Hey there,

TL;DR; Is it possible to use substitutions for conditional yaml content selection?

Long: I’m almost certain the feature I am looking for does not exist. Am I correct and if so, does anyone have a suggestion for a nice workaround?

This is a minimum example of a config to illustrate the use case, this won’t compile! The example plays with a pin setting but my actual use case is a bit more reasonable :slight_smile:

substitutions:
  number: 0

esphome:
  name: my-device-${number}
  platform: ESP8266
  board: d1_mini

sensor:
  - platform: dht
{% if ${number} == 1 %}  # Not working code for illustration only
    pin: GPIO4
{% elif ${number} == 2 %}
    pin: GPIO5
    update_interval: 60s
{% else %}
    pin: GPIO1
{% endif %}

Is something like this possible? Did anyone successfully combine esphome with a yaml templating engine (like ytt) to achieve this? Feels like something like it must be a regularly needed function.

Thanks!

1 Like

Sure you can, but you’ll need C++ code, something like this:

    - lambda: |
        if (${number} == 0) return 'pin: GPIO4'; 
        else if (${number} == 100) return 'pin: GPIO5';
        else return (${number});

Are you sure you are not mistaken? If you can refer to any documentation, that would be great!

I’m 100% sure that you are using wrong code in ESPhome. I’m not so sure of the code that I have written, since this is my hobby. Yet reference:

Maybe you can provide a real example, so we can try it.

Here is one from my config:

    on_value_range:
      - above: 90.1
        then: 
          - mqtt.publish_json:
              topic: owntracks/centkom/${device_name}
              retain: true
              qos: 0
              payload: |-
                  root["_type"] = "location";
                  root["lat"] = to_string(id(lat).raw_state);
                  root["lon"] = to_string(id(lon).raw_state);
                  root["tid"] = "${device_name}";
                  root["tst"] = id(gpstime).now().timestamp;
                  root["t"] = "s";

So I presume that I can insert substitution in lambda wherever possible.

So yeah, you are looking at lambdas, which is a feature of ESPHome to programmatically populate fields with dynamic content. My aim is to dynamically define fields (with fixed content). Check my example again. That is a completely different element of the puzzle.

If ESPHome doesn’t bring a template engine for this right out of the box, which I find most strange, I might go with ytt for my use case.

For the sake of others I will post my solution here as I progress in testing this!

ESPHome maintainers reading along: Any plans to integrate a templating engine in the esphome toolchain?

Edit: Similar discussion for reference: [Huge] [Suggestion / Feature Request] Configuration Templating · Issue #67 · esphome/esphome · GitHub

1 Like

Coming back to this topic.

I am convinced that ESPHome does currently not offer a solution for more complex templating in configuration files for the purpose of more complex configuration differences between similar devices.

@OttoWinter would you be interested to discuss this? Happy to reopen a GitHub ticket.

I recently ran into two tools which offer interesting features to cater for this use case. It would be amazing if the ESPHome toolchain supported one. I did not yet have the time to explore these and potentially better suited tools yet.

It is possible to use the c-preprocessor (CPP) as a macro preprocessor to configure and build multiple variants from the same esphome yaml sources via CPP’s #define and #if ... #endif directives. This approach also enables C/C++ .h files containing only CPP directives such as #defines to be include into yaml files. And it enables block comments via /* ... */ or #if 0 ... #endif.

The example project espmake can be leveraged to see one way this can be done while still allowing hash-style comments in yaml files.

1 Like