Loop through a comma delimited list

I need to parse a comma delimited list in ESPHome. Ideally I need to loop through the list to evaluate each item. Specifically I have a list of times stored in a text sensor 09:00,12:00,15:00.

I suspect I need to use lambda code to split the list into something I can loop over. Is lambda arduino code? I’m having a heck of a time searching for code examples.

As I understand it, lambdas are C++. Check this out: https://esphome.io/guides/automations.html#templates-lambdas

1 Like

Indeed they are c++

1 Like

So, I found several c++ examples for splitting a comma separated list, and I’m struggling. Essentially, I need to compare each time in the list and select the next time for an irrigation controller. No matter what example I use I get errors. Here’s an example of what code I am trying.

script:
  - id: event_end
    then:
      - text_sensor.template.publish:
          id: irrigation_zone1_next
          state: !lambda |-
            // string str = id(ui_zone1_times).state.c_str();
            string str = "09:00,12:00,13:00";
            vector<string> v;
            stringstream ss(str);
            while (ss.good()) {
                string substr;
                getline(ss, substr, ',');
                v.push_back(substr);
            }
            for (size_t i = 0; i < v.size(); i++) {
                ESP_LOGD("test: ", "%s", v[i];
            }
            return v;

I cannot find script: even documented on the esphome.io site. I may be blind though.

https://esphome.io/guides/automations.html?highlight=script#script-execute-action

I’ve used it before, it can be handy.

Thanks. I searched on the site. It found that page, but in the search results the word description was highlighted so I looked no further.

1 Like

I know I can save the headache and handle the automation in Home Assistant… but this is an Irrigation controller. So going offline could mean dead plants, or a dead pool pump (because it keeps the water topped off).

I’m using Home Assistant to edit the start times and duration. I assumed a comma separated list in an input_text box would be simple enough to parse.

OK, back on topic, what error are you getting. My c++ is not great, so I am not sure what you are even trying to do.

Maybe there is another way to solve the problem?

Does all this have to be done on the esp? It may be easier in home assistant?

EDIT: your last post probably answered the last part of my question :slight_smile:

I appreciate the effort.

src/main.cpp: In lambda function:
src/main.cpp:1319:7: error: 'string' was not declared in this scope
       string str = "09:00,12:00,15:00";
       ^
src/main.cpp:1319:7: note: suggested alternative:
In file included from /root/.platformio/packages/toolchain-xtensa/xtensa-lx106-elf/include/c++/4.8.2/string:39:0,
                 from src/esphome/core/component.h:3,
                 from src/esphome/components/api/api_connection.h:3,
                 from src/esphome.h:2,
                 from src/main.cpp:3:
/root/.platformio/packages/toolchain-xtensa/xtensa-lx106-elf/include/c++/4.8.2/bits/stringfwd.h:62:33: note:   'std::string'
   typedef basic_string<char>    string;   
                                 ^

How about working out how many times in total you might want a start time plus duration per day. Say 5?

Use 10 homeassistant text sensors, start_time_1 to start_time_5 and duration_1 to duration_5.

Set these text sensors from the input_text by parsing, then let esp device to read those homeassistabt sensors each morning. Worst that can happen, if contact between esp and HA is down is that the same happens as yesterday.

Or something like that.

Looks like you may need an include to bring in the .h file that provides string.

Maybe instead of trying to split up a comma separated string, why don’t you just make it an array or list?

Yeah. If c++ proves too difficult I may have to go that route. Its just, every other language I have ever used has some kind of simple split() function. It seemed like such a simple workaround, and that would hopefully use less memory.

Hi Jared. I am using an input_text field in lovelace to populate a text_sensor in ESPHome. I was hoping to turn that comma separated list into an array, or similar data. I’m open to suggestions though.

Maybe you were suggesting hard-coding the list… hmm. Yeah, if I have to. I just find that I am much more likely to tweak the values when necessary if I have a quick UI available. I recently created a screen full of weekly event reminders like this, and I love it.

yes. I was suggesting hard coding it in an array, but now I understand what you mean. So back to your code above, double check that you are using std::string rather than just string or maybe throw in a using namespace std. See if that makes a difference. Aside from that, I’m not sure you can use stringstream on ESP32, but I could be wrong.

Here’s it working with an array:

sensor:
  - platform: template
    name: testing_test
    id: test_1
    lambda: |-
      std::string strArray[3] = { "09:00", "12:00", "13:00" };
      for ( std::string s : strArray ) {
          ESP_LOGD("test: ", "Array to string: %s", s.c_str());
      }
      return 1;

Which produces this output:

[03:08:50][D][test: :182]: Array to string: 09:00
[03:08:50][D][test: :182]: Array to string: 12:00
[03:08:50][D][test: :182]: Array to string: 13:00
[03:08:50][D][sensor:092]: 'testing_test': Sending state 1.00000  with 1 decimals of accuracy

Second Edit:
I think this does what you want.

text_sensor:
  - platform: homeassistant
    name: "hatext"
    entity_id: input_text.text1
    id: hatext

  - platform: template
    name: testing_test2
    id: test_2
    update_interval: 10s
    lambda: |-
      std::string str = id(hatext).state;
      std::vector<std::string> v;
      char * token;
      char seps[] = ",";
      token = strtok (&str[0],seps);
      while (token != NULL)
      {
        v.push_back(token);
        token = strtok (NULL, seps);
      }
      for ( std::string s : v ) {
          ESP_LOGD("test: ", "String to Vector: %s", s.c_str());
      }
      return 1;

Which outputs:

[04:14:18][D][text_sensor:015]: 'hatext': Sending state '09:00,12:00,13:00'
[04:14:20][D][test: :204]: String to Vector: 09:00
[04:14:20][D][test: :204]: String to Vector: 12:00
[04:14:20][D][test: :204]: String to Vector: 13:00
[04:14:20][D][sensor:092]: 'testing_test2': Sending state 1.00000  with 1 decimals of accuracy
[04:14:25][D][homeassistant.text_sensor:016]: 'input_text.text1': Got state '09:00,12:00,15:00'
[04:14:25][D][text_sensor:015]: 'hatext': Sending state '09:00,12:00,15:00'
[04:14:30][D][test: :204]: String to Vector: 09:00
[04:14:30][D][test: :204]: String to Vector: 12:00
[04:14:30][D][test: :204]: String to Vector: 15:00
[04:14:30][D][sensor:092]: 'testing_test2': Sending state 1.00000  with 1 decimals of accuracy
2 Likes

I love pushing the edges of my understanding of programming! This gives me the start I needed. Thank you! I will update you on my progress.

[08:42:09][D][test: :1299]: String to Vector: 09:00
[08:42:09][D][test: :1299]: String to Vector: 12:00
[08:42:09][D][test: :1299]: String to Vector: 15:00

P.S. Soo… an error I was getting last night was from another lambda. It was late, I don’t understand how it happened, but I noticed I had a return id(id(ui_zone1_times).state).state; in the below text_sensor clip. I wonder how long that was the real issue, and what other code I tried would have worked.

  # Retrieve list of times from the Home Assistant UI.
  - platform: homeassistant
    id: ui_zone1_times
    entity_id: input_text.irrigation_zone1_times
    on_value:
      then:
      - text_sensor.template.publish:
          id: irrigation_zone1_times
          state: !lambda "return id(ui_zone1_times).state;"

Off topic but can I just say that I love your check-box button idea.
I’ve already started to steal it for my config!

Thanks :wink:

1 Like

Thanks @klogg. Here is a link to my decluttering-card template.
https://github.com/brianhanifin/Home-Assistant-Config/blob/14a601551da269da9b50a0bbdc05ba9535df0484/lovelace/templates/ui_old/button_check.yaml#L1

Thanks, I’ve been playing with this idea a bit today and I’ll look at your template.
I’ve been trying to get the entity icon as well as the check-box but haven’t succeeded yet (I have a question on the button card post)

I’m not sure if I’m going to like it with both icons but we’ll see…

Whatever, your idea is so perfect I can’t believe I have not seen it done before.

Interestingly (as this is what your OP was about) I’m about to re-write my garden irrigation package and it will definitely see some use there!!

1 Like