Things missing currently are:
Code to use the buttons
Internal or external schedules (easy fix if using HA frontend).
Code to display the actual running zones run time and remaining time on the LCD
Hi bremby.
I don’t have any schematic as I just build up as I go. The connections are this:
The four buttons share one common ground, and each button goes to an input on ‘IN5 - IN8’.
The 16x2 LCD has a I2C converter attached like found on AliExpress or Ebay.
https://www.aliexpress.com/item/32713904220.html?
It connects to the header designated ‘IIC’ but has ground connected to the spare ground pin on header ‘P2’.
Board power comes from the 24V AC irrigation transformer (black wires seen in the bottom of build image), the transformer is also connected to each relay by ‘daisy chained’ wire links as seen in the image.
The 24V AC is converted to 12V DC for the KC868 board. To do that I used a small 2 Amp bridge rectifier that in turn feeds a 36V DC to 12V DC converter module (which sits at the top behind the LCD). Both are soldered to small Vero board (AKA perf board) strip to make it easy to mount to the box.
My DC-DC module is obsolete, but any module with greater than 36V DC input and at least 12V DC output at 2A or more will be fine…
The 12V DC output is wired direct to the KC868 +12V power input.
Output for the 8x irrigation valves is via the Normally Open contact of each zone relay (not yet connected). Each relay Common contact is connected to one side of the 24V AC transformer via the row of tinned wire links.
This is my code currently below. I’ve added ability to change the LCD display to follow the status of the running zone. I don’t have any internal scheduling yet, and I’m not sure I need too, maybe a default program if HA is off-air and one button assigned to start a manual watering.
Not sure yet if I should use HA automations for scheduling or create of borrow something for Node-Red…
# 8 Zone Version and compiled via ESPhome and Python3.10.4
substitutions:
devicename: irrigation-controller
esphome:
name: $devicename
esp32:
board: nodemcu-32s
framework:
type: arduino
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Esp32-Irrigation"
# password: !secret ap_password
# Enable logging
logger:
# Enable Home Assistant API
api:
reboot_timeout: 0s
services:
- service: pause
then:
- sprinkler.pause: esp32_sprinkler_ctrlr
- service: resume
then:
- sprinkler.resume: esp32_sprinkler_ctrlr
ota:
# I2C bus config
i2c:
sda: 4
scl: 5
scan: true
id: bus_a
# I2C I/O expander config
pcf8574:
- id: 'pcf8574_output_hub'
address: 0x24
pcf8575: false
- id: 'pcf8574_input_hub'
address: 0x22
# 16x2 LCD config
display:
- platform: lcd_pcf8574
dimensions: 16x2
address: 0x27
update_interval: 2s
lambda: |-
switch (id(esp32_sprinkler_ctrlr).active_valve().value_or(-1)) {
case 0: //valve0, zone1, internal valve numbers not zone_valve_swX numbers
it.printf(0, 0, "Front Lawn: %s", id(zone_valve_sw1).state ? "ON" : "OFF");
if (id(zone_valve_sw1).state) {
it.printf(0, 1, "Mins: %2d of", id(esp32_sprinkler_ctrlr).time_remaining().value_or(0) / 60);
it.printf(12, 1, "%2d", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(0) / 60);
} else {
it.printf(0, 1, "Mins Set %2d ", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(0) / 60);
}
break;
case 1: //valve1, zone2,
it.printf(0, 0, "Back Lawn: %s", id(zone_valve_sw2).state ? "ON" : "OFF");
if (id(zone_valve_sw2).state) {
it.printf(0, 1, "Mins: %2d of", id(esp32_sprinkler_ctrlr).time_remaining().value_or(0) / 60);
it.printf(12, 1, "%2d", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(1) / 60);
} else {
it.printf(0, 1, "Mins Set %2d ", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(1) / 60);
}
break;
case 2: //valve2, zone3,
it.printf(0, 0, "Front middle: %s", id(zone_valve_sw3).state ? "ON" : "OFF");
if (id(zone_valve_sw3).state) {
it.printf(0, 1, "Mins: %2d of", id(esp32_sprinkler_ctrlr).time_remaining().value_or(0) / 60);
it.printf(12, 1, "%2d", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(2) / 60);
} else {
it.printf(0, 1, "Mins Set %2d ", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(2) / 60);
}
break;
case 3: //valve3, zone4
it.printf(0, 0, "West Fence: %s", id(zone_valve_sw4).state ? "ON" : "OFF");
if (id(zone_valve_sw4).state) {
it.printf(0, 1, "Mins: %2d of", id(esp32_sprinkler_ctrlr).time_remaining().value_or(0) / 60);
it.printf(12, 1, "%2d", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(3) / 60);
} else {
it.printf(0, 1, "Mins Set %2d ", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(3) / 60);
}
break;
case 4: //valve4, zone5
it.printf(0, 0, "Front South: %s", id(zone_valve_sw5).state ? "ON" : "OFF");
if (id(zone_valve_sw5).state) {
it.printf(0, 1, "Mins: %2d of", id(esp32_sprinkler_ctrlr).time_remaining().value_or(0) / 60);
it.printf(12, 1, "%2d", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(4) / 60);
} else {
it.printf(0, 1, "Mins Set %2d ", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(4) / 60);
}
break;
case 5: //valve5, zone6
it.printf(0, 0, "Back Wall W: %s", id(zone_valve_sw6).state ? "ON" : "OFF");
if (id(zone_valve_sw6).state) {
it.printf(0, 1, "Mins: %2d of", id(esp32_sprinkler_ctrlr).time_remaining().value_or(0) / 60);
it.printf(12, 1, "%2d", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(5) / 60);
} else {
it.printf(0, 1, "Mins Set %2d ", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(5) / 60);
}
break;
case 6: //valve6, zone7
it.printf(0, 0, "Back Wall E: %s", id(zone_valve_sw7).state ? "ON" : "OFF");
if (id(zone_valve_sw7).state) {
it.printf(0, 1, "Mins: %2d of", id(esp32_sprinkler_ctrlr).time_remaining().value_or(0) / 60);
it.printf(12, 1, "%2d", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(6) / 60);
} else {
it.printf(0, 1, "Mins Set %2d ", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(6) / 60);
}
break;
case 7: //valve7, zone8
it.printf(0, 0, "Verandas: %s", id(zone_valve_sw8).state ? "ON" : "OFF");
if (id(zone_valve_sw8).state) {
it.printf(0, 1, "Mins: %2d of", id(esp32_sprinkler_ctrlr).time_remaining().value_or(0) / 60);
it.printf(12, 1, "%2d", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(7) / 60);
} else {
it.printf(0, 1, "Mins Set %2d ", id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(7) / 60);
}
break;
case -1:
it.printf(0, 0, "Watering OFF");
it.strftime(0, 1,"Time is %H:%M:%S", id(homeassistant_time).now());
break;
default:
break;
}
# Main sprinkler code
sprinkler:
- id: esp32_sprinkler_ctrlr
main_switch: "Master Run/Stop"
auto_advance_switch: "Zones Auto Advance"
reverse_switch: "Zones Reverse"
valve_overlap: 1s
valves:
- valve_switch: "Zone 1"
enable_switch: "Zone 1 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw1
- valve_switch: "Zone 2"
enable_switch: "Zone 2 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw2
- valve_switch: "Zone 3"
enable_switch: "Zone 3 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw3
- valve_switch: "Zone 4"
enable_switch: "Zone 4 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw4
- valve_switch: "Zone 5"
enable_switch: "Zone 5 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw5
- valve_switch: "Zone 6"
enable_switch: "Zone 6 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw6
- valve_switch: "Zone 7"
enable_switch: "Zone 7 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw7
- valve_switch: "Zone 8"
enable_switch: "Zone 8 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw8
# Valve control outputs config via I/O expander
switch:
- platform: gpio
id: zone_valve_sw1
pin:
pcf8574: pcf8574_output_hub
# Use pin number 0
number: 0
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw2
pin:
pcf8574: pcf8574_output_hub
# Use pin number 1
number: 1
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw3
pin:
pcf8574: pcf8574_output_hub
# Use pin number 2
number: 2
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw4
pin:
pcf8574: pcf8574_output_hub
# Use pin number 3
number: 3
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw5
pin:
pcf8574: pcf8574_output_hub
# Use pin number 4
number: 4
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw6
pin:
pcf8574: pcf8574_output_hub
# Use pin number 5
number: 5
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw7
pin:
pcf8574: pcf8574_output_hub
# Use pin number 6
number: 6
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw8
pin:
pcf8574: pcf8574_output_hub
# Use pin number 7
number: 7
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: template #this switch doesn't work properly. Can pause via HA frontend, but will not resume... Via Services does work...
id: pause_switch
name: "Pause Irrigation Switch"
turn_on_action:
then:
- sprinkler.pause: esp32_sprinkler_ctrlr
turn_off_action:
then:
- sprinkler.resume: esp32_sprinkler_ctrlr
# Configuration to set multiplier via number
number:
- platform: template
id: esp32_ctrlr_multiplier
name: "Run Duration Multiplier"
min_value: 1.0
max_value: 3.0
step: 0.1
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).multiplier();"
set_action:
- sprinkler.set_multiplier:
id: esp32_sprinkler_ctrlr
multiplier: !lambda 'return x;'
# Configuration to set valve run duration via number
- platform: template
id: sprinkler_valve_1_duration
name: "Zone 1 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
# update_interval: 10s
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(0) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 0
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_2_duration
name: "Zone 2 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(1) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 1
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_3_duration
name: "Zone 3 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(2) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 2
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_4_duration
name: "Zone 4 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(3) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 3
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_5_duration
name: "Zone 5 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(4) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 4
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_6_duration
name: "Zone 6 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(5) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 5
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_7_duration
name: "Zone 7 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(6) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 6
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_8_duration
name: "Zone 8 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(7) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 7
run_duration: !lambda "return x * 60;"
#Rain Sensor from my HA
sensor:
- platform: homeassistant
id: rain_today
entity_id: sensor.daily_rain_rate
- platform: wifi_signal
name: "ESP Irrigation WiFi Signal Sensor"
update_interval: 300s
- platform: template
name: "Zone Time Remaining Sensor"
icon: mdi:progress-clock
unit_of_measurement: 'Min'
lambda: "return id(esp32_sprinkler_ctrlr).time_remaining().value_or(0) / 60;"
update_interval: 30s
# - platform: template
# name: "Zone Active Sensor"
## unit_of_measurement: ''
# lambda: "return id(esp32_sprinkler_ctrlr).active_valve().value_or(NAN);" #Valves are numbered from 0-7 internally which is an issue when displaying !
# update_interval: 30s
# Time source config
time:
- platform: homeassistant
id: homeassistant_time
timezone: Australia/Adelaide
#timezone: CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00
@mr.sneezy thank you so much,
I worked a little bit around you example and I stolen also something from ESPHome Sprinkler YAML - ESPHome - Home Assistant Community (home-assistant.io)
sharing back where I’m now
ESP Code
# Enable logging
logger:
###################################################################################################
##### I/O expander hub definition
###################################################################################################
mcp23017:
- id: 'mcp23017_hub'
address: 0x20
#nodemcu devkit v4.0
i2c:
sda: 21
scl: 22
scan: True
###################################################################################################
###################################################################################################
###################################################################################################
# Enable Home Assistant APIs
api:
reboot_timeout: 0s
services:
- service: set_multiplier
variables:
multiplier: float
then:
- sprinkler.set_multiplier:
id: esp32_sprinkler_ctrlr
multiplier: !lambda 'return multiplier;'
- service: start_full_cycle
then:
- sprinkler.start_full_cycle: esp32_sprinkler_ctrlr
- service: start_single_valve
variables:
valve: int
then:
- sprinkler.start_single_valve:
id: esp32_sprinkler_ctrlr
valve_number: !lambda 'return valve;'
- service: next_valve
then:
- sprinkler.next_valve: esp32_sprinkler_ctrlr
- service: previous_valve
then:
- sprinkler.previous_valve: esp32_sprinkler_ctrlr
- service: shutdown
then:
- sprinkler.shutdown: esp32_sprinkler_ctrlr
- service: pause
then:
- sprinkler.pause: esp32_sprinkler_ctrlr
- service: resume
then:
- sprinkler.resume: esp32_sprinkler_ctrlr
- service: resume_or_full_cycle
then:
- sprinkler.resume_or_start_full_cycle: esp32_sprinkler_ctrlr
- service: repeat_2
then:
- sprinkler.set_repeat:
id: esp32_sprinkler_ctrlr
repeat: 2 # would run three cycles
- service: repeat_3
then:
- sprinkler.set_repeat:
id: esp32_sprinkler_ctrlr
repeat: 3 # would run three cycles
# Main sprinkler code
sprinkler:
- id: esp32_sprinkler_ctrlr
main_switch: "Master Run/Stop"
auto_advance_switch: "Zones Auto Advance"
reverse_switch: "Zones Reverse"
valve_open_delay: 2s
valves:
- valve_switch: "Zone 1"
enable_switch: "Zone 1 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw1
- valve_switch: "Zone 2"
enable_switch: "Zone 2 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw2
- valve_switch: "Zone 3"
enable_switch: "Zone 3 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw3
- valve_switch: "Zone 4"
enable_switch: "Zone 4 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw4
- valve_switch: "Zone 5"
enable_switch: "Zone 5 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw5
- valve_switch: "Zone 6"
enable_switch: "Zone 6 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw6
# Valve control outputs config via I/O expander
switch:
#################################################################################################
####### CONTROL SWITCH
#################################################################################################
- platform: template
id: esp32_sprinkler_ctrlr_run
name: "Sprinkler Controller Run"
optimistic: true
on_turn_on:
- text_sensor.template.publish:
id: esp32_sprinkler_ctrlr_status
state: "Running"
- sprinkler.resume_or_start_full_cycle: esp32_sprinkler_ctrlr
- switch.turn_off: esp32_sprinkler_ctrlr_pause
- switch.turn_off: esp32_sprinkler_ctrlr_stop
- platform: template
id: esp32_sprinkler_ctrlr_stop
name: "Sprinkler Controller Stop"
optimistic: true
on_turn_on:
- text_sensor.template.publish:
id: esp32_sprinkler_ctrlr_status
state: "Stopped"
- sprinkler.shutdown: esp32_sprinkler_ctrlr
- switch.turn_off: esp32_sprinkler_ctrlr_pause
- switch.turn_off: esp32_sprinkler_ctrlr_run
- platform: template
id: esp32_sprinkler_ctrlr_pause
name: "Sprinkler Controller Pause"
optimistic: true
turn_on_action:
- delay: 500ms
- lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state != "Running")
{
id(esp32_sprinkler_ctrlr_pause).turn_off();
}
- lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state == "Running")
{
id(esp32_sprinkler_ctrlr_status).publish_state("Paused");
id(esp32_sprinkler_ctrlr).pause();
}
on_turn_off:
lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state == "Paused")
{
id(esp32_sprinkler_ctrlr_status).publish_state("Running");
id(esp32_sprinkler_ctrlr).resume();
}
- platform: template
id: esp32_sprinkler_ctrlr_resume
name: "Sprinkler Controller Resume"
optimistic: true
#################################################################################################
####### I/0 SWITCH
#################################################################################################
- platform: gpio
id: zone_valve_sw1
name: "MCP23017 Pin B2"
pin:
mcp23xxx: mcp23017_hub
# Use pin B2
number: 10
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw2
name: "MCP23017 Pin B3"
pin:
mcp23xxx: mcp23017_hub
# Use pin B3
number: 11
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw3
name: "MCP23017 Pin B4"
pin:
mcp23xxx: mcp23017_hub
# Use pin B4
number: 12
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw4
name: "MCP23017 Pin B5"
pin:
mcp23xxx: mcp23017_hub
# Use pin B5
number: 13
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw5
name: "MCP23017 Pin B6"
pin:
mcp23xxx: mcp23017_hub
# Use pin B6
number: 14
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw6
name: "MCP23017 Pin B7"
pin:
mcp23xxx: mcp23017_hub
# Use pin B7
number: 15
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
#- platform: template #this switch doesn't work properly. Can pause via HA frontend, but will not resume... Via Services does work...
# id: pause_switch
# name: "Pause Irrigation Switch"
# turn_on_action:
# then:
# - sprinkler.pause: esp32_sprinkler_ctrlr
# turn_off_action:
# then:
# - sprinkler.resume: esp32_sprinkler_ctrlr
number:
# Configuration to set multiplier via number
- platform: template
id: sprinkler_ctrlr_multiplier
name: "Run Duration Multiplier"
min_value: 1.0
max_value: 3.0
step: 0.1
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).multiplier();"
set_action:
- sprinkler.set_multiplier:
id: esp32_sprinkler_ctrlr
multiplier: !lambda 'return x;'
# Configure repeat
- platform: template
id: sprinkler_ctrlr_repeat_cycles
name: "Sprinkler Repeat Cycles"
min_value: 0
max_value: 300
step: 1
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).repeat();"
set_action:
- sprinkler.set_repeat:
id: esp32_sprinkler_ctrlr
repeat: !lambda 'return x;'
# Configuration to set valve run duration via number
- platform: template
id: sprinkler_valve_1_duration
name: "Zone 1 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: 10s
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(0) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 0
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_2_duration
name: "Zone 2 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: 10s
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(1) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 1
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_3_duration
name: "Zone 3 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: 10s
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(2) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 2
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_4_duration
name: "Zone 4 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: 10s
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(3) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 3
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_5_duration
name: "Zone 5 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: 10s
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(4) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 4
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_6_duration
name: "Zone 6 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: 10s
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(5) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 5
run_duration: !lambda "return x * 60;"
sensor:
### SENSORS
- platform: template
name: "Zone Time Remaining Sensor"
icon: mdi:progress-clock
unit_of_measurement: 'Min'
accuracy_decimals: 0
update_interval: 10s
lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state != "Paused")
{
return id(esp32_sprinkler_ctrlr).time_remaining().value_or(0) / 60;
}
else
{
return {};
}
- platform: template
name: "Zone Active Sensor"
unit_of_measurement: ''
accuracy_decimals: 0
#Valves are numbered from 0-7 internally which is an issue when displaying !
lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state == "Stopped")
{
return id(esp32_sprinkler_ctrlr).active_valve().value_or(NAN);
}
else
{
return id(esp32_sprinkler_ctrlr).active_valve().value_or(NAN) + 1;
}
update_interval: 10s
text_sensor:
- platform: template
id: esp32_sprinkler_ctrlr_status
name: "Sprinklers Status"
update_interval: 1s
# Time source config
time:
- platform: homeassistant
id: homeassistant_time
LOVELACE
- theme: Backend-selected
title: Sprinkler
path: sprinkler
type: panel
badges: []
cards:
- type: vertical-stack
cards:
- type: horizontal-stack
cards:
- show_name: true
show_icon: true
show_state: true
type: glance
entities:
- entity: sensor.sprinklers_status
- entity: sensor.zone_active_sensor
- entity: sensor.zone_time_remaining_sensor
state_color: false
- type: entities
entities:
- entity: number.run_duration_multiplier
- entity: number.sprinkler_repeat_cycles
- type: horizontal-stack
cards:
- show_name: true
show_icon: true
type: button
entity: switch.zone_1
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- show_name: true
show_icon: true
type: button
entity: switch.zone_2
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- show_name: true
show_icon: true
type: button
entity: switch.zone_3
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- show_name: true
show_icon: true
type: button
entity: switch.zone_4
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- show_name: true
show_icon: true
type: button
entity: switch.zone_5
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- show_name: true
show_icon: true
type: button
entity: switch.zone_6
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- type: horizontal-stack
cards:
- show_name: false
show_icon: true
type: button
entity: switch.zone_1_enable
icon: mdi:toggle-switch-outline
show_state: false
hold_action:
action: none
- show_name: false
show_icon: true
type: button
entity: switch.zone_2_enable
icon: mdi:toggle-switch-outline
show_state: false
hold_action:
action: none
- show_name: false
show_icon: true
type: button
entity: switch.zone_3_enable
icon: mdi:toggle-switch-outline
show_state: false
hold_action:
action: none
- show_name: false
show_icon: true
type: button
entity: switch.zone_4_enable
icon: mdi:toggle-switch-outline
show_state: false
hold_action:
action: none
- show_name: false
show_icon: true
type: button
entity: switch.zone_5_enable
icon: mdi:toggle-switch-outline
show_state: false
hold_action:
action: none
- show_name: false
show_icon: true
type: button
entity: switch.zone_6_enable
icon: mdi:toggle-switch-outline
show_state: false
hold_action:
action: none
- type: horizontal-stack
cards:
- show_name: false
show_icon: false
type: button
entity: number.zone_1_duration
icon: ''
show_state: true
hold_action:
action: none
- show_name: false
show_icon: false
type: button
entity: number.zone_2_duration
icon: ''
show_state: true
hold_action:
action: none
- show_name: false
show_icon: false
type: button
entity: number.zone_3_duration
icon: ''
show_state: true
hold_action:
action: none
- show_name: false
show_icon: false
type: button
entity: number.zone_4_duration
icon: ''
show_state: true
hold_action:
action: none
- show_name: false
show_icon: false
type: button
entity: number.zone_5_duration
icon: ''
show_state: true
hold_action:
action: none
- show_name: false
show_icon: false
type: button
entity: number.zone_6_duration
icon: ''
show_state: true
hold_action:
action: none
- square: false
columns: 3
type: grid
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: call-service
service: esphome.sprinkler_previous_valve
data: {}
target: {}
icon: mdi:skip-previous
show_state: false
hold_action:
action: none
name: Previous
- show_name: true
show_icon: true
type: button
icon: mdi:stop
show_state: false
hold_action:
action: none
name: Stop
entity: switch.sprinkler_controller_stop
tap_action:
action: toggle
- show_name: true
show_icon: true
type: button
tap_action:
action: call-service
service: esphome.sprinkler_next_valve
data: {}
target: {}
icon: mdi:skip-next
show_state: false
hold_action:
action: none
name: Next
- show_name: true
show_icon: true
type: button
icon: mdi:refresh-auto
show_state: false
hold_action:
action: none
name: Full Circle
entity: switch.zones_auto_advance
- show_name: true
show_icon: true
type: button
icon: mdi:arrow-collapse-right
show_state: false
hold_action:
action: none
name: Start
entity: switch.sprinkler_controller_run
- show_name: true
show_icon: true
type: button
icon: mdi:keyboard-tab-reverse
show_state: false
hold_action:
action: none
name: Reverse
entity: switch.zones_reverse
- show_name: true
show_icon: true
type: button
icon: mdi:play-pause
show_state: false
hold_action:
action: none
name: Resume
entity: switch.sprinkler_controller_resume
- show_name: true
show_icon: true
type: button
icon: mdi:pause
show_state: false
hold_action:
action: none
name: Pause
entity: switch.sprinkler_controller_pause
- show_name: true
show_icon: true
type: button
tap_action:
action: navigate
navigation_path: /lovelace/sprinkler-control
hold_action:
action: none
icon: mdi:dots-horizontal
name: Details
- show_name: true
show_icon: true
type: button
tap_action:
action: call-service
service: esphome.sprinkler_start_single_valve
data: {}
target: {}
icon: mdi:sprinkler-variant
show_state: true
hold_action:
action: none
name: Single
- show_name: true
show_icon: true
type: button
tap_action:
action: call-service
service: esphome.sprinkler_repeat_2
data: {}
target: {}
icon: mdi:water-sync
show_state: true
hold_action:
action: none
name: 2 Cycle
- show_name: true
show_icon: true
type: button
tap_action:
action: call-service
service: esphome.sprinkler_repeat_3
data: {}
target: {}
icon: mdi:water-sync
show_state: true
hold_action:
action: none
name: 3 Cycle
- theme: Backend-selected
title: SPRINKLER Control
path: sprinkler-control
type: panel
subview: true
badges: []
cards:
- type: grid
cards:
- type: vertical-stack
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: toggle
entity: switch.zone_1
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- type: entity
entity: number.zone_1_duration
- type: entities
entities:
- entity: number.zone_1_duration
- entity: switch.zone_1_enable
state_color: true
- type: vertical-stack
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: toggle
entity: switch.zone_2
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- type: entity
entity: number.zone_2_duration
- type: entities
entities:
- entity: number.zone_2_duration
- entity: switch.zone_2_enable
state_color: true
- type: vertical-stack
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: toggle
entity: switch.zone_3
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- type: entity
entity: number.zone_3_duration
- type: entities
entities:
- entity: number.zone_3_duration
- entity: switch.zone_3_enable
state_color: true
- type: vertical-stack
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: toggle
entity: switch.zone_4
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- type: entity
entity: number.zone_4_duration
- type: entities
entities:
- entity: number.zone_4_duration
- entity: switch.zone_4_enable
state_color: true
- type: vertical-stack
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: toggle
entity: switch.zone_5
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- type: entity
entity: number.zone_5_duration
- type: entities
entities:
- entity: number.zone_5_duration
- entity: switch.zone_5_enable
state_color: true
- type: vertical-stack
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: toggle
entity: switch.zone_6
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- type: entity
entity: number.zone_6_duration
- type: entities
entities:
- entity: number.zone_6_duration
- entity: switch.zone_6_enable
state_color: true
AUTOMATION
- id: '1665523175659'
alias: Sprinkler Controller
description: ''
trigger:
- platform: state
entity_id:
- switch.sprinkler_controller_stop
to: 'on'
id: SprinklerStop
- platform: state
entity_id:
- switch.master_run_stop
from: 'on'
to: 'off'
id: EndCycle
- platform: state
entity_id:
- switch.sprinkler_controller_resume
to: 'on'
id: SprinklerResume
condition: []
action:
- if:
- condition: trigger
id: SprinklerStop
then:
- delay:
hours: 0
minutes: 0
seconds: 2
milliseconds: 0
- type: toggle
device_id: 2a2143a5268d8661b4ce50e2807dcd62
entity_id: switch.sprinkler_controller_stop
domain: switch
- if:
- condition: and
conditions:
- condition: not
conditions:
- condition: state
entity_id: sensor.sprinklers_status
state: Paused
then:
- type: toggle
device_id: 2a2143a5268d8661b4ce50e2807dcd62
entity_id: switch.sprinkler_controller_stop
domain: switch
- if:
- condition: trigger
id: SprinklerResume
then:
- type: turn_off
device_id: 2a2143a5268d8661b4ce50e2807dcd62
entity_id: switch.sprinkler_controller_pause
domain: switch
- type: turn_off
device_id: 2a2143a5268d8661b4ce50e2807dcd62
entity_id: switch.sprinkler_controller_resume
domain: switch
mode: single
I have something to fix/understand:
- when I disable a zone, if I use the Next or Previous button the zone isn’t skipped. It works if I toggle the switch. any idea where is my error?
- I would like to have to total amout cycle remaing time and if i’m running more cycles what is the actual cycle eg 2/3, 3/6, etc
- can be possible to pass the zone value with
sprinkler.start_single_valve
directly by the UI with a drop down list menu? eg. press the single button and then select which valve to control - how to use/interact with the queue (add/remove, see the queue list, etc)
I found a response for point 1
- The
next_valve
,previous_valve
andstart_single_valve
actions ignore whether a valve is enabled via its enable switch.
Not sure I can help with points 2, 3, 4 as your Yaml skills are well above mine. Nice frontend cards by the way
I found an issue with ‘resume’ myself but have not tried to fault find it. I can Pause via GUI but Resume does not work.
Yes it would be better if previous/next did check the valve enable state. Perhaps this should be raised in the ESPhome Sprinkler git issues.
For my build I probably won’t use any Repeat cycle function, as I think the Multiplier is the way I’d change a cycle.
I’m experimenting a little bit with the “challenge” n#2
UI
- theme: Backend-selected
title: Sprinkler
path: sprinkler
type: panel
badges: []
cards:
- type: vertical-stack
cards:
- type: horizontal-stack
cards:
- type: entities
entities:
- entity: sensor.sprinklers_status
icon: mdi:list-status
secondary_info: none
- entity: timer.sprinklercountdown
name: Sprinkler Countdown
secondary_info: none
- entity: sensor.zone_active_sensor
icon: mdi:map-marker-path
secondary_info: none
- entity: sensor.zone_time_remaining_sensor
icon: mdi:history
secondary_info: none
state_color: true
- type: entities
entities:
- entity: number.run_duration_multiplier
icon: mdi:chart-multiline
secondary_info: none
- entity: number.sprinkler_repeat_cycles
icon: mdi:repeat
secondary_info: none
state_color: true
- type: horizontal-stack
cards:
- show_name: true
show_icon: true
type: button
entity: switch.zone_1
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- show_name: true
show_icon: true
type: button
entity: switch.zone_2
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- show_name: true
show_icon: true
type: button
entity: switch.zone_3
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- show_name: true
show_icon: true
type: button
entity: switch.zone_4
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- show_name: true
show_icon: true
type: button
entity: switch.zone_5
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- show_name: true
show_icon: true
type: button
entity: switch.zone_6
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- type: horizontal-stack
cards:
- show_name: false
show_icon: true
type: button
entity: switch.zone_1_enable
icon: mdi:toggle-switch-outline
show_state: false
hold_action:
action: none
- show_name: false
show_icon: true
type: button
entity: switch.zone_2_enable
icon: mdi:toggle-switch-outline
show_state: false
hold_action:
action: none
- show_name: false
show_icon: true
type: button
entity: switch.zone_3_enable
icon: mdi:toggle-switch-outline
show_state: false
hold_action:
action: none
- show_name: false
show_icon: true
type: button
entity: switch.zone_4_enable
icon: mdi:toggle-switch-outline
show_state: false
hold_action:
action: none
- show_name: false
show_icon: true
type: button
entity: switch.zone_5_enable
icon: mdi:toggle-switch-outline
show_state: false
hold_action:
action: none
- show_name: false
show_icon: true
type: button
entity: switch.zone_6_enable
icon: mdi:toggle-switch-outline
show_state: false
hold_action:
action: none
- type: horizontal-stack
cards:
- show_name: false
show_icon: false
type: button
entity: number.zone_1_duration
icon: ''
show_state: true
hold_action:
action: none
- show_name: false
show_icon: false
type: button
entity: number.zone_2_duration
icon: ''
show_state: true
hold_action:
action: none
- show_name: false
show_icon: false
type: button
entity: number.zone_3_duration
icon: ''
show_state: true
hold_action:
action: none
- show_name: false
show_icon: false
type: button
entity: number.zone_4_duration
icon: ''
show_state: true
hold_action:
action: none
- show_name: false
show_icon: false
type: button
entity: number.zone_5_duration
icon: ''
show_state: true
hold_action:
action: none
- show_name: false
show_icon: false
type: button
entity: number.zone_6_duration
icon: ''
show_state: true
hold_action:
action: none
- square: false
columns: 3
type: grid
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: call-service
service: esphome.sprinkler_previous_valve
data: {}
target: {}
icon: mdi:skip-previous
show_state: false
hold_action:
action: none
name: Previous
- show_name: true
show_icon: true
type: button
icon: mdi:stop
show_state: false
hold_action:
action: none
name: Stop
entity: switch.sprinkler_controller_stop
tap_action:
action: toggle
- show_name: true
show_icon: true
type: button
tap_action:
action: call-service
service: esphome.sprinkler_next_valve
data: {}
target: {}
icon: mdi:skip-next
show_state: false
hold_action:
action: none
name: Next
- show_name: true
show_icon: true
type: button
icon: mdi:refresh-auto
show_state: false
hold_action:
action: none
name: Full Circle
entity: switch.zones_auto_advance
- show_name: true
show_icon: true
type: button
icon: mdi:arrow-collapse-right
show_state: false
hold_action:
action: none
name: Start
entity: switch.sprinkler_controller_run
- show_name: true
show_icon: true
type: button
icon: mdi:keyboard-tab-reverse
show_state: false
hold_action:
action: none
name: Reverse
entity: switch.zones_reverse
- show_name: true
show_icon: true
type: button
icon: mdi:play-pause
show_state: false
hold_action:
action: none
name: Resume
entity: switch.sprinkler_controller_resume
- show_name: true
show_icon: true
type: button
icon: mdi:pause
show_state: false
hold_action:
action: none
name: Pause
entity: switch.sprinkler_controller_pause
- show_name: true
show_icon: true
type: button
tap_action:
action: navigate
navigation_path: /lovelace/sprinkler-control
hold_action:
action: none
icon: mdi:dots-horizontal
name: Details
- show_name: true
show_icon: true
type: button
tap_action:
action: call-service
service: esphome.sprinkler_start_single_valve
data: {}
target: {}
icon: mdi:sprinkler-variant
show_state: true
hold_action:
action: none
name: Single
- show_name: true
show_icon: true
type: button
tap_action:
action: call-service
service: esphome.sprinkler_repeat_2
data: {}
target: {}
icon: mdi:water-sync
show_state: true
hold_action:
action: none
name: 2 Cycle
- show_name: true
show_icon: true
type: button
tap_action:
action: call-service
service: esphome.sprinkler_repeat_3
data: {}
target: {}
icon: mdi:water-sync
show_state: true
hold_action:
action: none
name: 3 Cycle
- theme: Backend-selected
title: SPRINKLER Control
path: sprinkler-control
type: panel
subview: true
badges: []
cards:
- type: grid
cards:
- type: vertical-stack
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: toggle
entity: switch.zone_1
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- type: entity
entity: number.zone_1_duration
- type: entities
entities:
- entity: number.zone_1_duration
- entity: switch.zone_1_enable
state_color: true
- type: vertical-stack
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: toggle
entity: switch.zone_2
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- type: entity
entity: number.zone_2_duration
- type: entities
entities:
- entity: number.zone_2_duration
- entity: switch.zone_2_enable
state_color: true
- type: vertical-stack
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: toggle
entity: switch.zone_3
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- type: entity
entity: number.zone_3_duration
- type: entities
entities:
- entity: number.zone_3_duration
- entity: switch.zone_3_enable
state_color: true
- type: vertical-stack
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: toggle
entity: switch.zone_4
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- type: entity
entity: number.zone_4_duration
- type: entities
entities:
- entity: number.zone_4_duration
- entity: switch.zone_4_enable
state_color: true
- type: vertical-stack
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: toggle
entity: switch.zone_5
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- type: entity
entity: number.zone_5_duration
- type: entities
entities:
- entity: number.zone_5_duration
- entity: switch.zone_5_enable
state_color: true
- type: vertical-stack
cards:
- show_name: true
show_icon: true
type: button
tap_action:
action: toggle
entity: switch.zone_6
icon: mdi:sprinkler
show_state: false
hold_action:
action: none
- type: entity
entity: number.zone_6_duration
- type: entities
entities:
- entity: number.zone_6_duration
- entity: switch.zone_6_enable
state_color: true
AUTOMATION
- id: '1665523175659'
alias: Sprinkler Controller
description: ''
trigger:
- platform: state
entity_id:
- switch.sprinkler_controller_stop
to: 'on'
id: SprinklerStop
from: 'off'
- platform: state
entity_id:
- switch.master_run_stop
from: 'on'
to: 'off'
id: EndCycle
- platform: state
entity_id:
- switch.sprinkler_controller_resume
to: 'on'
id: SprinklerResume
- platform: state
entity_id:
- switch.sprinkler_controller_run
to: 'on'
id: Sprinkler Controller Start
from: 'off'
- platform: state
entity_id:
- switch.sprinkler_controller_pause
id: Sprinkler Controller Pause
from: 'off'
to: 'on'
condition: []
action:
- choose:
- conditions:
- condition: trigger
id: SprinklerStop
sequence:
- delay:
hours: 0
minutes: 0
seconds: 2
milliseconds: 0
- type: toggle
device_id: 2a2143a5268d8661b4ce50e2807dcd62
entity_id: switch.sprinkler_controller_stop
domain: switch
- service: timer.finish
data: {}
target:
entity_id: timer.sprinklercountdown
- conditions:
- condition: trigger
id: EndCycle
- condition: and
conditions:
- condition: not
conditions:
- condition: state
entity_id: sensor.sprinklers_status
state: Paused
sequence:
- type: toggle
device_id: 2a2143a5268d8661b4ce50e2807dcd62
entity_id: switch.sprinkler_controller_stop
domain: switch
- conditions:
- condition: trigger
id: SprinklerResume
sequence:
- type: turn_off
device_id: 2a2143a5268d8661b4ce50e2807dcd62
entity_id: switch.sprinkler_controller_pause
domain: switch
- type: turn_off
device_id: 2a2143a5268d8661b4ce50e2807dcd62
entity_id: switch.sprinkler_controller_resume
domain: switch
- service: timer.start
data: {}
target:
entity_id: timer.sprinklercountdown
- conditions:
- condition: trigger
id: Sprinkler Controller Start
sequence:
- service: timer.start
data:
duration: '{{ ( (states(''number.zone_1_duration'')|int*60)+ (states(''number.zone_2_duration'')|int*60)+
(states(''number.zone_3_duration'')|int*60)+ (states(''number.zone_4_duration'')|int*60)+
(states(''number.zone_5_duration'')|int*60)+ (states(''number.zone_5_duration'')|int*60)
) | timestamp_custom("%H:%M:%S", 0) }}'
target:
entity_id: timer.sprinklercountdown
- conditions:
- condition: trigger
id: Sprinkler Controller Pause
sequence:
- service: timer.pause
data: {}
target:
entity_id: timer.sprinklercountdown
alias: SprinklerChoices
mode: single
Cool. Nothing quite so interesting here. Installed the four physical buttons on the box lid and configured ESPhome to read them. Working fine. Now to do something useful with them.
(also adding a power input fuse to the box from the 24V AC transformer)
thank you @mr.sneezy , as you are some “steps” ahead me… shall you share how you wired the buttons and how configured the inputs?
I will try my best to get to the same page:D
I added four buttons using normally open momentary switches I had in my parts box. Kinconys diagram shows how to wire them. I picked I2C I/O hub inputs 5-8 because they were close to the ground pin which needs to be connected to one side of each button. You could use 1-4 etc to be more logical.
Here is a closer image of the wiring as seen on the circuit board showing the 5 wires to the I2C I/O hub inputs.
Here’s a image of the back of the buttons in case it helps, really nothing to see though.
I’ve added a small inline fuse and holder to the main 24V AC input, as the transformer has none. It’s to protect the transformer if a valve cable in the garden is damged (shorted).
Like the LCD mount and the button mount, it’s 3D printed on my old but reliable Prusa i3 clone.
Code associated with the buttons for testing them. Results are seen in the ESPhome logs live view after flashing if you don’t have the LCD…
# I2C bus config
i2c:
sda: 4
scl: 5
scan: true
id: bus_a
# I2C I/O expander config
pcf8574:
- id: 'pcf8574_output_hub'
address: 0x24
pcf8575: false
- id: 'pcf8574_input_hub'
address: 0x22
binary_sensor:
- platform: gpio
id: button_1 #push button on front of controller enclosure
pin:
pcf8574: pcf8574_input_hub
# Use pin number 4 (starting at 0)
number: 4
# One of INPUT or OUTPUT
mode:
input: true
inverted: true
internal: true
on_click:
- min_length: 50ms
max_length: 350ms
then:
- sprinkler.resume_or_start_full_cycle: esp32_sprinkler_ctrlr
- platform: gpio
id: button_2 #push button on front of controller enclosure
pin:
pcf8574: pcf8574_input_hub
# Use pin number 5 (starting at 0)
number: 5
# One of INPUT or OUTPUT
mode:
input: true
inverted: true
internal: true
on_click:
- min_length: 50ms
max_length: 350ms
then:
- sprinkler.next_valve: esp32_sprinkler_ctrlr
- platform: gpio
id: button_3 #push button on front of controller enclosure
pin:
pcf8574: pcf8574_input_hub
# Use pin number 6 (starting at 0)
number: 6
# One of INPUT or OUTPUT
mode:
input: true
inverted: true
internal: true
on_click:
- min_length: 50ms
max_length: 350ms
then:
- sprinkler.previous_valve: esp32_sprinkler_ctrlr
- platform: gpio
id: button_4 #push button on front of controller enclosure
pin:
pcf8574: pcf8574_input_hub
# Use pin number 7 (starting at 0)
number: 7
# One of INPUT or OUTPUT
mode:
input: true
inverted: true
internal: true
on_click:
- min_length: 50ms
max_length: 350ms
then:
- sprinkler.pause: esp32_sprinkler_ctrlr
- min_length: 500ms
max_length: 2000ms
then:
- sprinkler.shutdown: esp32_sprinkler_ctrlr
Now that the buttons do useful stuff, I need to show that on the LCD (i.e paused status).
The paused valve number apparently is available internally form what I see on Github references, but I will need to make my LCD cases more complex or rethink that method…
paused_valve()
This is awesome! I just finished a basic irrigation controller 4 or 5 months before they introduced the sprinkler component but, doing it over had been on my to do list. Reading through the docs, I’ve been excitedl to take on this challenge and thanks to your awesome post I’ll have something to look st for help. Thank you for taking your time and sharing this with us! I appreciate this very much!
@mr.sneezy , I did something to simplify (I guess) the code for the SWITCH portion; this should safe a lot of rows…, let me know what do you think
lambda: |-
switch (id(esp32_sprinkler_ctrlr).active_valve().value_or(-1)) {
case -1:
it.strftime(0, 0, "%a", id(homeassistant_time).now());
it.strftime(10, 0, "%d-%m-%Y", id(homeassistant_time).now());
it.strftime(12, 1,"%H:%M:%S", id(homeassistant_time).now());
it.printf(0, 3, "Status: %s", id(esp32_sprinkler_ctrlr_status).state.c_str());
if (id(esp32_sprinkler_ctrlr_status).state == "Paused") {
it.printf(0, 2, "Zone %s", id(zone_active_sensor).state.c_str());
it.printf(10, 2, "T: %s", id(zone_time_remaining_sensor).state.c_str());
}
break;
default:
it.printf(0, 0, "Zone %s:", id(zone_active_sensor).state.c_str());
it.printf(8, 0, "%s", id(zone_active_sensor).state.c_str() ? "ON" : "OFF");
it.printf(0, 1, "Time Letf: %s", id(zone_time_remaining_sensor).state.c_str());
break;
}
I also made the LCD “dimmable” following these instructions from @LUNZ
[Dimmable PCF8574 LCD Display with ESPHome]
(Dimmable PCF8574 LCD Display with ESPHome)
here is the full code, just in case
# Establish Substitutions
substitutions:
device_name: sprinkler
friendly_name: "Sprinkler"
device_platform: ESP32
device_board: esp32dev
device_ip: X.X.X.X
sensor_update_frequency: 1s
sprinkler_name: esp32_sprinkler_ctrlr
packages:
wifi: !include common/device_wifi.yaml
device_base: !include common/device_base_ESP32.yaml
home_assistant_api: !include common/device_api.yaml
sensor_wifi_ip_address: !include common/sensor_wifi_ip_address.yaml
# Enable logging
logger:
###################################################################################################
##### I/O expander hub definition
###################################################################################################
mcp23017:
- id: 'mcp23017_hub'
address: 0x20
#nodemcu devkit v4.0
i2c:
sda: 21
scl: 22
scan: True
frequency: 200kHz
###################################################################################################
# 10x4 LCD config
display:
- platform: lcd_pcf8574
dimensions: 20x4
address: 0x27
update_interval: 1s
lambda: |-
switch (id(esp32_sprinkler_ctrlr).active_valve().value_or(-1)) {
case -1:
it.strftime(0, 0, "%a", id(homeassistant_time).now());
it.strftime(10, 0, "%d-%m-%Y", id(homeassistant_time).now());
it.strftime(12, 1,"%H:%M:%S", id(homeassistant_time).now());
it.printf(0, 3, "Status: %s", id(esp32_sprinkler_ctrlr_status).state.c_str());
if (id(esp32_sprinkler_ctrlr_status).state == "Paused") {
it.printf(0, 2, "Zone %s", id(zone_active_sensor).state.c_str());
it.printf(10, 2, "T: %s", id(zone_time_remaining_sensor).state.c_str());
}
break;
default:
it.printf(0, 0, "Zone %s:", id(zone_active_sensor).state.c_str());
it.printf(8, 0, "%s", id(zone_active_sensor).state.c_str() ? "ON" : "OFF");
it.printf(0, 1, "Time Letf: %s", id(zone_time_remaining_sensor).state.c_str());
break;
}
output:
- platform: ledc
pin: GPIO14
id: sprinkler_backlight
light:
- platform: monochromatic
output: sprinkler_backlight
name: "LCD Display Sprinkler Backlight"
id: light_backlight
restore_mode: ALWAYS_ON
###################################################################################################
###################################################################################################
# Enable Home Assistant APIs
api:
reboot_timeout: 0s
services:
- service: set_multiplier
variables:
multiplier: float
then:
- sprinkler.set_multiplier:
id: esp32_sprinkler_ctrlr
multiplier: !lambda 'return multiplier;'
- service: start_full_cycle
then:
- sprinkler.start_full_cycle: esp32_sprinkler_ctrlr
- service: start_single_valve
variables:
valve: int
then:
- sprinkler.start_single_valve:
id: esp32_sprinkler_ctrlr
valve_number: !lambda 'return valve;'
- service: next_valve
then:
- sprinkler.next_valve: esp32_sprinkler_ctrlr
- service: previous_valve
then:
- sprinkler.previous_valve: esp32_sprinkler_ctrlr
- service: shutdown
then:
- sprinkler.shutdown: esp32_sprinkler_ctrlr
- service: pause
then:
- sprinkler.pause: esp32_sprinkler_ctrlr
- service: resume
then:
- sprinkler.resume: esp32_sprinkler_ctrlr
- service: resume_or_full_cycle
then:
- sprinkler.resume_or_start_full_cycle: esp32_sprinkler_ctrlr
- service: repeat_2
then:
- sprinkler.set_repeat:
id: esp32_sprinkler_ctrlr
repeat: 2 # would run three cycles
- service: repeat_3
then:
- sprinkler.set_repeat:
id: esp32_sprinkler_ctrlr
repeat: 3 # would run three cycles
# Main sprinkler code
sprinkler:
- id: esp32_sprinkler_ctrlr
main_switch: "Master Run/Stop"
auto_advance_switch: "Zones Auto Advance"
reverse_switch: "Zones Reverse"
valve_open_delay: 2s
valves:
- valve_switch: "Zone 1"
enable_switch: "Zone 1 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw1
- valve_switch: "Zone 2"
enable_switch: "Zone 2 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw2
- valve_switch: "Zone 3"
enable_switch: "Zone 3 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw3
- valve_switch: "Zone 4"
enable_switch: "Zone 4 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw4
- valve_switch: "Zone 5"
enable_switch: "Zone 5 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw5
- valve_switch: "Zone 6"
enable_switch: "Zone 6 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw6
# Valve control outputs config via I/O expander
switch:
#################################################################################################
####### CONTROL SWITCH
#################################################################################################
- platform: template
id: esp32_sprinkler_ctrlr_run
name: "Sprinkler Controller Run"
optimistic: true
on_turn_on:
- text_sensor.template.publish:
id: esp32_sprinkler_ctrlr_status
state: "Running"
- sprinkler.resume_or_start_full_cycle: esp32_sprinkler_ctrlr
- switch.turn_off: esp32_sprinkler_ctrlr_pause
- switch.turn_off: esp32_sprinkler_ctrlr_stop
- platform: template
id: esp32_sprinkler_ctrlr_stop
name: "Sprinkler Controller Stop"
optimistic: true
on_turn_on:
- text_sensor.template.publish:
id: esp32_sprinkler_ctrlr_status
state: "Stopped"
- sprinkler.shutdown: esp32_sprinkler_ctrlr
- switch.turn_off: esp32_sprinkler_ctrlr_pause
- switch.turn_off: esp32_sprinkler_ctrlr_run
- platform: template
id: esp32_sprinkler_ctrlr_pause
name: "Sprinkler Controller Pause"
optimistic: true
turn_on_action:
- delay: 500ms
- lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state != "Running")
{
id(esp32_sprinkler_ctrlr_pause).turn_off();
}
- lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state == "Running")
{
id(esp32_sprinkler_ctrlr_status).publish_state("Paused");
id(esp32_sprinkler_ctrlr).pause();
}
on_turn_off:
lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state == "Paused")
{
id(esp32_sprinkler_ctrlr_status).publish_state("Running");
id(esp32_sprinkler_ctrlr).resume();
}
- platform: template
id: esp32_sprinkler_ctrlr_resume
name: "Sprinkler Controller Resume"
optimistic: true
#################################################################################################
####### I/0 SWITCH
#################################################################################################
- platform: gpio
id: zone_valve_sw1
name: "MCP23017 Pin B2"
pin:
mcp23xxx: mcp23017_hub
# Use pin B2
number: 10
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw2
name: "MCP23017 Pin B3"
pin:
mcp23xxx: mcp23017_hub
# Use pin B3
number: 11
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw3
name: "MCP23017 Pin B4"
pin:
mcp23xxx: mcp23017_hub
# Use pin B4
number: 12
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw4
name: "MCP23017 Pin B5"
pin:
mcp23xxx: mcp23017_hub
# Use pin B5
number: 13
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw5
name: "MCP23017 Pin B6"
pin:
mcp23xxx: mcp23017_hub
# Use pin B6
number: 14
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw6
name: "MCP23017 Pin B7"
pin:
mcp23xxx: mcp23017_hub
# Use pin B7
number: 15
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
#- platform: template #this switch doesn't work properly. Can pause via HA frontend, but will not resume... Via Services does work...
# id: pause_switch
# name: "Pause Irrigation Switch"
# turn_on_action:
# then:
# - sprinkler.pause: esp32_sprinkler_ctrlr
# turn_off_action:
# then:
# - sprinkler.resume: esp32_sprinkler_ctrlr
number:
# Configuration to set multiplier via number
- platform: template
id: sprinkler_ctrlr_multiplier
name: "Run Duration Multiplier"
min_value: 1.0
max_value: 3.0
step: 0.1
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).multiplier();"
set_action:
- sprinkler.set_multiplier:
id: esp32_sprinkler_ctrlr
multiplier: !lambda 'return x;'
# Configure repeat
- platform: template
id: sprinkler_ctrlr_repeat_cycles
name: "Sprinkler Repeat Cycles"
min_value: 0
max_value: 300
step: 1
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).repeat();"
set_action:
- sprinkler.set_repeat:
id: esp32_sprinkler_ctrlr
repeat: !lambda 'return x;'
# Configuration to set valve run duration via number
- platform: template
id: sprinkler_valve_1_duration
name: "Zone 1 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: $sensor_update_frequency
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(0) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 0
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_2_duration
name: "Zone 2 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: $sensor_update_frequency
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(1) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 1
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_3_duration
name: "Zone 3 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: $sensor_update_frequency
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(2) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 2
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_4_duration
name: "Zone 4 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: $sensor_update_frequency
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(3) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 3
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_5_duration
name: "Zone 5 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: $sensor_update_frequency
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(4) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 4
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_6_duration
name: "Zone 6 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: $sensor_update_frequency
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(5) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 5
run_duration: !lambda "return x * 60;"
sensor:
### SENSORS
- platform: template
name: "Cycle Total Time Sensor"
icon: mdi:progress-clock
unit_of_measurement: 'Min'
accuracy_decimals: 0
update_interval: $sensor_update_frequency
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(0)/60 + id(esp32_sprinkler_ctrlr).valve_run_duration(1)/60;"
#lambda: |-
# {% set ns = namespace(states=[]) %}
# {% for s in states.sensor %}
# {% if s.object_id.startswith('valve_run_') and s.object_id.endswith('_duration') %}
# {% set ns.states = ns.states + [ s.state | float ] %}
# {% endif %}
# {% endfor %}
# {{ ns.states | sum | round(2) }}
# - platform: template
# name: "Zone Active Sensor"
# id: zone_active_sensor
# unit_of_measurement: ''
# accuracy_decimals: 0
# #Valves are numbered from 0-7 internally which is an issue when displaying !
# lambda: |-
# if(id(esp32_sprinkler_ctrlr_status).state == "Stopped")
# {
# return id(esp32_sprinkler_ctrlr).active_valve().value_or(NAN);
# }
# else
# {
# return id(esp32_sprinkler_ctrlr).active_valve().value_or(NAN) + 1;
# }
# update_interval: $sensor_update_frequency
- platform: homeassistant
id: homeassistant_sprinklercountdown
entity_id: timer.sprinklercountdown
internal: false
text_sensor:
- platform: template
id: esp32_sprinkler_ctrlr_status
name: "Sprinklers Status"
update_interval: $sensor_update_frequency
- platform: template
name: "Zone Active Sensor"
id: zone_active_sensor
#unit_of_measurement: ''
#accuracy_decimals: 0
#Valves are numbered from 0-7 internally which is an issue when displaying !
lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state == "Stopped")
{
int zone_active = id(esp32_sprinkler_ctrlr).active_valve().value_or(NAN);
std::string zone_active_as_string = esphome::to_string(zone_active);
return zone_active_as_string;
}
else
{
int zone_active = id(esp32_sprinkler_ctrlr).active_valve().value_or(NAN) + 1;
std::string zone_active_as_string = esphome::to_string(zone_active);
return zone_active_as_string;
}
update_interval: $sensor_update_frequency
# # Expose Valve Progress Percent as a sensor.
- platform: template
id: progress_percent_valve
name: "Zone Progress"
#unit_of_measurement: '%'
#accuracy_decimals: 0
update_interval: $sensor_update_frequency
icon: "mdi:progress-clock"
lambda: |-
int valve_progress_percent = round(((id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(id(esp32_sprinkler_ctrlr).active_valve().value_or(0)) - id(esp32_sprinkler_ctrlr).time_remaining().value_or(0)) * 100 / id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(id(esp32_sprinkler_ctrlr).active_valve().value_or(0))));
std::string valve_progress_percent_as_string = esphome::to_string(valve_progress_percent);
return valve_progress_percent_as_string;
# # Expose Zone Time Remaining
- platform: template
name: "Zone Time Remaining Sensor"
id: zone_time_remaining_sensor
icon: mdi:progress-clock
#unit_of_measurement: 'Min'
#accuracy_decimals: 0
update_interval: $sensor_update_frequency
lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state != "Paused")
{
int seconds = round(id(esp32_sprinkler_ctrlr).time_remaining().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()};
}
else
{
return {};
}
### Input to managet the display backlight
- platform: homeassistant
id: display_sprinkler_backlight
entity_id: input_number.sprinklerbacklightlevel
internal: true
on_value:
then:
- output.turn_on: sprinkler_backlight
- output.set_level:
id: sprinkler_backlight
level: !lambda |-
return atoi(id(display_sprinkler_backlight).state.c_str()) / 100.0;
# Time source config
time:
- platform: homeassistant
id: homeassistant_time
timezone: Europe/Rome
@mr.sneezy Very nice implementation of your ESPHome based irrigation system. I have an old RainMachine that is about to die and their replacement is both expensive and old so I think I will build my own. One thing I was curious about your setup is how the time is tracked as I did not see any reference to an RTC on the board. Did you add one? Or is time completely dependent on HA which may be an issue in case the system needs to operate on its own for some time.
I didn’t worry about RTC until it proves necessary yet. So far the network time has been reliable so the watering has been reliable.
Oddly enough I did another recent small project for somebody else that uses a $5 RTC module on an ESP32. I used this one below, but it needed four pull up resistors removed to make the SDA and SCL lines 3.3V compatible. As this module is I2C driven it should be not hard to add to the 8ch relay board in parallel with the LCD if I need too.
RTC Clock & EEPROM Module, I2C, DS1307, AT24C32 - 99Tech
Hi,
Great work. I am looking for a solution where the controller can connect to Home Assistant via ie. ethernet. I see this board has ethernet connector. Could this be connected to Home Assistant with ethernet or the eth. connector is for other purposes?
I believe so yes. ESPhome supports a good number of Ethernet chips and the one on this board is the first one they mention in the ESPhome list.
I have used Ethernet with ESPhome fine on other boards, just not this one yet.
hello, I’m trying to build an automatic watering system based on slightly modified your code, unfortunately I keep getting the error “class esphome: :sprinkler : :Sprinkler:” has no member named “time_remaining”. Do you know what could be causing this?
My YAML
# Establish Substitutions
substitutions:
device_name: sprinkler
friendly_name: "Sprinkler"
device_platform: ESP32
device_board: esp32dev
sensor_update_frequency: 1s
sprinkler_name: esp32_sprinkler_ctrlr
esphome:
name: sprinkler
friendly_name: Sprinkler
esp32:
board: esp32dev
framework:
type: arduino
# Enable logging
logger:
###################################################################################################
##### I/O expander hub definition
###################################################################################################
mcp23017:
- id: 'mcp23017_hub'
address: 0x26
#nodemcu devkit v4.0
i2c:
sda: 33
scl: 32
scan: True
frequency: 400kHz
ethernet:
type: LAN8720
mdc_pin: GPIO23
mdio_pin: GPIO18
clk_mode: GPIO17_OUT
phy_addr: 0
power_pin: GPIO4
###################################################################################################
# 10x4 LCD config
display:
- platform: lcd_pcf8574
dimensions: 20x4
address: 0x27
update_interval: 1s
lambda: |-
switch (id(esp32_sprinkler_ctrlr).active_valve().value_or(-1)) {
case -1:
it.strftime(0, 0, "%a", id(homeassistant_time).now());
it.strftime(10, 0, "%d-%m-%Y", id(homeassistant_time).now());
it.strftime(12, 1,"%H:%M:%S", id(homeassistant_time).now());
it.printf(0, 3, "Status: %s", id(esp32_sprinkler_ctrlr_status).state.c_str());
if (id(esp32_sprinkler_ctrlr_status).state == "Paused") {
it.printf(0, 2, "Zone %s", id(zone_active_sensor).state.c_str());
it.printf(10, 2, "T: %s", id(zone_time_remaining_sensor).state.c_str());
}
break;
default:
it.printf(0, 0, "Zone %s:", id(zone_active_sensor).state.c_str());
it.printf(8, 0, "%s", id(zone_active_sensor).state.c_str() ? "ON" : "OFF");
it.printf(0, 1, "Time Letf: %s", id(zone_time_remaining_sensor).state.c_str());
break;
}
output:
- platform: ledc
pin: GPIO14
id: sprinkler_backlight
light:
- platform: monochromatic
output: sprinkler_backlight
name: "LCD Display Sprinkler Backlight"
id: light_backlight
restore_mode: ALWAYS_ON
###################################################################################################
###################################################################################################
# Enable Home Assistant APIs
api:
reboot_timeout: 0s
encryption:
key: "FkNGBbOhmbWTgfvvZuVbM51UuFlb4EIb+dFi7whRA/g="
services:
- service: set_multiplier
variables:
multiplier: float
then:
- sprinkler.set_multiplier:
id: esp32_sprinkler_ctrlr
multiplier: !lambda 'return multiplier;'
- service: start_full_cycle
then:
- sprinkler.start_full_cycle: esp32_sprinkler_ctrlr
- service: start_single_valve
variables:
valve: int
then:
- sprinkler.start_single_valve:
id: esp32_sprinkler_ctrlr
valve_number: !lambda 'return valve;'
- service: next_valve
then:
- sprinkler.next_valve: esp32_sprinkler_ctrlr
- service: previous_valve
then:
- sprinkler.previous_valve: esp32_sprinkler_ctrlr
- service: shutdown
then:
- sprinkler.shutdown: esp32_sprinkler_ctrlr
- service: pause
then:
- sprinkler.pause: esp32_sprinkler_ctrlr
- service: resume
then:
- sprinkler.resume: esp32_sprinkler_ctrlr
- service: resume_or_full_cycle
then:
- sprinkler.resume_or_start_full_cycle: esp32_sprinkler_ctrlr
- service: repeat_2
then:
- sprinkler.set_repeat:
id: esp32_sprinkler_ctrlr
repeat: 2 # would run three cycles
- service: repeat_3
then:
- sprinkler.set_repeat:
id: esp32_sprinkler_ctrlr
repeat: 3 # would run three cycles
ota:
password: "7001db87bfa399a3e551f7206250c3dd"
# Main sprinkler code
sprinkler:
- id: esp32_sprinkler_ctrlr
main_switch: "Master Run/Stop"
auto_advance_switch: "Zones Auto Advance"
reverse_switch: "Zones Reverse"
valve_open_delay: 2s
valves:
- valve_switch: "Zone 1"
enable_switch: "Zone 1 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw1
- valve_switch: "Zone 2"
enable_switch: "Zone 2 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw2
- valve_switch: "Zone 3"
enable_switch: "Zone 3 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw3
- valve_switch: "Zone 4"
enable_switch: "Zone 4 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw4
- valve_switch: "Zone 5"
enable_switch: "Zone 5 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw5
- valve_switch: "Zone 6"
enable_switch: "Zone 6 Enable"
run_duration: 900s
valve_switch_id: zone_valve_sw6
# Valve control outputs config via I/O expander
switch:
#################################################################################################
####### CONTROL SWITCH
#################################################################################################
- platform: template
id: esp32_sprinkler_ctrlr_run
name: "Sprinkler Controller Run"
optimistic: true
on_turn_on:
- text_sensor.template.publish:
id: esp32_sprinkler_ctrlr_status
state: "Running"
- sprinkler.resume_or_start_full_cycle: esp32_sprinkler_ctrlr
- switch.turn_off: esp32_sprinkler_ctrlr_pause
- switch.turn_off: esp32_sprinkler_ctrlr_stop
- platform: template
id: esp32_sprinkler_ctrlr_stop
name: "Sprinkler Controller Stop"
optimistic: true
on_turn_on:
- text_sensor.template.publish:
id: esp32_sprinkler_ctrlr_status
state: "Stopped"
- sprinkler.shutdown: esp32_sprinkler_ctrlr
- switch.turn_off: esp32_sprinkler_ctrlr_pause
- switch.turn_off: esp32_sprinkler_ctrlr_run
- platform: template
id: esp32_sprinkler_ctrlr_pause
name: "Sprinkler Controller Pause"
optimistic: true
turn_on_action:
- delay: 500ms
- lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state != "Running")
{
id(esp32_sprinkler_ctrlr_pause).turn_off();
}
- lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state == "Running")
{
id(esp32_sprinkler_ctrlr_status).publish_state("Paused");
id(esp32_sprinkler_ctrlr).pause();
}
on_turn_off:
lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state == "Paused")
{
id(esp32_sprinkler_ctrlr_status).publish_state("Running");
id(esp32_sprinkler_ctrlr).resume();
}
- platform: template
id: esp32_sprinkler_ctrlr_resume
name: "Sprinkler Controller Resume"
optimistic: true
#################################################################################################
####### I/0 SWITCH
#################################################################################################
- platform: gpio
id: zone_valve_sw1
name: "MCP23017 Pin B2"
pin:
mcp23xxx: mcp23017_hub
# Use pin B2
number: 10
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw2
name: "MCP23017 Pin B3"
pin:
mcp23xxx: mcp23017_hub
# Use pin B3
number: 11
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw3
name: "MCP23017 Pin B4"
pin:
mcp23xxx: mcp23017_hub
# Use pin B4
number: 12
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw4
name: "MCP23017 Pin B5"
pin:
mcp23xxx: mcp23017_hub
# Use pin B5
number: 13
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw5
name: "MCP23017 Pin B6"
pin:
mcp23xxx: mcp23017_hub
# Use pin B6
number: 14
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
- platform: gpio
id: zone_valve_sw6
name: "MCP23017 Pin B7"
pin:
mcp23xxx: mcp23017_hub
# Use pin B7
number: 15
# One of INPUT or OUTPUT
mode:
output: true
inverted: true
internal: true
#- platform: template #this switch doesn't work properly. Can pause via HA frontend, but will not resume... Via Services does work...
# id: pause_switch
# name: "Pause Irrigation Switch"
# turn_on_action:
# then:
# - sprinkler.pause: esp32_sprinkler_ctrlr
# turn_off_action:
# then:
# - sprinkler.resume: esp32_sprinkler_ctrlr
number:
# Configuration to set multiplier via number
- platform: template
id: sprinkler_ctrlr_multiplier
name: "Run Duration Multiplier"
min_value: 1.0
max_value: 3.0
step: 0.1
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).multiplier();"
set_action:
- sprinkler.set_multiplier:
id: esp32_sprinkler_ctrlr
multiplier: !lambda 'return x;'
# Configure repeat
- platform: template
id: sprinkler_ctrlr_repeat_cycles
name: "Sprinkler Repeat Cycles"
min_value: 0
max_value: 300
step: 1
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).repeat();"
set_action:
- sprinkler.set_repeat:
id: esp32_sprinkler_ctrlr
repeat: !lambda 'return x;'
# Configuration to set valve run duration via number
- platform: template
id: sprinkler_valve_1_duration
name: "Zone 1 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: $sensor_update_frequency
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(0) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 0
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_2_duration
name: "Zone 2 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: $sensor_update_frequency
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(1) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 1
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_3_duration
name: "Zone 3 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: $sensor_update_frequency
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(2) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 2
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_4_duration
name: "Zone 4 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: $sensor_update_frequency
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(3) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 3
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_5_duration
name: "Zone 5 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: $sensor_update_frequency
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(4) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 4
run_duration: !lambda "return x * 60;"
- platform: template
id: sprinkler_valve_6_duration
name: "Zone 6 Duration"
icon: mdi:timer
unit_of_measurement: Min
min_value: 1
max_value: 120
step: 1.0
update_interval: $sensor_update_frequency
mode: box
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(5) / 60;"
set_action:
- sprinkler.set_valve_run_duration:
id: esp32_sprinkler_ctrlr
valve_number: 5
run_duration: !lambda "return x * 60;"
sensor:
### SENSORS
- platform: template
name: "Cycle Total Time Sensor"
icon: mdi:progress-clock
unit_of_measurement: 'Min'
accuracy_decimals: 0
update_interval: $sensor_update_frequency
lambda: "return id(esp32_sprinkler_ctrlr).valve_run_duration(0)/60 + id(esp32_sprinkler_ctrlr).valve_run_duration(1)/60;"
#lambda: |-
# {% set ns = namespace(states=[]) %}
# {% for s in states.sensor %}
# {% if s.object_id.startswith('valve_run_') and s.object_id.endswith('_duration') %}
# {% set ns.states = ns.states + [ s.state | float ] %}
# {% endif %}
# {% endfor %}
# {{ ns.states | sum | round(2) }}
# - platform: template
# name: "Zone Active Sensor"
# id: zone_active_sensor
# unit_of_measurement: ''
# accuracy_decimals: 0
# #Valves are numbered from 0-7 internally which is an issue when displaying !
# lambda: |-
# if(id(esp32_sprinkler_ctrlr_status).state == "Stopped")
# {
# return id(esp32_sprinkler_ctrlr).active_valve().value_or(NAN);
# }
# else
# {
# return id(esp32_sprinkler_ctrlr).active_valve().value_or(NAN) + 1;
# }
# update_interval: $sensor_update_frequency
- platform: homeassistant
id: homeassistant_sprinklercountdown
entity_id: timer.sprinklercountdown
internal: false
text_sensor:
- platform: template
id: esp32_sprinkler_ctrlr_status
name: "Sprinklers Status"
update_interval: $sensor_update_frequency
- platform: template
name: "Zone Active Sensor"
id: zone_active_sensor
#unit_of_measurement: ''
#accuracy_decimals: 0
#Valves are numbered from 0-7 internally which is an issue when displaying !
lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state == "Stopped")
{
int zone_active = id(esp32_sprinkler_ctrlr).active_valve().value_or(NAN);
std::string zone_active_as_string = esphome::to_string(zone_active);
return zone_active_as_string;
}
else
{
int zone_active = id(esp32_sprinkler_ctrlr).active_valve().value_or(NAN) + 1;
std::string zone_active_as_string = esphome::to_string(zone_active);
return zone_active_as_string;
}
update_interval: $sensor_update_frequency
# # Expose Valve Progress Percent as a sensor.
- platform: template
id: progress_percent_valve
name: "Zone Progress"
#unit_of_measurement: '%'
#accuracy_decimals: 0
update_interval: $sensor_update_frequency
icon: "mdi:progress-clock"
lambda: |-
int valve_progress_percent = round(((id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(id(esp32_sprinkler_ctrlr).active_valve().value_or(0)) - id(esp32_sprinkler_ctrlr).time_remaining().value_or(0)) * 100 / id(esp32_sprinkler_ctrlr).valve_run_duration_adjusted(id(esp32_sprinkler_ctrlr).active_valve().value_or(0))));
std::string valve_progress_percent_as_string = esphome::to_string(valve_progress_percent);
return valve_progress_percent_as_string;
# # Expose Zone Time Remaining
- platform: template
name: "Zone Time Remaining Sensor"
id: zone_time_remaining_sensor
icon: mdi:progress-clock
#unit_of_measurement: 'Min'
#accuracy_decimals: 0
update_interval: $sensor_update_frequency
lambda: |-
if(id(esp32_sprinkler_ctrlr_status).state != "Paused")
{
int seconds = round(id(esp32_sprinkler_ctrlr).time_remaining().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()};
}
else
{
return {};
}
### Input to managet the display backlight
- platform: homeassistant
id: display_sprinkler_backlight
entity_id: input_number.sprinklerbacklightlevel
internal: true
on_value:
then:
- output.turn_on: sprinkler_backlight
- output.set_level:
id: sprinkler_backlight
level: !lambda |-
return atoi(id(display_sprinkler_backlight).state.c_str()) / 100.0;
# Time source config
time:
- platform: homeassistant
id: homeassistant_time
timezone: Europe/Rome
```