ESPHome: DIY Irrigation Controller With Internal Scheduler

HI,

I understood the issue
when you replace the days name in the integration.h file to match your language, you have to put attention to the text specially to match the latest case (Today)

else if (day == "Tod") { //Today in English

because the substitution is taking only 3 char, you have to use only the first 3 char in your language

string day = time.substr(6,3).c_str(); //day text is added to original string

for English “Today” is “Tod”

// Converting days to week numbers, change text based on your Language
    if (day == "Mon" || day == "mon" || day == "MON") {
      next_wday = 2;
    } else if (day == "Tue" || day == "tue" || day == "TUE") {
      next_wday = 3;
    } else if (day == "Wed" || day == "wed" || day == "WED") {
      next_wday = 4;
    } else if (day == "Thu" || day == "thu" || day == "THU") {
      next_wday = 5;
    } else if (day == "Fri" || day == "fri" || day == "FRI") {
      next_wday = 6;
    } else if (day == "Sat" || day == "sat" || day == "SAT") {
      next_wday = 7;
    } else if (day == "Sun" || day == "sun" || day == "SUN") {
      next_wday = 1;
    } else if (day == "Tod") { //Today in English
      next_wday = time_wday;
    }
1 Like

HI @bremby Thank! I havent installed yet, i have to make a modification at pump shelter. I tested on my kitchen table :sweat_smile: everything was working but I dont remeber if I tested that specific function.

regards

@bremby hi again! if you define initial, every time you reboot HA it will set to that value. will lost you days or times settings.

Bye

@bremby guess what?? it´s me again :stuck_out_tongue_closed_eyes: delete initial from code

From my config.yaml

input_number:
  irrigation_zone1_duration:
    name: Duración Zona 1
    min: 0
    max: 30
    step: 1
    mode: slider
    icon: mdi:timer

Tell me if that works

Regards

Hi,

thanks for noticing this. Maybe because i am spanish speaker and in spanish today = “hoy”, just 3 letters so i didn’t have that problem when i modified irrigation.h

regards,

Hi,

I managed to make everything working and cover 6 zones

this is the configuration page

I also added 2 additional switches
one to stop all the schedules when they are running
image

- platform: template
    name: Stop All Zones
    id: irrigation_stop_zones
    icon: mdi:sprinkler-variant
    optimistic: true
    turn_on_action:
      - switch.turn_off: irrigation_channel_1
      - switch.turn_off: irrigation_channel_2
      - switch.turn_off: irrigation_channel_3
      - switch.turn_off: irrigation_channel_4
      - switch.turn_off: irrigation_channel_5
      - switch.turn_off: irrigation_channel_6
      - delay: 10s
      - switch.turn_off: irrigation_stop_zones

one to “suspend” the schedule (eg. you want to suspend the irrigation for a period of time, but you don’t want to clean the configurations or turn off the esp)

image

  - platform: template
    name: Irrigation Zone 1
    id: irrigation_zone_1
    icon: mdi:sprinkler-variant
    lambda: return id(irrigation_channel_1).state;
    optimistic: true
    turn_on_action:
      # Turn on if not disabled and not running
      if:
        condition:
          and:
            - lambda: return id(irrigation_zone_1_duration) > 0;
            - binary_sensor.is_off: ui_stop_irrigation_automation
        then:
          - switch.turn_on: irrigation_channel_1
    turn_off_action:
      - switch.turn_off: irrigation_channel_1

let me know what you think or if you have made additional configurations or have any suggestions

regards

2 Likes

Hi! great Job…i thinking about different season config, you dont need the same amount of water in autumn and winter, as in spring and summer.

Regards

1 Like

Hey all, thinking about giving this project a try. I notice the device used for switching is a Sonoff 4 Channel Pro R2. I don’t seem to be able to find one and the link in the blog article says it is out of stock.

Does anyone know if a Sonoff 4 Channel Pro R3 would work or is this something different again?

Also would this be suitable as a power supply?

Hi @currest2620,

I used an ESP32 module with an 8ch relay module:

LILYGO® TTGO T-Internet-POE ESP32-WROOM LAN8720A Chip Ethernet Adapter And Downloader Expansion Board Programmable Hardware - Module - Shenzhen Xin Yuan Electronic Technology Co., Ltd

ELEGOO Relay Module with Optocoupler for Arduino UNO R3 MEGA 2560 1280 DSP ARM PIC AVR STM32 Raspberry Pi – ELEGOO Official

The trick is adjusting the PINOUT definition with your board

Nice, though I would prefer to use a sonof four channel as the relays are built in.

Thank you for letting me know about the outdated Sonoff link (I am updating the link on my post). The R3 looks to be a direct replacement for the R2, so it should work the same.

Awesome. I’ll get one ordered. Thanks for the feedback.

Hello,

So I have everything configured but I’m running into an issue.
I have it scheduled for Saturday @05:53 and Monday @11:00. The next watering for zone 1 should say Monday @11:00 since the watering for Saturday has already ran but it’s showing Saturday @11:00.

Not sure why it’s not following the schedule.

Hi! @stinger that’s because the schedule is for every day, you can’t choose the time for each days… So, if you choose Saturday and Monday, and then you set it to run at 5 am and 11am, it will run those two days at those two hours :grimacing:

Thanks for the info. I’ll see what I can do to modify it to fit my needs.

Hey guys, I have received the Sonof 4ch pro R3 and have flashed it with ESP Home. So now I would like to try out the ESP home code.

The first, most basic question I have is … what do I do with then irrigation.h file? Do I copy that to any specific location?

I am also unsure about these includes in the irrigation.yaml file:

  <<: !include common/substitutions/gpio/sonoff4chpror2.yaml
  <<: !include common/esphome/leds/status_with_api.yaml

Where do I obtain these files and where do they go?

Hold the phone… think I’ve worked it out. Pretty basic really.

OK, got this setup on the SONOF 4CH Pro. Seems to be working OK. I’ll run some tests to check.

Todo, is to have the system run on certain days, say every second day (to comply with local water restrictions) and to have the duration minutes displayed on the card, (I only see the slider).

Awesome work. Thanks for the instructions and documentation.

1 Like

@VikingBlod @joaquin68 I really need help here.
I re-installed HA and the ESP and now I’m stuck with the never-ending loop
can you help me with the steps to successfully load the code and stop the reboot very 60 seconds?

Regards

Hi! @bremby did you upload my code or others code? Did you verified this?

https://community.home-assistant.io/t/esphome-diy-irrigation-controller-with-internal-scheduler/171844/41?u=joaquin68

@joaquin68 , yep. last month i started from your code and i added 6 zones. but now after the re-install (i reloaded the config from the backup) probably i missed something and the esp reboots every 60sec. I think that this happen when it try to get the time from home assistant. i really don’t remember what step i did last time to fix it

here the config.xml

#########################################################
### IRRIGATION
#########################################################
input_text:
  ##Time Schedule
  irrigation_zone_1_times:
    name: Time Schedule - Zone 1
    icon: mdi:chart-timeline
    mode: text
    #initial: 01:00

##Day Schedule
  irrigation_zone_1_days:
    name: Day Schedule - Zone 1
    icon: mdi:calendar-week
    mode: text
    #initial: mon

input_number:
  ##Duration
  irrigation_zone_1_duration:
    name: Duration - Zone 1
    min: 0
    max: 30
    step: 1
    mode: slider
    icon: mdi:timer
    #initial: 5

this is the ESP config

esphome:
  name: irrigation-control
  platform: ESP32
  board: esp-wrover-kit
  includes:
    - irrigation.h
ethernet:
  type: LAN8720
  mdc_pin: GPIO23
  mdio_pin: GPIO18
  clk_mode: GPIO17_OUT
  phy_addr: 0
  power_pin: GPIO12
  manual_ip:
   static_ip: 192.168.1.x
   gateway: 192.168.1.x
   subnet: 255.255.255.0
   dns1: 192.168.1.x
   dns2: 192.168.1.x
# Enable logging
logger:
# Enable Home Assistant API
api:
  reboot_timeout: 0s
ota:
globals:
#==============================================================#
  # Irrigation time remaining
  - id: remaining_time_1
    type: int
    restore_value: no
    initial_value: "300"
#==============================================================#
  # Store previous values to verify change.
  - id: remaining_time_1_previous
    type: int
    restore_value: no
    initial_value: "0"
#==============================================================#
binary_sensor:
  # Connection status
  - platform: status
    name: "Irrigation Status"
#==============================================================#
  - platform: homeassistant
    id: ui_stop_irrigation_automation
    entity_id: input_boolean.stop_irrigation_automation
#==============================================================#
switch:
#==============================================================#
  - platform: restart
    name: "irrigation-control_restart"
#==============================================================#
  # Virtual Zone Switches which toggle the relay, and store the current state.
  - platform: template
    name: Stop All Zones
    id: irrigation_stop_zones
    icon: mdi:sprinkler-variant
    optimistic: true
    turn_on_action:
      - switch.turn_off: irrigation_channel_1
      - delay: 10s
      - switch.turn_off: irrigation_stop_zones
#==============================================================#
  - platform: template
    name: Irrigation Zone 1
    id: irrigation_zone_1
    icon: mdi:sprinkler-variant
    lambda: return id(irrigation_channel_1).state;
    optimistic: true
    turn_on_action:
      # Turn on if not disabled.
      if:
        condition:
          and:
            - lambda: return id(irrigation_zone_1_duration) > 0;
            - binary_sensor.is_off: ui_stop_irrigation_automation
        then:
          - switch.turn_on: irrigation_channel_1
    turn_off_action:
      - switch.turn_off: irrigation_channel_1
#==============================================================#
  # Relays which trigger solenoids
  - platform: gpio
    id: irrigation_channel_1
    pin: GPIO04
    restore_mode: ALWAYS_OFF
    inverted: yes
    on_turn_on:
      then:
        # Start the countdown timer.
        - globals.set:
            id: remaining_time_1
            value: !lambda return id(irrigation_zone_1_duration).state * 60;
        # Show the remaining time.
        - sensor.template.publish:
            id: irrigation_zone_1_remaining
            state: !lambda return id(irrigation_zone_1_duration).state;
        # Show the "Next Time" as "now".
        - text_sensor.template.publish:
            id: irrigation_zone_1_next
            state: "now"
            # state NOW on original code, change to your preferred language
    on_turn_off:
      then:
        - sensor.template.publish:
            id: irrigation_zone_1_remaining
            state: "0"
        # Update the next scheduled run time.
        - text_sensor.template.publish:
            id: irrigation_zone_1_next
            state: !lambda |-
              return update_next_runtime(id(irrigation_zone_1_times).state, id(irrigation_zone_1_days).state);
sensor:
#==============================================================#
  - platform: uptime
    name: "Uptime irrigation-control"
#==============================================================#
  # Retrieve durations settings from the Home Assistant UI.
  - platform: homeassistant
    id: ui_zone_1_duration
    entity_id: input_number.irrigation_zone_1_duration
    on_value:
      #if:
      #  condition:
      #    api.connected:
      then:
        - sensor.template.publish:
            id: irrigation_zone_1_duration
            state: !lambda return id(ui_zone_1_duration).state;
#==============================================================#
  # Store durations.
  - platform: template
    name: Irrigation duration - Zone 1
    id: irrigation_zone_1_duration
    accuracy_decimals: 0
    unit_of_measurement: min
    icon: mdi:camera-timer
#==============================================================#
  # Countdown sensors.
  - platform: template
    name: Remaining Time - Zone 1
    id: irrigation_zone_1_remaining
    lambda: "return 0;"
    accuracy_decimals: 0
    unit_of_measurement: min
    icon: mdi:timer
    on_value:
      then:
        - if:
            condition:
              lambda: return id(remaining_time_1) == 0;
            then:
              - switch.turn_off: irrigation_channel_1
###########################################
#
# Template Text Sensors
#
#==============================================================#
  - platform: version
    name: "ESPHome Version"
#==============================================================#
  # Retrieve list of times from the Home Assistant UI.
  - platform: homeassistant
    id: ui_zone_1_times
    entity_id: input_text.irrigation_zone_1_times
    on_value:
      #if:
      #  condition:
      #    api.connected:
      then:
        #- delay: 10sec
        - text_sensor.template.publish:
            id: irrigation_zone_1_times
            state: !lambda return id(ui_zone_1_times).state;
#==============================================================#
  # Store time lists.
  - platform: template
    name: Schedule - Zone 1
    id: irrigation_zone_1_times
    on_value:
      then:
        # Update the next scheduled run time.
        - text_sensor.template.publish:
            id: irrigation_zone_1_next
            state: !lambda |-
              return update_next_runtime(id(irrigation_zone_1_times).state, id(irrigation_zone_1_days).state);
#==============================================================#
  # Retrieve list of days from the Home Assistant UI.
  - platform: homeassistant
    id: ui_zone_1_days
    entity_id: input_text.irrigation_zone_1_days
    on_value:
      #if:
      #  condition:
      #    api.connected:
      then:
        #- delay: 10sec
        - text_sensor.template.publish:
            id: irrigation_zone_1_days
            state: !lambda return id(ui_zone_1_days).state;
#==============================================================#
  # Store time lists.
  - platform: template
    name: Day - Zone 1
    id: irrigation_zone_1_days
    on_value:
      then:
        # Update the next scheduled run time.
        - text_sensor.template.publish:
            id: irrigation_zone_1_next
            state: !lambda |-
              return update_next_runtime(id(irrigation_zone_1_times).state, id(irrigation_zone_1_days).state);
#==============================================================#
  # Set the next scheduled time.
  - platform: template
    name: Next Irrigation - Zone 1
    id: irrigation_zone_1_next
    icon: mdi:calendar-clock
#==============================================================#
# Update the countdown timers every 5 seconds.
interval:
  - interval: 5s
    then:
      - lambda: |-
          if (id(remaining_time_1) > 0) {
            // Store the previous time.
            id(remaining_time_1_previous) = id(remaining_time_1);
            // When the relay is on.
            if (id(irrigation_channel_1).state) {
              // Decrement the timer.
              id(remaining_time_1) -= 5;
              // Turn off the relay when the time reaches zero... or the remaining time fails a sanity check!
              //if (id(remaining_time_1) <= 0 || id(irrigation_zone_1_remaining).state > id(irrigation_zone_1_duration).state){
              if (id(remaining_time_1) <= 0) {
                id(irrigation_channel_1).turn_off();
                id(remaining_time_1) = 0;
              }
            }
            // Update the remaining time display.
            if (id(remaining_time_1_previous) != id(remaining_time_1)) {
              id(irrigation_zone_1_remaining).publish_state( (id(remaining_time_1)/60) + 1 );
            }
          }
# Time based automations.
time:
  - platform: homeassistant
    id: homeassistant_time
    timezone: Europe/Rome
    #timezone: CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00
    on_time:
      - seconds: 0
        minutes: /1
        then:
          - lambda: |-
              if (scheduled_runtime(id(irrigation_zone_1_next).state.c_str()))
                {
                  id(irrigation_zone_1).turn_on();
                }