ESPHome Sprinkler controller

Fair enough - at that point it is probably convoluted enough to just use an automation.

Now that I think about it, there are some options:

  1. You could use the HTTP client component to trigger an API action on the other device; constructing the payload could be a bit challenging though.

  2. You could use the MQTT client component to publish messages on a topic from one device, and listen for them on the other device.

Now that i realized ESPHome has a new (new for me) Sprinkler component, i can change my previous ESPHome made up sprinkler solution. I got a question though:

I have 3 valves and no pump in my sprinkler config. I used interlocking in GPIO switches since the pressure is enough for only 1 zone at a time. Also, i used to send the zone times at the start instance, so that if the WiFi connection of the ESPHome is lost, it can still turn off the valves in time and not make a flood:

switch:
  - platform: gpio
    name: "Relay_1"
    id: relay1
    pin: D1
    inverted: True
    restore_mode: RESTORE_DEFAULT_OFF
    interlock: &interlock_group [relay1, relay2, relay3, relay4]
    on_turn_on:
      then:
      - globals.set:
          id: remaining_time1
          value: !lambda "return id(time1);"

globals:
 - id: time1
   type: int
   restore_value: no
   initial_value: '600'
 - id: remaining_time1
   type: int
   restore_value: no
   initial_value: '600'

api:
  services:
    - service: set_time_1
      variables:
        time: int
      then:
        globals.set:
          id: time1
          value: !lambda "return time;"

interval:
 - interval: 5s
   then:
     - lambda: |-
         if(id(relay1).state) {
           id(remaining_time1)=id(remaining_time1)-5;
           if(id(remaining_time1)<=0){
             id(relay1).turn_off();
           }
         }

So, i was just using “esphome.espsprinkler_set_time_1” service to set up the duration and switch on GPIO1. So, even if the WiFi connection is lost, ESPHome will still be able to switch off valve1.

My questions are:

  1. Do i still need this way of check for WiFi connection loss, or the ESPHome sprinkler controller is handling to switch off the valves after duration is completed, standalone on connection loss?

  2. Will leaving the interlocking mechanism on GPIO settings create a problem or is it OK?

  1. No, you don’t need to do that. The sprinkler component handles run durations on all its own, and does not need a network connection to run its programs (only to start them).

  2. If you only have one sprinkler component in your configuration (the equivalent of a ‘program’ in a dedicated irrigation controller), you can use the valve_open_delay setting to ensure that only one valve is open at a time.

Also, there’s a major upgrade of the component in the ESPHome dev branch, which provides easy-to-use support for persisting the valve durations (and the multiplier) across reboots and upgrades. If you’re interesting, @rcblackwell and I have created a really nice configuration which makes use of this and can share it with you.

Thanks a lot Kevin, i would appreciate if you can share the configuration you and @rcblackwell created.

Here’s an example to get you started; it’s from esphome config so it includes all of defaults that you don’t actually need to specify:

external_components:
- source:
    url: https://github.com/esphome/esphome
    ref: dev
    type: git
  components:
  - sprinkler
  refresh: 1d
sprinkler:
- id: sprinklers
  main_switch:
    name: Front Yard Sprinkler Start/Resume/Stop
    disabled_by_default: false
    restore_mode: RESTORE_DEFAULT_OFF
  auto_advance_switch:
    name: Front Yard Sprinkler Auto-Advance
    disabled_by_default: false
    restore_mode: RESTORE_DEFAULT_OFF
    entity_category: config
  multiplier_number:
    name: Front Yard Sprinkler Multiplier
    mode: BOX
    icon: mdi:timer-cog-outline
    initial_value: 1.0
    min_value: 0.0
    max_value: 6.0
    step: 0.1
    restore_value: true
    disabled_by_default: false
    entity_category: config
  valves:
  - valve_switch:
      name: Front Yard Sprinkler Lower
      disabled_by_default: false
      restore_mode: RESTORE_DEFAULT_OFF
    enable_switch:
      name: Front Yard Enable Sprinkler Lower
      disabled_by_default: false
      restore_mode: RESTORE_DEFAULT_OFF
      entity_category: config
    run_duration_number:
      name: Front Yard Sprinkler Lower Duration
      unit_of_measurement: min
      mode: BOX
      icon: mdi:timer-outline
      initial_value: 15
      min_value: 0
      max_value: 120
      step: 1
      restore_value: true
      disabled_by_default: false
      entity_category: config
    valve_switch_id: relay1
  - valve_switch:
      name: Front Yard Sprinkler Upper
      disabled_by_default: false
      restore_mode: RESTORE_DEFAULT_OFF
    enable_switch:
      name: Front Yard Enable Sprinkler Upper
      disabled_by_default: false
      restore_mode: RESTORE_DEFAULT_OFF
      entity_category: config
    run_duration_number:
      name: Front Yard Sprinkler Upper Duration
      unit_of_measurement: min
      mode: BOX
      icon: mdi:timer-outline
      initial_value: 30
      min_value: 0
      max_value: 120
      step: 1
      restore_value: true
      disabled_by_default: false
      entity_category: config
    valve_switch_id: relay2
  next_prev_ignore_disabled: false
  disabled_by_default: false
1 Like

Please can you post your complete sprinkler system setup?

Too bad it is not possible to enter the days of activation for each single valve.
For example, I have areas that I would like to water only Monday-Wednesday-Thursday.

Here you go… this is 'esphome config` output so it includes a lot of stuff that isn’t actually required in the config files, but I don’t have time to trim it down :slight_smile:

https://km6g.us/~kpfleming/esphome-esp32r4-irrigation.txt

Thanks!
How did you set up the automations in Home Assistant and how do you manage them?

I currently have a zigbee relay that manages a single pump, a very simple system, and it’s done like this with also a notification in case the program is not executed due to a problem

#IRRIGAZIONE SMART V1.0 30-06-22#

input_number:
  durata_irrigazione:
    name: "Durata Irrigazione"
    min: 5
    max: 120
    step: 5
    mode: slider
    unit_of_measurement: s
    icon: mdi:timer-outline
    
input_datetime:
  orario_irrigazione:
    name: "Orario Irrigazione"
    has_date: false
    has_time: true
    icon: mdi:clock-outline

  ultima_irrigazione:
    name: "Ultima Irrigazione"
    has_date: true
    has_time: true
    icon: mdi:clock-outline

timer:
  timer_irrigazione:
    name: "Timer Irrigazione"
    duration: "00:00:00"
    icon: mdi:timer-sand

input_boolean:
  stato_irrigazione:
    name: "Stato Irrigazione"
    #initial: 'on'
    icon: mdi:power-standby
    
script:
  irrigazione_vasi:
    alias: Irrigazione Vasi
    sequence:
    - service: switch.turn_on
      data: {}
      target:
        entity_id: switch.irrigation_pump
    - service: timer.start
      entity_id: timer.timer_irrigazione
      data_template:
        duration: >-
          {{ '00:00:%02i' % (states('input_number.durata_irrigazione') | int  ) }}
    - wait_for_trigger:
        - platform: event
          event_type: timer.finished
          event_data:
            entity_id: timer.timer_irrigazione
      timeout: '70'
    - service: switch.turn_off
      data: {}
      target:
        entity_id: switch.irrigation_pump
        
automation: 
- alias: Irrigazione Vasi
  initial_state: true
  trigger:
    platform: template
    value_template: >-
      {{ states('sensor.time') == (states.input_datetime.orario_irrigazione.attributes.timestamp | int | timestamp_custom('%H:%M', False)) }}
  condition:
    - condition: state
      entity_id: input_boolean.stato_irrigazione
      state: 'on'
  action:
    - service: script.turn_on 
      entity_id: script.irrigazione_vasi
    - wait_for_trigger:
        - platform: state
          entity_id:
            - switch.irrigation_pump
          to: 'on'    
      timeout: 00:00:10
      continue_on_timeout: true # Se false esce e non va avanti
    - variables:
        message: |-
          {%- if states('switch.irrigation_pump') == 'on' -%}
            Sto annaffiando le piante
          {%- else -%}
            Forse c'è un problema con l'attivazione della pompa
          {%- endif -%}
    - service: notify.mobile_app_inanu
      data:
        title: IRRIGAZIONE
        message: '{{ message }}'
    - service: notify.mobile_app_inani
      data:
        title: IRRIGAZIONE
        message: '{{ message }}'
    
- alias: Timestamp Ultima Irrigazione
  trigger:
    - platform: state
      entity_id: switch.irrigation_pump
      from: 'off'
      to: 'on'
  condition: []
  action:
    - service: input_datetime.set_datetime
      target:
        entity_id: input_datetime.ultima_irrigazione
      data:
        timestamp: '{{ now().timestamp() }}'
    

        

I haven’t setup automations in HA yet, since we’re still about a week away from warm enough weather to actually activate our irrigation system… but I plan to use the new ‘Calendar’ features to trigger automations that use the services I defined in ESPHome.

Looks like i am completely lost on this controller. I made all settings, can use it manually.

esphome:
  name: esptest
  platform: ESP8266
  board: nodemcuv2
  on_boot:
    priority: -100
    then:
      # Set default state for Valve Status
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
      # Set multiplier to 60, convert seconds to minutes
      - sprinkler.set_multiplier:
          id: lawn_sprinkler_ctrlr
          multiplier: 60
          
wifi:
  ssid: "XXXX"
  password: "XXXX"
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Sprinkler Fallback Hotspot"
    password: "XXXX"

captive_portal:

# Enable logging
logger:

ota:

web_server:
  port: 80

time:
  - platform: homeassistant
    id: homeassistant_time

sensor:
  # Uptime sensor.
  - platform: uptime
    name: esptest Uptime

  # WiFi Signal sensor.
  - platform: wifi_signal
    name: esptest WiFi Signal
    update_interval: 60s
    
text_sensor:
  # Expose Time Remaining as a sensor.
  - platform: template
    id: time_remaining
    name: "Time Remaining"
    update_interval: 20s
    icon: "mdi:timer-sand"
    lambda: |-
      int seconds = round(id(lawn_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()};

  # Expose Progress Percent as a sensor.
  - platform: template
    id: progress_percent
    name: "Progress %"
    update_interval: 20s
    icon: "mdi:progress-clock"
    lambda: |-
      int progress_percent = round(((id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(id(lawn_sprinkler_ctrlr).active_valve().value_or(0)) - id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value_or(0)) * 100 / id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(id(lawn_sprinkler_ctrlr).active_valve().value_or(0))));
      std::string progress_percent_as_string = std::to_string(progress_percent);
      return progress_percent_as_string;

  # Expose Valve Status as a sensor.
  - platform: template
    id: valve_status
    name: "Status"
    update_interval: never
    icon: "mdi:information-variant"


sprinkler:
  - id: lawn_sprinkler_ctrlr
    main_switch: 
      name: Lawn Sprinklers
      disabled_by_default: false
      restore_mode: RESTORE_DEFAULT_OFF
    auto_advance_switch: 
      name: Sprinkler Auto-Advance
      disabled_by_default: false
      restore_mode: RESTORE_DEFAULT_OFF
      entity_category: config
    multiplier_number:
      name: Sprinkler Multiplier
      mode: BOX
      icon: mdi:timer-cog-outline
      initial_value: 1.0
      min_value: 0.0
      max_value: 6.0
      step: 0.1
      restore_value: true
      disabled_by_default: false
      entity_category: config
    valve_open_delay: 5s
    next_prev_ignore_disabled: true
    valves:
      - valve_switch: 
          name: Relay_1
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_OFF
        enable_switch: 
          name: Enable Relay_1
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_ON
          entity_category: config
        run_duration_number:
          name: Relay_1 Duration
          unit_of_measurement: min
          mode: BOX
          icon: mdi:timer-outline
          initial_value: 10
          min_value: 0
          max_value: 30
          step: 1
          restore_value: true
          disabled_by_default: false
          entity_category: config
        valve_switch_id: relay1
      - valve_switch: 
          name: Relay_2
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_OFF
        enable_switch: 
          name: Enable Relay_2
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_ON
          entity_category: config
        run_duration_number:
          name: Relay_2 Duration
          unit_of_measurement: min
          mode: BOX
          icon: mdi:timer-outline
          initial_value: 10
          min_value: 0
          max_value: 30
          step: 1
          restore_value: true
          disabled_by_default: false
          entity_category: config
        valve_switch_id: relay2
      - valve_switch: 
          name: Relay_3
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_OFF
        enable_switch: 
          name: Enable Relay_3
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_ON
          entity_category: config
        run_duration_number:
          name: Relay_3 Duration
          unit_of_measurement: min
          mode: BOX
          icon: mdi:timer-outline
          initial_value: 10
          min_value: 0
          max_value: 30
          step: 1
          restore_value: true
          disabled_by_default: false
          entity_category: config
        valve_switch_id: relay3
      - valve_switch: 
          name: Relay_4
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_OFF
        enable_switch: 
          name: Enable Relay_4
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_OFF
          entity_category: config
        run_duration_number:
          name: Relay_4 Duration
          unit_of_measurement: min
          mode: BOX
          icon: mdi:timer-outline
          initial_value: 10
          min_value: 0
          max_value: 30
          step: 1
          restore_value: true
          disabled_by_default: false
          entity_category: config
        valve_switch_id: relay4
switch:
  - platform: gpio
    id: relay1
    pin: D1
    inverted: True
    internal: True
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "Relay 1 Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
  - platform: gpio
    pin: D2
    id: relay2
    inverted: True
    internal: True
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "Relay 2 Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
  - platform: gpio
    pin: D6
    id: relay3
    inverted: True
    internal: True
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "Relay 3 Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
  - platform: gpio
    name: "Relay_4"
    pin: D7
    id: relay4
    inverted: True
    internal: True
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "Relay 4 Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
          
# Enable Home Assistant API
api:
  services:
    - service: start_full_cycle
      then:
        - sprinkler.start_full_cycle: lawn_sprinkler_ctrlr
    - service: start_single_valve
      variables:
        valve: int
      then:
        - sprinkler.start_single_valve:
            id: lawn_sprinkler_ctrlr
            valve_number: !lambda 'return valve-1;'
    - service: next_valve
      then:
        - sprinkler.next_valve: lawn_sprinkler_ctrlr
    - service: previous_valve
      then:
        - sprinkler.previous_valve: lawn_sprinkler_ctrlr
    - service: shutdown
      then:
        - sprinkler.shutdown: lawn_sprinkler_ctrlr
    - service: pause
      then:
        - sprinkler.pause: lawn_sprinkler_ctrlr
    - service: resume
      then:
        - sprinkler.resume: lawn_sprinkler_ctrlr
    - service: set_valve_run_duration
      then:
        - sprinkler.set_valve_run_duration:
            id: lawn_sprinkler_ctrlr
            valve_number: !lambda 'return valve-1;'
            run_duration: !lambda 'return duration;'



button:
  - platform: template
    id: sprinkler_pause
    name: "Pause"
    icon: "mdi:pause"
    on_press:
      then:
        - text_sensor.template.publish:
            id: valve_status
            state: "Paused"
        - sprinkler.pause: lawn_sprinkler_ctrlr

Am i supposed to set the schedules with automations on HA? If that is so, then i need to add sprinkler.set_valve_run_duration to services, right? Then the automation on HA in order should be:

  • Enable required valves
  • Set valve durations
  • Start service sprinkler.start_full_cycle

I am supposed to be changing the schedules (set valve durations) as required per week or season or whatever. Is this way OK or is there any other way?

1 Like

First, with the ESPHome release a few days ago, there’s no need to set the multiplier in an on_boot action, or to multiply the numbers by 60 to get minutes. You’re already using a number component for the multiplier, and you have restore_value: true so its value will be remembered by ESPHome. If you look at the examples in the current ESPHome documentation you can see how to set those numbers so that they will be interpreted as minutes instead of seconds.

If you want all of your valves to run in sequence, then in HA you only need to trigger the start_full_cycle service, and the ESPHome sprinkler controller will take care of the rest.

You can change the valve run durations directly in Home Assistant, since the number components will appear there. If you change them manually that’s fine, you can also setup HA automations to change them however you like. Regardless of the method you choose, the new durations (and multiplier) values will be stored in ESPHome. For seasonal changes, it’s easier to use the multiplier to adjust the watering time instead of adjusting the run durations directly. Set your run duration to the time you want for ‘mild’ weather (spring/autumn) and then use the multiplier to increase (summer) or decrease (winter) the calculated run times.

Kevin,

My understanding of the multiplier was foggy at best until now. Thanks for the clear explanation. It’s helped immensely. I now see where such would be beneficial in my use-case. Back to coding I go!

1 Like

I think i finalized my configuration at last. I have no pump, 1 controller, 3 valves+1 valve spare. This config also saves multiplier and run durations to esp8266 flash so on reboots and power cuts, it can restore these values. I do not use “repeat”.

esphome:
  name: esptest
  platform: ESP8266
  board: nodemcuv2
  on_boot:
    priority: -100
    then:
      # Set default state for Valve Status
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
  esp8266_restore_from_flash : true

wifi:
  ssid: "XXXXX"
  password: "XXXXX"
  # Enable fallback hotspot (captive portal) in case wifi connection fails
  ap:
    ssid: "Sprinkler Fallback Hotspot"
    password: "XXXXX"

captive_portal:

# Enable logging
logger:

ota:

web_server:
  port: 80

time:
  - platform: homeassistant
    id: homeassistant_time

sensor:
  # Uptime sensor.
  - platform: uptime
    name: esptest Uptime

  # WiFi Signal sensor.
  - platform: wifi_signal
    name: esptest WiFi Signal
    update_interval: 60s
    
text_sensor:
  # Expose Time Remaining as a sensor.
  - platform: template
    id: time_remaining
    name: "Time Remaining"
    update_interval: 20s
    icon: "mdi:timer-sand"
    lambda: |-
      int seconds = round(id(lawn_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()};

  # Expose Progress Percent as a sensor.
  - platform: template
    id: progress_percent
    name: "Progress %"
    update_interval: 20s
    icon: "mdi:progress-clock"
    lambda: |-
      int progress_percent = round(((id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(id(lawn_sprinkler_ctrlr).active_valve().value_or(0)) - id(lawn_sprinkler_ctrlr).time_remaining_active_valve().value_or(0)) * 100 / id(lawn_sprinkler_ctrlr).valve_run_duration_adjusted(id(lawn_sprinkler_ctrlr).active_valve().value_or(0))));
      std::string progress_percent_as_string = std::to_string(progress_percent);
      return progress_percent_as_string;

  # Expose Valve Status as a sensor.
  - platform: template
    id: valve_status
    name: "Status"
    update_interval: never
    icon: "mdi:information-variant"


sprinkler:
  - id: lawn_sprinkler_ctrlr
    main_switch: 
      name: Lawn Sprinklers
      disabled_by_default: false
      restore_mode: RESTORE_DEFAULT_OFF
    auto_advance_switch: 
      name: Sprinkler Auto-Advance
      disabled_by_default: false
      restore_mode: RESTORE_DEFAULT_OFF
      entity_category: config
    multiplier_number:
      name: Sprinkler Multiplier
      mode: BOX
      icon: mdi:timer-cog-outline
      initial_value: 1.0
      min_value: 0.0
      max_value: 6.0
      step: 0.1
      restore_value: true
      disabled_by_default: false
      entity_category: config
    valve_open_delay: 5s
    next_prev_ignore_disabled: true
    valves:
      - valve_switch: 
          name: Relay_1
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_OFF
        enable_switch: 
          name: Enable Relay_1
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_ON
          entity_category: config
        run_duration_number:
          name: Relay_1 Duration
          unit_of_measurement: min
          mode: BOX
          icon: mdi:timer-outline
          initial_value: 10
          min_value: 0
          max_value: 30
          step: 1
          restore_value: true
          disabled_by_default: false
          entity_category: config
        valve_switch_id: relay1
      - valve_switch: 
          name: Relay_2
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_OFF
        enable_switch: 
          name: Enable Relay_2
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_ON
          entity_category: config
        run_duration_number:
          name: Relay_2 Duration
          unit_of_measurement: min
          mode: BOX
          icon: mdi:timer-outline
          min_value: 0
          max_value: 30
          step: 1
          restore_value: true
          disabled_by_default: false
          entity_category: config
          initial_value: 10
        valve_switch_id: relay2
      - valve_switch: 
          name: Relay_3
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_OFF
        enable_switch: 
          name: Enable Relay_3
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_ON
          entity_category: config
        run_duration_number:
          name: Relay_3 Duration
          unit_of_measurement: min
          mode: BOX
          icon: mdi:timer-outline
          initial_value: 10
          min_value: 0
          max_value: 30
          step: 1
          restore_value: true
          disabled_by_default: false
          entity_category: config
        valve_switch_id: relay3
      - valve_switch: 
          name: Relay_4
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_OFF
        enable_switch: 
          name: Enable Relay_4
          disabled_by_default: false
          restore_mode: RESTORE_DEFAULT_OFF
          entity_category: config
        run_duration_number:
          name: Relay_4 Duration
          unit_of_measurement: min
          mode: BOX
          icon: mdi:timer-outline
          initial_value: 10
          min_value: 0
          max_value: 30
          step: 1
          restore_value: true
          disabled_by_default: false
          entity_category: config
        valve_switch_id: relay4
switch:
  - platform: gpio
    id: relay1
    pin: D1
    inverted: True
    internal: True
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "Relay 1 Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
  - platform: gpio
    pin: D2
    id: relay2
    inverted: True
    internal: True
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "Relay 2 Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
  - platform: gpio
    pin: D6
    id: relay3
    inverted: True
    internal: True
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "Relay 3 Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
  - platform: gpio
    name: "Relay_4"
    pin: D7
    id: relay4
    inverted: True
    internal: True
    restore_mode: RESTORE_DEFAULT_OFF
    on_turn_on:
      - text_sensor.template.publish:
          id: valve_status
          state: "Relay 4 Active"
    on_turn_off:
      - text_sensor.template.publish:
          id: valve_status
          state: "Idle"
          
# Enable Home Assistant API
api:
  services:
    - service: set_multiplier
      variables:
        multiplier: float
      then:
        - sprinkler.set_multiplier:
            id: lawn_sprinkler_ctrlr
            multiplier: !lambda 'return multiplier;'
    - service: start_full_cycle
      then:
        - sprinkler.start_full_cycle: lawn_sprinkler_ctrlr
    - service: start_single_valve
      variables:
        valve: int
      then:
        - sprinkler.start_single_valve:
            id: lawn_sprinkler_ctrlr
            valve_number: !lambda 'return valve-1;'
    - service: next_valve
      then:
        - sprinkler.next_valve: lawn_sprinkler_ctrlr
    - service: previous_valve
      then:
        - sprinkler.previous_valve: lawn_sprinkler_ctrlr
    - service: shutdown
      then:
        - sprinkler.shutdown: lawn_sprinkler_ctrlr
    - service: pause
      then:
        - sprinkler.pause: lawn_sprinkler_ctrlr
    - service: resume
      then:
        - sprinkler.resume: lawn_sprinkler_ctrlr
    - service: set_valve_run_duration
      variables:
        valve: int
        duration: int
      then:
        - sprinkler.set_valve_run_duration:
            id: lawn_sprinkler_ctrlr
            valve_number: !lambda 'return valve-1;'
            run_duration: !lambda 'return duration*60;'

button:
  - platform: template
    id: sprinkler_pause
    name: "Pause"
    icon: "mdi:pause"
    on_press:
      then:
        - text_sensor.template.publish:
            id: valve_status
            state: "Paused"
        - sprinkler.pause: lawn_sprinkler_ctrlr

Please feel free to correct my mistakes and excess configuration since i am at best a beginner on ESPHome, and i collected all these config from you guys’ configs. Btw Thanks a lot to you guys for all help especially @kpfleming and @rcblackwell .

2 Likes

Looks nice! I don’t think you actually need the services for setting the multiplier and run-durations though; those number entities should appear directly in HA and be settable via the normal HA automation system. If you use an HA automation to change the value of the multiplier number, that will be communicated to ESPHome, take effect, and also be stored in flash.

I thought, if i need a double or triple schedule like 10:00 in the morning for 10 mins and 22:00 for 5 mins, then in the automation i could set multiplier to 2 in the morning, start full cycle, then set multiplier to 1 in the evening and start full cycle again; assuming i left the duration as 5 mins. Or, in the automation i let alone multiplier to 1 and change specific valve durations with the automation to handle this double or triple different schedules through the day. Because morning and evening durations of each valve changes in my situation, it is not always a multiplier. Like:

10:00
V1: 10mins
V2: 5 mins
V3: 15 mins

22:00
V1: 5 mins
V2: 0mins
V3: 12mins

Some of the lawn are under sun, some are in shadows etc . That’s why the duration changes…

That was the reason why i put these services for multiplier and run-durations. I don’t know if there is any other way…

The number entities are directly modifiable in Home Assistant; there is no ‘custom’ service needed. When building an automation using the UI, use the “number.set_value” service (part of HA itself), then choose the appropriate number entity from your ESPHome device’s entities.

1 Like

I’m really surprised, I never see people use the divide function. If you live in a hot climate, hate seeing water from your system running into the road or if you want to water in a smarter way, I’d suggest people look into it.

@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