ESPHome Sprinkler controller

@Fallingaway24 I have just found the divide function when I was mirroring my old (not “smart”) controller’s logic. To the ESP + HA based hybrid smart irrigation system.

The system is still under testing on my desk before I can put it into live to the garden. Be ready for reading about the whole project, if you are interested in. I’m so optimistic and excited, so far first test cases are good, but I would have to test the full matrix of monitored environmental conditions.
Basically I combined resources and samples from here and an interesting way of automation from HA.

That HA automation does use a fully weather condition driven schedule with no bound to a calendar based schedule at all.

@febalci:

Please think of an idea to split the roles and responsibilities between ESP32 (or ESP8266) and HA:

  • ESP relay board could be good for handling valves and take care of one single irrigation cycle.
  • HA would responsible to the smart logic: calculating optimal runtime to all zones, scheduling cycle starts, etc.

Once HA has decided it is time to irrigate, then HA can set runtime (even for each zones) then kicks in the watering cycle on ESP.
Once a watering cycle will be kicked in, the ESP will take care of managing everything related to the current cycle.

In HA you will have chance to more thing check (current temperature and maximum temperatures since last time watered, soil moisture level, time since last watering cycle, rain fallen recently, rain predicted in the near future, solar radiation.)

There is everything here allows you to build up an even better and more sophisticated watering system than the professionals have.
And obviously you can get it far more cheaper.

If you have a HA system running, your valves and pipes are still good and you can have a WiFi connection at the place of controller. (WiFi will also need for professional solutions)

2 Likes

I’m very interested in your project, especially the HA approach. I’ll be watching to see how you make out.

@rcblackwell Please check this out:

(Still had no time today for collect the code and share it)

I’d love to read about it. Mine is also heavily conditioned by time of year/season and previous/forcasted weather. I worked in the green industry a long 15+ years and a calendar based schedule is horrible and extremely wasteful. Another thing, I’m seeing a lot of people with evening watering schedules. There are only a few circumstances where an evening watering schedule is needed and people often think when its summer time and hot, they need to water in the evenings. That is factually wrong and it’s the worst time of the year to do evening watering. There is an exception though besides the fact that its generally not even necessary but people insist on playing with fire all I can say is make sure you do it with enough time left in the day for the water to dry off of the plants/leaves, don’t do it right before it gets dark.

Hi,

please help me to build automation because I cannot know how to do it.

I have esphome sprinkler controller system with 9 valves. One of these valves is a hose valve. The whole system and the integration as well work very well. I can control all valves from HA UI. Nice.

I have a physical button connected to a gpio port of the ESP32 board and a binary_sensor to this button. The status of the physical button is shown on the HA UI. I want to control the hose valve of the sprinkler controller with this button.

The ‘hose’ valve works from HA UI. But, I cannot call it from esphome script like a switch with the switch.turn_on process or with something like this. The problem is that the ‘hose’ valve is not a switch. So, I can not control it. Please share your idea or solution.

Thanks,

here is my stripped down code:

binary_sensor:
  - platform: gpio
    name: "Irrigation ESP32 Hose Button"
    id: "esp32_gpio_16"
    pin: GPIO16
    filters:
      - delayed_on: 100ms
	on_press:
		???????

sprinkler:
  - id: sprinkler_ctrlr
    main_switch:
      name: "Sprinklers main switch"
      id: sprinkler_ctrlr_main_switch_id
    auto_advance_switch: "Sprinklers Auto Advance"
    valves:
      - valve_switch: "Hose"
        enable_switch: "Enable Hose"
        run_duration: 300s
        pump_switch_id: irrigation_esp32_mcp23017_0x27_gpio_3_cistern_pump
        valve_switch_id: irrigation_esp32_mcp23017_0x27_gpio_5_hose_valve

switch:
  - platform: gpio
    name: "Irrigation Cistern Pump"
    id: "irrigation_esp32_mcp23017_0x27_gpio_3_cistern_pump"
    restore_mode: RESTORE_DEFAULT_OFF
    pin:
      mcp23xxx: mcp23017_0x27
      number: 2
      mode: OUTPUT
      inverted: True

  - platform: gpio
    name: "Irrigation Hose Valve"
    id: "irrigation_esp32_mcp23017_0x27_gpio_5_hose_valve"
    restore_mode: RESTORE_DEFAULT_OFF
    pin:
      mcp23xxx: mcp23017_0x27
      number: 4
      mode: OUTPUT
      inverted: True

Look at the documentation, there are tons of examples. On_press is for making a momentary switch, so if you use that the switch will turn back off as soon as you take your finger off the button.

Hi @Fallingaway24,

you are right. I know this behavior of the momentary switch. The problem and my question is not this.
The question is, how can I start a sprinkler valve switch in the esphome script. I know how can I start the auto circle with all enabled valves. I want to call a given valve_switch.

Thanks,

This is in the Sprinkler component documentation.

You’re question is kind of confusing. You mention not being able to control your “hose valve” because it’s not a switch but in your code, you clearly have a “hose valve” as a gpio switch so, it’s hard to figure out what you’re asking. If you want to toggle it from an esphome script, you need to make a script and I don’t see a script in your code. If you’re talking about just controlling a single valve at a time, that is what the enable switch is for. For each valve you will want to create an enable switch. This will allow you to disable valves in a full cycle, specify certain valves for a full cycle or control single valves independent of running a cycle, so if you wanted to turn on “zone1” and only zone 1, you would only activate the enable switch of zone1 and turn on the system.

I am trying to make a single-valve sprinkler controller to work on the same way as a multi-valve controller, but not getting closer.

I am just wondering, is it on purpose/intentional/by design that it is not possible to use " sprinkler.start_full_cycle" or " sprinkler.resume_or_start_full_cycle" actions when there is only a single valve under a controller?

Following up on this it also looks like adding a main_switch is not possible to a single valve controller, hence (is it a consequence?) the controller multiplier doesn’t work either (doesn’t even get exposed to HA).

As soon as I am adding a second valve to the controller config with a main_switch and auto_advance_switch (which seems mandatory for multi-valve controllers) the multiplier gets exposed immediately and the controllers starts behaving as expected.

However, I don’t need the second valve on that controller. Obviously I can have a dummy valve hanging around there as a workaround, but is this intentional for some reason or could that be a bug in esphome?

Hello @febalci Great job!

I’m trying to replicate your code in my 8-sector irrigation project, but I can’t get the ESP32 to return to the previous irrigation state when there’s a power outage. When it’s turned on, it doesn’t resume from where it left off, but rather starts the irrigation from the beginning. I copied your entire code without any modifications. Could it be because I’m using an ESP32 board?

Hi @joaopedros2 ,

maybe what i wrote was confusing; the code doesn’t save the state to resume where it was left off; my intention was to stop sprinklers when there is a power outage, and keep the valves closed when the power comes back on. Just save the run durations and and multiplier values and restore these values back when the power comes back on, so that it can continue the next cycle as i intended.

Btw, if i am not mistaken, i remember something like “esp8266_restore_from_flash : true” doesn’t work with ESP32 anyway.

1 Like

thank you for your answer. What can be done to resume irrigation in the event of a power failure?

Ideally I’d like Time Remaining and Progress % to update once per second but only when a sprinkler is active. I haven’t figured out how to do that yet.

Thanks for all the info and just if someone finds this thread, here is how I solved the challenge regarding the update_interval:

First set the “update_interval” of both sensors to a high number, e.g. 10000s (I haven’t tested “never”)

Then create a “binary_sensor template” in esphome

binary_sensor:
  - platform: template
    name: "${friendly_name} High Speed Update"
    id: high_speed_update
    on_state:
      - lambda: !lambda |-
          // This is to revert back to the default update interval when needed
          static uint32_t default_time_interval = id(time_remaining).get_update_interval();
          static uint32_t default_percent_interval = id(progress_percent).get_update_interval();

          // 1000 = 1 secs = New "high speed" interval
          int update_time_interval = x ? 1000 : default_time_interval;
          int update_percent_interval = x ? 1000 : default_percent_interval;

          id(time_remaining).set_update_interval(update_time_interval);
          id(progress_percent).set_update_interval(update_percent_interval);

          id(time_remaining).call_setup();
          id(progress_percent).call_setup();

You can also set the parameter “internal” to true to hide it from HA. I haven’t done that to easily see that it is working :slight_smile:

Finally, in the “on_turn_on” and on “on_turn_off” actions of the valves switch the binary_sensor:

switch:
  - platform: gpio
    pin: GPIO22
    id: relay01
    restore_mode: RESTORE_DEFAULT OFF
    on_turn_on:
      - binary_sensor.template.publish:
          id: high_speed_update
          state: ON
      - text_sensor.template.publish:
          id: valve_status
          state: "Drip Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
      - binary_sensor.template.publish:
          id: high_speed_update
          state: OFF

I found this piece of code in this post: Dynamically change update_interval - #10 by 0x3333 provided by @0x3333

1 Like

@derjoerg , thanks for the code snippit. I’ve added it to my code. Works great.

My sprinkler is super simple, a single relay as I have a small garden. I use the scheduler add on for timing.

For anyone wanting to use. Some lambda code taken from other posts and consolidated:

switch:
  - platform: gpio
    name: "Sprinkler Switch"
    id: sprinkler_switch
    pin: D1
    internal: True
    on_turn_off:
      then:
      - lambda: |-
          id(time_remaining) = 0;

sensor:
  - platform: homeassistant
    id: runtime_mins
    unit_of_measurement: "min"
    accuracy_decimals: 0
    entity_id: input_number.sprinkler_runtime 
    on_value:
      - sprinkler.set_valve_run_duration:
          id: garden_sprinkler_ctrlr
          valve_number: 0
          run_duration: !lambda "return x * 60;"

sprinkler:
  - id: garden_sprinkler_ctrlr
    valves:
      - valve_switch: "Garden Sprinkler"
        run_duration: 300s  # default max
        valve_switch_id: sprinkler_switch

text_sensor:
  - platform: template
    id: time_remaining
    name: "Time Remaining"
    update_interval: 5s
    icon: "mdi:timer-sand"
    filters:
      - lambda: |-
          static std::string last;
          if (x == last)
            return {};
          last = x;
          return x;
    lambda: !lambda |-
      int seconds = round(id(garden_sprinkler_ctrlr).time_remaining_active_valve().value_or(0));
        int days = seconds / (24 * 3600);
        seconds = seconds % (24 * 3600);
        int hours = seconds / 3600;
        seconds = seconds % 3600;
        int minutes = seconds /  60;
        seconds = seconds % 60;
          return {
            ((days ? String(days) + "d " : "") +
            (hours ? String(hours) + "h " : "") +
            (minutes ? String(minutes) + "m " : "") +
            (String(seconds) + "s")
             ).c_str()};

View in HA (schedules currently disabled as winter here!)

@chimeranzl, can you share some details on the Scheduler part in your UI? how it works? also, what is the progress bar?