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
```
Anyone can share an automated schedule?
Do you do the automation built in the esphome yaml or do you build it via HA automations? I want it to be on the esphome so if the network is down it wont fail
Thanks
I use HA automations to trigger the schedules via a HA Calender. My understanding is the zone times are stored local to the controller in ESPH, I can trigger a schedule locally via a button if the network is down (or not). Not sure if schedule timing works after the network is down. Mostly the issue here would be power failure on the mains, and that means the controller power is down also.
I use a template sensor to measure the daily mean temperature as a condition to allow trigger of a second schedule that can occur inbetween the main schedule days.
Did you ever fixed the time.remaining issue? I am getting the same error and prevents me from running this.
The Sprinkler component was changed from time_remaining()
to time_remaining_active_valve()
to return the value of the zone remaining time.
Update all the instances of time_remaining in the yaml and it will compile, I think there are 9.
This is my current code. Compiled under ESPhome 2024.12.4
# 8 Zone Version using KC868-A8 ESP32 relay board update 2-2-2025
esphome:
name: irrigation-controller
esp32:
board: nodemcu-32s
framework:
type: arduino
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
output_power: 8.5db
fast_connect: False
manual_ip:
# Set this to the IP of the ESP
static_ip: !secret static_ip
# Set this to the IP address of the router. Often ends with .1
gateway: !secret gateway_ip
# The subnet of the network. 255.255.255.0 works for most home networks.
subnet: 255.255.255.0
# use_address: irrigation-controller.local
# 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: 3600s
services: #services for device 'irrigation controller' in Home Assistant
- service: start_full_cycle
then:
- sprinkler.start_full_cycle: esp32_sprinkler_ctrlr
- service: pause
then:
- sprinkler.pause: esp32_sprinkler_ctrlr
- service: resume
then:
- sprinkler.resume: 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: resume_or_full_cycle
then:
- sprinkler.resume_or_start_full_cycle: esp32_sprinkler_ctrlr
ota:
- platform: esphome
# I2C bus config
i2c:
sda: 4
scl: 5
scan: true
id: bus_a
frequency: 800kHz
# 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: 1s
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_active_valve().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_active_valve().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_active_valve().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_active_valve().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_active_valve().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_active_valve().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_active_valve().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_active_valve().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:
if ((id(esp32_sprinkler_ctrlr).paused_valve().value_or(-1) +1) == 0) { //first valve is 0 so assign -1 if no valve paused
it.printf(0, 0, "Watering OFF");
it.strftime(0, 1,"Time is %H:%M:%S", id(homeassistant_time).now());
} else {
it.printf(0, 0, "Watering PAUSED");
it.printf(0, 1, "Zone %2d", id(esp32_sprinkler_ctrlr).paused_valve().value_or(0) +1);
}
break;
default:
break;
}
## static int current_page_num = 1;
## int number_of_pages = 4;
# current_page_num += 1;
# if (current_page_num > number_of_pages) {
# current_page_num = 1;
# }
# Main sprinkler code
sprinkler:
- id: esp32_sprinkler_ctrlr
main_switch: "Master Run/Stop"
auto_advance_switch: "Zones Auto Advance"
# next_prev_ignore_disabled: true
# reverse_switch: "Zones Reverse"
valve_overlap: 1s
valves:
- valve_switch: "Zone 1"
enable_switch: "Zone 1 Enable"
run_duration: 600s
valve_switch_id: zone_valve_sw1
- valve_switch: "Zone 2"
enable_switch: "Zone 2 Enable"
run_duration: 300s
valve_switch_id: zone_valve_sw2
- valve_switch: "Zone 3"
enable_switch: "Zone 3 Enable"
run_duration: 600s
valve_switch_id: zone_valve_sw3
- valve_switch: "Zone 4"
enable_switch: "Zone 4 Enable"
run_duration: 300s
valve_switch_id: zone_valve_sw4
- valve_switch: "Zone 5"
enable_switch: "Zone 5 Enable"
run_duration: 300s
valve_switch_id: zone_valve_sw5
- valve_switch: "Zone 6"
enable_switch: "Zone 6 Enable"
run_duration: 300s
valve_switch_id: zone_valve_sw6
- valve_switch: "Zone 7"
enable_switch: "Zone 7 Enable"
run_duration: 600s
valve_switch_id: zone_valve_sw7
- valve_switch: "Zone 8"
enable_switch: "Zone 8 Enable"
run_duration: 300s
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_active_valve().value_or(0) / 60;"
update_interval: 30s
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.pause: 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.shutdown: esp32_sprinkler_ctrlr
# - 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
I’ve had some WiFi connecting issues for a few months, shown up using a Ping monitor in HA. Trying to resolve them currently, although the irrigation schedules seem to be running as normal.
One thing that has helped is increasing the I2C clock frequency (800kHz) and also increasing the display update time to 2s. It could well be that I have a board issues though, like 3.3V regulator etc. I don’t think I had any connection issues in the past in the logs so that’s why I think it could be the board rather than coding…
Hello, can you share yaml for this card and automation?