Loop through a comma delimited list

I’m glad it helped. I’m not sure I’d use it without some additional input checking because a poorly typed text input on HA could crash the whole thing, so just keep that in mind. But like I said, I’m glad I was able to help.

UPDATE: I simplified the incomplete code I originally posted here. I realized that I could just write put a function in the include file and skip all of the class stuff the examples lead to believe you need. I use update_next_runtime() to update the template text_sensors.

Next I need to add some code to populate the next scheduled time at load time. Well, and every time the list of times changes.

irrigation.h

#include "esphome.h"

std::string update_next_runtime(std::string time_list) {
  // Initialize variables.
  std::vector<std::string> times;
  char * token;
  token = strtok(&time_list[0], ",");

  // Split the list of run times into an array.
  while (token != NULL) {
    times.push_back(token);
    token = strtok(NULL, ",");
  }

  // Retrieve the current time.
  auto time_now = id(homeassistant_time).now();
  int time_hour = time_now.hour;
  //int time_minute = time_now.minute;

  // Initialize variables.
  std::vector<std::string> next_time;
  int next_hour = 0;
  //int next_minute = 0;
  int index = 0;
  int loop_count = 0;
  int time_count = times.size()-1;

  // Compare the list of times with the current time, and return the next in the list.
  //ESP_LOGD("IrrigationNextRuntime", "now: %i:%i", hour, minute);
  for (std::string time : times) {
    // Split the hour and minutes.
    token = strtok(&time[0], ":");
    while (token != NULL) {
      next_time.push_back(token);
      token = strtok(NULL, ":");
    }

    // Retrieve the next hour from the list.
    next_hour = std::atoi(next_time[index].c_str());
    //next_minute = std::atoi(next_time[index+1].c_str());

    //ESP_LOGD("IrrigationNextRuntime", "next_hour: %s", time.c_str());
    if (time_hour < next_hour) {
      // Return this time if the next hour is greater than the current hour.
      return time.c_str();
      break;
    }

    // When we reach the end of our schedule for the day, return the first time of tomorrow.
    //ESP_LOGD("IrrigationNextRuntime", "loop_count: %i, time_count: %i", loop_count, time_count);
    if (time_count == loop_count) {
      //return next_time[0].c_str() + std::string(":") + next_time[1].c_str();
      return times[0].c_str();
      break;
    }

    // Increment the loop counter and array index.
    loop_count += 1;
    index += 2;
  }

  return "unknown";
}

irrigation.yaml: esphome include irrigation.h

esphome:
  name: $id
  platform: ESP8266
  board: esp01_1m
  includes:
    - irrigation.h

irrigation.yaml: text_sensor templates

text_sensor:
  - platform: template
    name: Zone1 Next Scheduled
    id: irrigation_zone1_next
  - platform: template
    name: Zone2 Next Scheduled
    id: irrigation_zone2_next
  - platform: template
    name: Zone3 Next Scheduled
    id: irrigation_zone3_next

irrigation.yaml: relay off > update next scheduled

switch:
  # Example is simplified to only show relevant text_sensor.template.publish:
  - platform: gpio
    id: relay1
    pin: $relay1_gpio
    on_turn_off:
      # Update the next scheduled run time.
      - text_sensor.template.publish:
          id: irrigation_zone1_next
          state: !lambda |-
            return update_next_runtime(id(ui_zone1_times).state);

Here the UI I have come up with to control this remotely. It needs some polish, but it works great! I can manually start a watering cycle, that ends when the set duration expires, and I can set the scheduled times.

For now I am ignoring the minutes. I am just going to have the times trigger on the hour.

I just published an article on my site talking about my Irrigation Controller project, in case you are interested. There are definitely improvements to be made… but it has been running rock solid since I plugged it in 145 hours ago! So, I intend to leave it alone for now. :smiley:

1 Like

Hey Brian good job on the project. Is this still running? Thanks.

Yes! This controller has been rock solid, 100% reliable, unlike my previous Melnor battery powered device.