I’m looking to add days to mine too. Is your full code online somewhere?
Since this post I have written an article on my website sharing details on creating the required Home Assistant Entities and a Simplified User Interface. This should provide more of the missing information.
Hi Brian, could you share more info on the electrical connect part? I see from the pictures that you power the sonoff with the 120V AC direct line in. What about the valve solenoids? Do send the positive from the 24VAC transformer to all the valve solenoids and splice the ground to the sonoff?
Thanks for your help.
Looks good! Thanks for sharing. I am taking some of it to make a custom controller with an ESP where I can add an antenna, DHT sensor and I hope I can also integrate weather forecast.
Mario, since this post I have written an article on my website sharing details on creating the required Home Assistant Entities and a Simplified User Interface . This should provide more of the missing information.
Hi its been a while since my last post, I hope everyone find this proyect helpfull
Original idea by @BrianHanifin ESPHome: DIY Irrigation Controller With Internal Scheduler.
Plus Functionalities by @raberrio.
And Full operation of the buttons, scheduling possibilities and finally the inputs texts and numbers explained by @VikingBlod.
This goes in config.yaml
######RIEGO
input_text:
##HORAS
irrigation_zone1_times:
name: Horarios 1
icon: mdi:chart-timeline
irrigation_zone2_times:
name: Horarios 2
icon: mdi:chart-timeline
irrigation_zone3_times:
name: Horarios 3
icon: mdi:chart-timeline
# irrigation_zone4_times:
# name: Horarios 4
# icon: mdi:chart-timeline
##DIAS
irrigation_zone1_days:
name: Dias Zona 1
icon: mdi:calendar-week
irrigation_zone2_days:
name: Dias Zona 2
icon: mdi:calendar-week
irrigation_zone3_days:
name: Dias Zona 3
icon: mdi:calendar-week
# irrigation_zone4_days:
# name: Dias Zona 4
# icon: mdi:calendar-week
input_number:
##DURACION
irrigation_zone1_duration:
name: Duración Zona 1
min: 0
max: 30
step: 1
mode: slider
icon: mdi:timer
irrigation_zone2_duration:
name: Duración Zona 2
min: 0
max: 30
step: 1
mode: slider
icon: mdi:timer
irrigation_zone3_duration:
name: Duración Zona 3
min: 0
max: 30
step: 1
mode: slider
icon: mdi:timer
irrigation_zone4_duration:
name: Duración Zona 4
min: 0
max: 30
step: 1
mode: slider
icon: mdi:timer
This is esphome yaml
# MIT License: https://github.com/brianhanifin/Irrigation-with-display/blob/master/LICENSE
#
# Credit: @bruxy70 thank you for the significant head start!
# Personal project goals: https://github.com/brianhanifin/Home-Assistant-Config/issues/37
#
substitutions:
project: Irrigation Controller2
id: irrigation2
<<: !include common/substitutions/gpio/sonoff4chpror2.yaml
esphome:
name: riego_sonoff
platform: ESP8266
board: esp01_1m
includes:
- irrigation.h
wifi:
ssid: "SSID"
password: "PASSWoRd"
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Irrigation Fallback Hotspot"
password: "password"
captive_portal:
<<: !include common/logger.yaml
# Enable Home Assistant API
api:
ota:
globals:
# ============================================================================= #
# Irrigation time remaining
- id: remaining_time1
type: int
restore_value: no
initial_value: "300"
- id: remaining_time2
type: int
restore_value: no
initial_value: "300"
- id: remaining_time3
type: int
restore_value: no
initial_value: "300"
- id: remaining_time4
type: int
restore_value: no
initial_value: "300"
# ============================================================================= #
# Store previous values to verify change.
- id: remaining_time1_previous
type: int
restore_value: no
initial_value: "0"
- id: remaining_time2_previous
type: int
restore_value: no
initial_value: "0"
- id: remaining_time3_previous
type: int
restore_value: no
initial_value: "0"
- id: remaining_time4_previous
type: int
restore_value: no
initial_value: "0"
# Common housekeeping components.
output:
<<: !include common/outputs/status_led.yaml
light:
<<: !include common/lights/status_led.yaml
binary_sensor:
- !include common/binary_sensors/status.yaml
# ============================================================================= #
# Buttons along the left side of the unit (R1, R2, R3, R4).
- platform: gpio
id: key1
pin:
number: $button1_gpio
mode: INPUT_PULLUP
inverted: True
filters:
- delayed_on: 100ms
- delayed_off: 100ms
on_click:
min_length: 50ms
max_length: 350ms
then:
- switch.toggle: irrigation_zone1
- platform: gpio
id: key2
pin:
number: $button2_gpio
mode: INPUT_PULLUP
inverted: True
filters:
- delayed_on: 100ms
- delayed_off: 100ms
on_click:
min_length: 50ms
max_length: 350ms
then:
- switch.toggle: irrigation_zone2
- platform: gpio
id: key3
pin:
number: $button3_gpio
mode: INPUT_PULLUP
inverted: True
filters:
- delayed_on: 100ms
- delayed_off: 100ms
on_click:
min_length: 50ms
max_length: 350ms
then:
- switch.toggle: irrigation_zone3
- platform: gpio
id: key4
pin:
number: $button4_gpio
mode: INPUT_PULLUP
inverted: True
filters:
- delayed_on: 100ms
- delayed_off: 100ms
on_click:
min_length: 50ms
max_length: 350ms
then:
- switch.toggle: irrigation_zone4
switch:
#- !include common/switches/restart.yaml
# ============================================================================= #
# Virtual Zone Switches which toggle the relay, and store the current state.
- platform: template
name: Irrigation Zone1
id: irrigation_zone1
icon: mdi:sprinkler-variant
lambda: return id(relay1).state;
optimistic: true
turn_on_action:
# Turn on if not disabled.
if:
condition:
lambda: return id(irrigation_zone1_duration) > 0;
then:
- switch.turn_on: relay1
turn_off_action:
- switch.turn_off: relay1
- platform: template
name: Irrigation Zone2
id: irrigation_zone2
icon: mdi:sprinkler-variant
lambda: return id(relay2).state;
optimistic: true
turn_on_action:
# Turn on if not disabled.
if:
condition:
lambda: return id(irrigation_zone2_duration) > 0;
then:
- switch.turn_on: relay2
turn_off_action:
- switch.turn_off: relay2
- platform: template
name: Irrigation Zone3
id: irrigation_zone3
icon: mdi:sprinkler-variant
lambda: return id(relay3).state;
optimistic: true
turn_on_action:
# Turn on if not disabled.
if:
condition:
lambda: return id(irrigation_zone3_duration) > 0;
then:
- switch.turn_on: relay3
turn_off_action:
- switch.turn_off: relay3
- platform: template
name: Irrigation Zone4
id: irrigation_zone4
icon: mdi:sprinkler-variant
lambda: return id(relay4).state;
optimistic: true
turn_on_action:
# Turn on if not disabled.
if:
condition:
lambda: return id(irrigation_zone4_duration) > 0;
then:
- switch.turn_on: relay4
turn_off_action:
- switch.turn_off: relay4
# ============================================================================= #
# Relays which trigger solenoids
- platform: gpio
id: relay1
pin: $relay1_gpio
restore_mode: ALWAYS_OFF
on_turn_on:
then:
# Start the countdown timer.
- globals.set:
id: remaining_time1
value: !lambda return id(irrigation_zone1_duration).state * 60;
# Show the remaining time.
- sensor.template.publish:
id: irrigation_zone1_remaining
state: !lambda return id(irrigation_zone1_duration).state;
# Show the "Next Time" as "now".
- text_sensor.template.publish:
id: irrigation_zone1_next
state: "ahora"
# state NOW on original code, change to your preferred language
on_turn_off:
then:
- sensor.template.publish:
id: irrigation_zone1_remaining
state: "0"
# Update the next scheduled run time.
- text_sensor.template.publish:
id: irrigation_zone1_next
state: !lambda |-
return update_next_runtime(id(irrigation_zone1_times).state, id(irrigation_zone1_days).state);
- platform: gpio
id: relay2
pin: $relay2_gpio
restore_mode: ALWAYS_OFF
on_turn_on:
then:
# Start the countdown timer.
- globals.set:
id: remaining_time2
value: !lambda return id(irrigation_zone2_duration).state * 60;
# Show the remaining time.
- sensor.template.publish:
id: irrigation_zone2_remaining
state: !lambda return id(irrigation_zone2_duration).state;
# Show the "Next Time" as "now".
- text_sensor.template.publish:
id: irrigation_zone2_next
state: "ahora"
on_turn_off:
then:
- sensor.template.publish:
id: irrigation_zone2_remaining
state: "0"
# Update the next scheduled run time.
- text_sensor.template.publish:
id: irrigation_zone2_next
state: !lambda |-
return update_next_runtime(id(irrigation_zone2_times).state, id(irrigation_zone2_days).state);
- platform: gpio
id: relay3
pin: $relay3_gpio
restore_mode: ALWAYS_OFF
on_turn_on:
then:
# Start the countdown timer.
- globals.set:
id: remaining_time3
value: !lambda return id(irrigation_zone3_duration).state * 60;
# Show the remaining time.
- sensor.template.publish:
id: irrigation_zone3_remaining
state: !lambda return id(irrigation_zone3_duration).state;
# Show the "Next Time" as "now".
- text_sensor.template.publish:
id: irrigation_zone3_next
state: "ahora"
on_turn_off:
then:
- sensor.template.publish:
id: irrigation_zone3_remaining
state: "0"
# Update the next scheduled run time.
- text_sensor.template.publish:
id: irrigation_zone3_next
state: !lambda |-
return update_next_runtime(id(irrigation_zone3_times).state, id(irrigation_zone3_days).state);
- platform: gpio
id: relay4
pin: $relay4_gpio
restore_mode: ALWAYS_OFF
on_turn_on:
then:
# Start the countdown timer.
- globals.set:
id: remaining_time4
value: !lambda return id(irrigation_zone4_duration).state * 60;
# Show the remaining time.
- sensor.template.publish:
id: irrigation_zone4_remaining
state: !lambda return id(irrigation_zone4_duration).state;
# Show the "Next Time" as "now".
- text_sensor.template.publish:
id: irrigation_zone4_next
state: "ahora"
on_turn_off:
then:
- sensor.template.publish:
id: irrigation_zone4_remaining
state: "0"
# Update the next scheduled run time.
- text_sensor.template.publish:
id: irrigation_zone4_next
state: !lambda |-
return update_next_runtime(id(irrigation_zone4_times).state, id(irrigation_zone4_days).state);
sensor:
- !include common/sensors/uptime.yaml
- !include common/sensors/wifi_signal.yaml
# ============================================================================= #
# Retrieve durations settings from the Home Assistant UI.
- platform: homeassistant
id: ui_zone1_duration
entity_id: input_number.irrigation_zone1_duration
on_value:
#if:
# condition:
# api.connected:
then:
- sensor.template.publish:
id: irrigation_zone1_duration
state: !lambda return id(ui_zone1_duration).state;
- platform: homeassistant
id: ui_zone2_duration
entity_id: input_number.irrigation_zone2_duration
on_value:
#if:
# condition:
# api.connected:
then:
- sensor.template.publish:
id: irrigation_zone2_duration
state: !lambda return id(ui_zone2_duration).state;
- platform: homeassistant
id: ui_zone3_duration
entity_id: input_number.irrigation_zone3_duration
on_value:
#if:
# condition:
# api.connected:
then:
- sensor.template.publish:
id: irrigation_zone3_duration
state: !lambda return id(ui_zone3_duration).state;
- platform: homeassistant
id: ui_zone4_duration
entity_id: input_number.irrigation_zone4_duration
on_value:
#if:
# condition:
# api.connected:
then:
- sensor.template.publish:
id: irrigation_zone4_duration
state: !lambda return id(ui_zone4_duration).state;
# ============================================================================= #
# Store durations.
- platform: template
name: Duración riego Zona 1
id: irrigation_zone1_duration
accuracy_decimals: 0
unit_of_measurement: min
icon: mdi:camera-timer
- platform: template
name: Duración riego Zona 2
id: irrigation_zone2_duration
accuracy_decimals: 0
unit_of_measurement: min
icon: mdi:camera-timer
- platform: template
name: Duración riego Zona 3
id: irrigation_zone3_duration
accuracy_decimals: 0
unit_of_measurement: min
icon: mdi:camera-timer
- platform: template
name: Duración riego Zona 4
id: irrigation_zone4_duration
accuracy_decimals: 0
unit_of_measurement: min
icon: mdi:camera-timer
# ============================================================================= #
# Countdown sensors.
- platform: template
name: Zona 1 tiempo restante
id: irrigation_zone1_remaining
lambda: "return 0;"
accuracy_decimals: 0
unit_of_measurement: min
icon: mdi:timer
on_value:
then:
- if:
condition:
lambda: return id(remaining_time1) == 0;
then:
- switch.turn_off: relay1
- platform: template
name: Zona 2 tiempo restante
id: irrigation_zone2_remaining
lambda: "return 0;"
accuracy_decimals: 0
unit_of_measurement: min
icon: mdi:timer
on_value:
then:
- if:
condition:
lambda: return id(remaining_time2) == 0;
then:
- switch.turn_off: relay2
- platform: template
name: Zona 3 tiempo restante
id: irrigation_zone3_remaining
lambda: "return 0;"
accuracy_decimals: 0
unit_of_measurement: min
icon: mdi:timer
on_value:
then:
- if:
condition:
lambda: return id(remaining_time3) == 0;
then:
- switch.turn_off: relay3
- platform: template
name: Zona 4 tiempo restante
id: irrigation_zone4_remaining
lambda: "return 0;"
accuracy_decimals: 0
unit_of_measurement: min
icon: mdi:timer
on_value:
then:
- if:
condition:
lambda: return id(remaining_time4) == 0;
then:
- switch.turn_off: relay4
text_sensor:
# ============================================================================= #
# Retrieve list of times from the Home Assistant UI.
- platform: homeassistant
id: ui_zone1_times
entity_id: input_text.irrigation_zone1_times
on_value:
#if:
# condition:
# api.connected:
then:
#- delay: 10sec
- text_sensor.template.publish:
id: irrigation_zone1_times
state: !lambda return id(ui_zone1_times).state;
- platform: homeassistant
id: ui_zone2_times
entity_id: input_text.irrigation_zone2_times
on_value:
#if:
# condition:
# api.connected:
then:
#- delay: 10sec
- text_sensor.template.publish:
id: irrigation_zone2_times
state: !lambda return id(ui_zone2_times).state;
- platform: homeassistant
id: ui_zone3_times
entity_id: input_text.irrigation_zone3_times
on_value:
#if:
# condition:
# api.connected:
then:
#- delay: 10sec
- text_sensor.template.publish:
id: irrigation_zone3_times
state: !lambda return id(ui_zone3_times).state;
- platform: homeassistant
id: ui_zone4_times
entity_id: input_text.irrigation_zone4_times
on_value:
#if:
# condition:
# api.connected:
then:
#- delay: 10sec
- text_sensor.template.publish:
id: irrigation_zone4_times
state: !lambda return id(ui_zone4_times).state;
# ============================================================================= #
# Store time lists.
- platform: template
name: Zona 1 Horarios
id: irrigation_zone1_times
on_value:
then:
# Update the next scheduled run time.
- text_sensor.template.publish:
id: irrigation_zone1_next
state: !lambda |-
return update_next_runtime(id(irrigation_zone1_times).state, id(irrigation_zone1_days).state);
- platform: template
name: Zona 2 Horarios
id: irrigation_zone2_times
on_value:
then:
# Update the next scheduled run time.
- text_sensor.template.publish:
id: irrigation_zone2_next
state: !lambda |-
return update_next_runtime(id(irrigation_zone2_times).state, id(irrigation_zone2_days).state);
- platform: template
name: Zona 3 Horarios
id: irrigation_zone3_times
on_value:
then:
# Update the next scheduled run time.
- text_sensor.template.publish:
id: irrigation_zone3_next
state: !lambda |-
return update_next_runtime(id(irrigation_zone3_times).state, id(irrigation_zone3_days).state);
- platform: template
name: Zona 4 Horarios
id: irrigation_zone4_times
on_value:
then:
# Update the next scheduled run time.
- text_sensor.template.publish:
id: irrigation_zone4_next
state: !lambda |-
return update_next_runtime(id(irrigation_zone4_times).state, id(irrigation_zone4_days).state);
# ============================================================================= #
# Retrieve list of days from the Home Assistant UI.
- platform: homeassistant
id: ui_zone1_days
entity_id: input_text.irrigation_zone1_days
on_value:
#if:
# condition:
# api.connected:
then:
#- delay: 10sec
- text_sensor.template.publish:
id: irrigation_zone1_days
state: !lambda return id(ui_zone1_days).state;
- platform: homeassistant
id: ui_zone2_days
entity_id: input_text.irrigation_zone2_days
on_value:
#if:
# condition:
# api.connected:
then:
#- delay: 10sec
- text_sensor.template.publish:
id: irrigation_zone2_days
state: !lambda return id(ui_zone2_days).state;
- platform: homeassistant
id: ui_zone3_days
entity_id: input_text.irrigation_zone3_days
on_value:
#if:
# condition:
# api.connected:
then:
#- delay: 10sec
- text_sensor.template.publish:
id: irrigation_zone3_days
state: !lambda return id(ui_zone3_days).state;
- platform: homeassistant
id: ui_zone4_days
entity_id: input_text.irrigation_zone4_days
on_value:
#if:
# condition:
# api.connected:
then:
#- delay: 10sec
- text_sensor.template.publish:
id: irrigation_zone4_days
state: !lambda return id(ui_zone4_days).state;
# ============================================================================= #
# Store time lists.
- platform: template
name: Zona 1 Días
id: irrigation_zone1_days
on_value:
then:
# Update the next scheduled run time.
- text_sensor.template.publish:
id: irrigation_zone1_next
state: !lambda |-
return update_next_runtime(id(irrigation_zone1_times).state, id(irrigation_zone1_days).state);
- platform: template
name: Zona 2 Días
id: irrigation_zone2_days
on_value:
then:
# Update the next scheduled run time.
- text_sensor.template.publish:
id: irrigation_zone2_next
state: !lambda |-
return update_next_runtime(id(irrigation_zone2_times).state, id(irrigation_zone2_days).state);
- platform: template
name: Zona 3 Días
id: irrigation_zone3_days
on_value:
then:
# Update the next scheduled run time.
- text_sensor.template.publish:
id: irrigation_zone3_next
state: !lambda |-
return update_next_runtime(id(irrigation_zone3_times).state, id(irrigation_zone3_days).state);
- platform: template
name: Zona 4 Días
id: irrigation_zone4_days
on_value:
then:
# Update the next scheduled run time.
- text_sensor.template.publish:
id: irrigation_zone4_next
state: !lambda |-
return update_next_runtime(id(irrigation_zone4_times).state, id(irrigation_zone4_days).state);
# ============================================================================= #
# Set the next scheduled time.
- platform: template
name: Zona 1 siguiente riego
id: irrigation_zone1_next
icon: mdi:calendar-clock
- platform: template
name: Zona 2 siguiente riego
id: irrigation_zone2_next
icon: mdi:calendar-clock
- platform: template
name: Zona 3 siguiente riego
id: irrigation_zone3_next
icon: mdi:calendar-clock
- platform: template
name: Zona 4 siguiente riego
id: irrigation_zone4_next
icon: mdi:calendar-clock
# Update the countdown timers every 5 seconds.
interval:
- interval: 5s
then:
- lambda: |-
if (id(remaining_time1) > 0) {
// Store the previous time.
id(remaining_time1_previous) = id(remaining_time1);
// When the relay is on.
if (id(relay1).state) {
// Decrement the timer.
id(remaining_time1) -= 5;
// Turn off the relay when the time reaches zero... or the remaining time fails a sanity check!
//if (id(remaining_time1) <= 0 || id(irrigation_zone1_remaining).state > id(irrigation_zone1_duration).state){
if (id(remaining_time1) <= 0) {
id(relay1).turn_off();
id(remaining_time1) = 0;
}
}
// Update the remaining time display.
if (id(remaining_time1_previous) != id(remaining_time1)) {
id(irrigation_zone1_remaining).publish_state( (id(remaining_time1)/60) + 1 );
}
}
if (id(remaining_time2) > 0) {
id(remaining_time2_previous) = id(remaining_time2);
if (id(relay2).state) {
id(remaining_time2) -= 5;
if (id(remaining_time2) <= 0) {
id(relay2).turn_off();
id(remaining_time2) = 0;
}
}
if (id(remaining_time2_previous) != id(remaining_time2)) {
id(irrigation_zone2_remaining).publish_state( (id(remaining_time2)/60) + 1 );
}
}
if (id(remaining_time3) > 0) {
id(remaining_time3_previous) = id(remaining_time3);
if (id(relay3).state) {
id(remaining_time3) -= 5;
if (id(remaining_time3) <= 0) {
id(relay3).turn_off();
id(remaining_time3) = 0;
}
}
if (id(remaining_time3_previous) != id(remaining_time3)) {
id(irrigation_zone3_remaining).publish_state( (id(remaining_time3)/60) + 1 );
}
}
if (id(remaining_time4) > 0) {
id(remaining_time4_previous) = id(remaining_time4);
if (id(relay4).state) {
id(remaining_time4) -= 5;
if (id(remaining_time4) <= 0) {
id(relay4).turn_off();
id(remaining_time4) = 0;
}
}
if (id(remaining_time4_previous) != id(remaining_time4)) {
id(irrigation_zone4_remaining).publish_state( (id(remaining_time4)/60) + 1 );
}
}
# Time based automations.
time:
- platform: homeassistant
id: homeassistant_time
timezone: America/Buenos_Aires
on_time:
- seconds: 0
minutes: /1
then:
- lambda: |-
if (scheduled_runtime(id(irrigation_zone1_next).state.c_str())) {
id(irrigation_zone1).turn_on();
}
if (scheduled_runtime(id(irrigation_zone2_next).state.c_str())) {
id(irrigation_zone2).turn_on();
}
if (scheduled_runtime(id(irrigation_zone3_next).state.c_str())) {
id(irrigation_zone3).turn_on();
}
if (scheduled_runtime(id(irrigation_zone4_next).state.c_str())) {
id(irrigation_zone4).turn_on();
}
this is irrigation.h
#include "esphome.h"
using namespace std;
// Declare functions before calling them.
bool scheduled_runtime(string);
string update_next_runtime(string, string);
bool scheduled_runtime(string time) {
// Retrieve the current time.
auto time_now = id(homeassistant_time).now();
int time_hour = time_now.hour;
int time_minute = time_now.minute;
int time_wday = time_now.day_of_week; //added for day scheduling
//Prevent program crash - functions were created specting a time formated string
// if you pass "now", program crashes in certain cases.
if (time == "ahora") { //"now" in English, customize according to your prefs.
return false;
}
// Split the hour and minutes.
int next_hour = atoi(time.substr(0,2).c_str());
int next_minute = atoi(time.substr(3,2).c_str()); int next_wday = 0;
string day = time.substr(6,3).c_str(); //day text is added to original string
// Converting days to week numbers, change text based on your Language
if (day == "Lun" || day == "lun" || day == "LUN") {
next_wday = 2;
} else if (day == "Mar" || day == "mar" || day == "MAR") {
next_wday = 3;
} else if (day == "Mie" || day == "mie" || day == "MIE") {
next_wday = 4;
} else if (day == "Jue" || day == "jue" || day == "JUE") {
next_wday = 5;
} else if (day == "Vie" || day == "vie" || day == "VIE") {
next_wday = 6;
} else if (day == "Sab" || day == "sab" || day == "SAB") {
next_wday = 7;
} else if (day == "Dom" || day == "dom" || day == "DOM") {
next_wday = 1;
} else if (day == "Hoy") { //Today in English
next_wday = time_wday;
}
//ESP_LOGD("scheduled_runtime()", "now: %i:%i, wday: %i", next_hour, next_minute, time_wday);
// return (time_hour == next_hour && time_minute == next_minute);
return (time_hour == next_hour && time_minute == next_minute && time_wday == next_wday); //added wday to condition
}
string update_next_runtime(string time_list, string days_list) {
// Initialize variables.
vector<string> times;
vector<string> next_time;
vector<string> days; //added for day scheduling
vector<string> next_day; //added for day scheduling
char * token;
char * token2; //to work on day string
//bool single_time = false;
//bool single_day = false;
string updated_next_time;
string updated_next_day;
// Split the list of run times into an array.
token = strtok(&time_list[0], ",");
while (token != NULL) {
times.push_back(token);
token = strtok(NULL, ",");
}
// Split the list of run days into an array.
token2 = strtok(&days_list[0], ",");
while (token2 != NULL) {
days.push_back(token2);
token2 = strtok(NULL, ",");
}
// Need to delete this in order to day-time integration works
// Stop now if the list does not contain more than one time.
//if (times.size() <= 1) {
//return time_list;
//updated_next_time = time_list;
//single_time = true;
//}
// Stop now if the list does not contain more than one day.
//if (days.size() <= 1) {
//updated_next_day = days_list;
//single_day = true;
//}
// Retrieve the current time.
auto time_now = id(homeassistant_time).now();
int time_hour = time_now.hour;
int time_minute = time_now.minute;
int time_wday = time_now.day_of_week;
// Initialize variables.
int next_hour = 0;
int next_minute = 0;
int index = 0;
int loop_count = 0;
int time_count = times.size()-1;
// Compare the list of times with the current time, and return the next in the list.
//ESP_LOGD("update_next_runtime", "now: %i:%i", hour, minute);
//if (!single_time) {
for (string time : times) {
// Retrieve the next scheduled time from the list.
next_hour = atoi(time.substr(0,2).c_str());
next_minute = atoi(time.substr(3,2).c_str());
//ESP_LOGD("update_next_runtime", "next_hour: %s", time.c_str());
if (time_hour < next_hour || (time_hour == next_hour && time_minute < next_minute)) {
// Return this time if the next hour is greater than the current hour.
//return times[loop_count].c_str();
//break;
updated_next_time = times[loop_count].c_str();
break;
// When we reach the end of our schedule for the day, return the first time of tomorrow.
} else if (time_count == loop_count) {
//return times[0].c_str();
//break;
updated_next_time = times[0].c_str();
break;
}
// Increment the loop counter and array index.
loop_count += 1;
index += 2;
}
//}
int loop2_count = 0;
int day_count = days.size()-1;
int next_wday = 0;
int index2 = 0;
//if (!single_day) {
for (string day : days) {
// Retrieve the next scheduled day from the list. Set your preferred language. Check correct correlations with day numbers
if (day == "Lun" || day == "lun" || day == "LUN") {
next_wday = 2;
} else if (day == "Mar" || day == "mar" || day == "MAR") {
next_wday = 3;
} else if (day == "Mie" || day == "mie" || day == "MIE") {
next_wday = 4;
} else if (day == "Jue" || day == "jue" || day == "JUE") {
next_wday = 5;
} else if (day == "Vie" || day == "vie" || day == "VIE") {
next_wday = 6;
} else if (day == "Sab" || day == "sab" || day == "SAB") {
next_wday = 7;
} else if (day == "Dom" || day == "dom" || day == "DOM") {
next_wday = 1;
}
//ESP_LOGD("update_next_runtime", "next_hour: %s", time.c_str());
if (time_wday == next_wday && (time_hour < next_hour || (time_hour == next_hour && time_minute < next_minute))) {
// Return this day if the next day is today AND there is still a scheduled time for today.
//updated_next_day = days[loop2_count].c_str();
updated_next_day = "Hoy"; //Today
break;
// If the next day is not today, also the next time is the first of day
} else if (time_wday < next_wday) {
updated_next_day = days[loop2_count].c_str(); updated_next_time = times[0].c_str();
break;
// When we reach the end of our schedule for the week, return the first day of next week.
} else if (day_count == loop2_count) {
updated_next_day = days[0].c_str();
break;
}
// Increment the loop counter and array index.
loop2_count += 1;
index2 += 2;
}
//}
return updated_next_time + " " + updated_next_day;
Very impressive improvement!
Thanks! Your post was my inspiration and thanks to @raberrio and @VikingBlod for Share their customs or changes.
Greeting from
Hi folks,
awesome work!!!
@joaquin68 I think there is a missing } in the irrigation.h code you posted and the latest function is not working. you should add a } at the end
from
return updated_next_time + " " + updated_next_day;
to
return updated_next_time + " " + updated_next_day;
}
HI @joaquin68 ,
I think you should add the initial state as suggested by @VikingBlod to avoid reboot loop
input_text:
irrigation_zone1_times:
name: Zone 1 Time Periods
initial: 01:00
irrigation_zone2_times:
name: Zone 2 Time Periods
initial: 01:00
irrigation_zone1_days:
name: Zone 1 Days of the Week
initial: Mon,Wed,Fri
irrigation_zone2_days:
name: Zone 2 Days of the Week
initial: Mon,Wed,Fri
EDIT: got it. I need to define once and the remove it to avoid issues with reboot
Hi @VikingBlod ,
how did you change the card?
I can’t make the slider working
and I would like to understand if you are able to insert the day and the time in the UI
input_text:
irrigation_zone1_times:
name: Zone 1 Time Periods
icon: mdi:chart-timeline
irrigation_zone1_days:
name: Zone 1 Days of the Week
icon: mdi:calendar-week
input_number:
irrigation_zone1_duration:
name: Zone 1 Duration
icon: mdi:timer
min: 2
max: 60
step: 2
This is how I define the values. And the following is how I configured my Lovelace Yaml.
- type: vertical-stack
cards:
- type: entities
entities:
- entity: input_text.irrigation_zone1_days
- entity: input_text.irrigation_zone1_times
- entity: input_number.irrigation_zone1_duration
- entity: sensor.zone_1_next_watering
title: Backyard Zone 1 - Schedule
- type: entities
entities:
- entity: switch.irrigation_zone_1
secondary_info: last-changed
name: Zone 1 Watering
title: Backyard Zone 1 - Watering
- type: history-graph
entities:
- entity: switch.irrigation_zone_1
hours_to_show: 24
refresh_interval: 0
The above gives me the following;
Thank you!!!
I figured out that Entities card has the expected behavior VS the Entity card
i will play more now with your sample. thank you for sharing
Hi,
I managed to configure it. Thank you all for this amazing job
I replaced the sonoff with an ESP32 and I control 6 zones with a relay board
I have 2 additional questions:
-
if I want to run a zone more than one time the same day, should I configure the time with the comma separator? (eg. what I did in zone 2)
-
In the ESP32 log I see this
INFO Detected timezone 'CET' with UTC offset 1 and daylight savings time from 27 March 02:00:00 to 30 October 03:00:00
, but on the scheduled time the zone doesn’t start. any idea on what I’m missing?
if i manually trig the switch (see Zone 1), sounds good
but the next irrigation is ignored
as you can see Zone 2 is not triggered, and Zone 3 schedule is wrong, it should be Thu not Mon
I tested both the timezone format, same issue
timezone: Europe/Rome
timezone: CET-1CEST-2,M3.5.0/02:00:00,M10.5.0/03:00:00
regards
EDIT. I think I found the first issue, Day and Time need a comma as separator without spaces
eg
Mon,Tue,Wed,Thu,Fri,Sat,Sun
22:01,22:10
but the next irrigation still doesn’t toggle the switch
HI,
I understood the issue
when you replace the days name in the integration.h file to match your language, you have to put attention to the text specially to match the latest case (Today)
else if (day == "Tod") { //Today in English
because the substitution is taking only 3 char, you have to use only the first 3 char in your language
string day = time.substr(6,3).c_str(); //day text is added to original string
for English “Today” is “Tod”
// Converting days to week numbers, change text based on your Language
if (day == "Mon" || day == "mon" || day == "MON") {
next_wday = 2;
} else if (day == "Tue" || day == "tue" || day == "TUE") {
next_wday = 3;
} else if (day == "Wed" || day == "wed" || day == "WED") {
next_wday = 4;
} else if (day == "Thu" || day == "thu" || day == "THU") {
next_wday = 5;
} else if (day == "Fri" || day == "fri" || day == "FRI") {
next_wday = 6;
} else if (day == "Sat" || day == "sat" || day == "SAT") {
next_wday = 7;
} else if (day == "Sun" || day == "sun" || day == "SUN") {
next_wday = 1;
} else if (day == "Tod") { //Today in English
next_wday = time_wday;
}
HI @bremby Thank! I havent installed yet, i have to make a modification at pump shelter. I tested on my kitchen table everything was working but I dont remeber if I tested that specific function.
regards
@bremby hi again! if you define initial, every time you reboot HA it will set to that value. will lost you days or times settings.
Bye
@bremby guess what?? it´s me again delete initial from code
From my config.yaml
input_number:
irrigation_zone1_duration:
name: Duración Zona 1
min: 0
max: 30
step: 1
mode: slider
icon: mdi:timer
Tell me if that works
Regards
Hi,
thanks for noticing this. Maybe because i am spanish speaker and in spanish today = “hoy”, just 3 letters so i didn’t have that problem when i modified irrigation.h
regards,
Hi,
I managed to make everything working and cover 6 zones
this is the configuration page
I also added 2 additional switches
one to stop all the schedules when they are running
- platform: template
name: Stop All Zones
id: irrigation_stop_zones
icon: mdi:sprinkler-variant
optimistic: true
turn_on_action:
- switch.turn_off: irrigation_channel_1
- switch.turn_off: irrigation_channel_2
- switch.turn_off: irrigation_channel_3
- switch.turn_off: irrigation_channel_4
- switch.turn_off: irrigation_channel_5
- switch.turn_off: irrigation_channel_6
- delay: 10s
- switch.turn_off: irrigation_stop_zones
one to “suspend” the schedule (eg. you want to suspend the irrigation for a period of time, but you don’t want to clean the configurations or turn off the esp)
- platform: template
name: Irrigation Zone 1
id: irrigation_zone_1
icon: mdi:sprinkler-variant
lambda: return id(irrigation_channel_1).state;
optimistic: true
turn_on_action:
# Turn on if not disabled and not running
if:
condition:
and:
- lambda: return id(irrigation_zone_1_duration) > 0;
- binary_sensor.is_off: ui_stop_irrigation_automation
then:
- switch.turn_on: irrigation_channel_1
turn_off_action:
- switch.turn_off: irrigation_channel_1
let me know what you think or if you have made additional configurations or have any suggestions
regards