i wished this whole topic could somehow be origanized and put into modules or something so i can be easier adopted by others.
there’s so much information in this thread, but it’s so cluttered and for a noob hard to understand what works how and how parts interact.
any ideas how this could be done?
i copied lots of parts into my HA config and some parts seem to work, but some parts are missing, and i pull my hair out for 3 weeks now w/o a proper outcome
I agree.
I plan to put my stuff up at some point in the not too distant future, not because I think it is better than anything else but just because I would like to try to help someone in return for all the help I’ve had in the past here.
I’ll start a new thread when I do.
My code is setup to be used as a package. Check the docs for more info on how to use packages
great. i will check that. haven’t worked with packages yet.
btw: i’m using a nodemcu (tasmota firmware) together with a 4 relay board (all from aliexpress). i reuse the 24c ac/ac converter connected to a bridge rectifier and a dc/dc step down converter to power the nodemcu and the relais. works perfectly fine and i the most reliable and cheapest setup i could find.
would you mind sharing your github? i search for your userid but couldn’t find anything.
I don’t have anything on Git but my reticulation code is about in this thread. I’ll post an update in a few days which is closer to a final version
ok all, I have now got a much nicer interface and working watering day setup. In terms of what I want the end solution to be, its only missing the rain / weather conditions which I will sort out in the near future. I have to say a big thanks to @petro and @anon43302295 for their work helping me get the watering day side of things working.
again, this is in a package called reticulation.yaml
########################################
#
# This is a full reticulation
# control package using DarkSky
# weather prediction to
# prevent watering if rain
# is expected, or occured recently
# with local moisture sensor data
# as well
#
########################################
# Weather prediction setup
sensor:
- platform: darksky
api_key: !secret darksky_api_key
name: Reticulation Weather
forecast:
- 1
update_interval: '00:30:00'
monitored_conditions:
- precip_intensity
- precip_probability
- precip_intensity_max
# - summary
# - icon
# - temperature
# - apparent_temperature
# - wind_speed
# - wind_bearing
# - cloud_cover
# - humidity
# - hourly_summary
# - daily_summary
# - temperature_max
# - temperature_min
# - apparent_temperature_max
- platform: template # determine if today is selected as a watering day for program 1
sensors:
retic_program1_watering_day:
value_template: >
{% set sensor_names = [ 'monday', 'tuesday', 'wednesday','thursday','friday','saturday','sunday'] %}
{% set today_name = sensor_names[now().weekday()] %}
{% set entity_id = 'input_boolean.retic_program1_'+today_name %}
{{ is_state(entity_id, 'on') }}
retic_program2_watering_day:
value_template: >
{% set sensor_names = [ 'monday', 'tuesday', 'wednesday','thursday','friday','saturday','sunday'] %}
{% set today_name = sensor_names[now().weekday()] %}
{% set entity_id = 'input_boolean.retic_program2_'+today_name %}
{{ is_state(entity_id, 'on') }}
# Calculations for rain to stop reticulation
# to be completed later
# Reticulation control panel setup
input_datetime:
retic_program1_start_time: # program start time control
name: Program 1 Start Time
has_date: false
has_time: true
initial: '04:00'
retic_program2_start_time:
name: Program 2 Start Time
has_date: false
has_time: true
initial: '18:00'
input_number:
retic_program1_station1_run_time: # station run time control
name: Station 1 Run Time
initial: 10
min: 0
max: 30
step: 1
icon: mdi:camera-timer
retic_program1_station2_run_time:
name: Station 2 Run Time
initial: 10
min: 0
max: 30
step: 1
icon: mdi:camera-timer
retic_program2_station1_run_time:
name: Station 1 Run Time
initial: 10
min: 0
max: 30
step: 1
icon: mdi:camera-timer
retic_program2_station2_run_time:
name: Station 2 Run Time
initial: 10
min: 0
max: 30
step: 1
icon: mdi:camera-timer
input_boolean:
retic_program1_monday: # watering day selections for program 1
name: Monday
retic_program1_tuesday:
name: Tuesday
retic_program1_wednesday:
name: Wednesday
retic_program1_thursday:
name: Thursday
retic_program1_friday:
name: Friday
retic_program1_saturday:
name: Saturday
retic_program1_sunday:
name: Sunday
retic_program2_monday: # watering day selections for program 2
name: Monday
retic_program2_tuesday:
name: Tuesday
retic_program2_wednesday:
name: Wednesday
retic_program2_thursday:
name: Thursday
retic_program2_friday:
name: Friday
retic_program2_saturday:
name: Saturday
retic_program2_sunday:
name: Sunday
retic_station1_manual_run:
name: Station 1 ON Manual
icon: mdi:arrow-right-drop-circle
retic_station2_manual_run:
name: Station 2 ON Manual
icon: mdi:arrow-right-drop-circle
retic_program1_enable:
name: Enable
retic_program2_enable:
name: Enable
group: # frontend interface setup
retic_manual:
control: hidden
name: 'Manual Control'
entities:
- input_boolean.retic_station1_manual_run
- input_boolean.retic_station2_manual_run
retic_program1:
control: hidden
name: 'Program 1'
entities:
- input_boolean.retic_program1_enable
- script.retic_program1_run
- input_datetime.retic_program1_start_time
- group.retic_program1_watering_days
- group.retic_program1_run_times
retic_program2:
control: hidden
name: 'Program 2'
entities:
- input_boolean.retic_program2_enable
- script.retic_program2_run
- input_datetime.retic_program2_start_time
- group.retic_program2_watering_days
- group.retic_program2_run_times
retic_program1_watering_days:
control: hidden
name: 'Watering days'
icon: mdi:calendar-multiple-check
entities:
- input_boolean.retic_program1_monday
- input_boolean.retic_program1_tuesday
- input_boolean.retic_program1_wednesday
- input_boolean.retic_program1_thursday
- input_boolean.retic_program1_friday
- input_boolean.retic_program1_saturday
- input_boolean.retic_program1_sunday
retic_program2_watering_days:
control: hidden
name: 'Watering days'
icon: mdi:calendar-multiple-check
entities:
- input_boolean.retic_program2_monday
- input_boolean.retic_program2_tuesday
- input_boolean.retic_program2_wednesday
- input_boolean.retic_program2_thursday
- input_boolean.retic_program2_friday
- input_boolean.retic_program2_saturday
- input_boolean.retic_program2_sunday
retic_program1_run_times:
control: hidden
name: 'Run times'
icon: mdi:camera-timer
entities:
- input_number.retic_program1_station1_run_time
- input_number.retic_program1_station2_run_time
retic_program2_run_times:
control: hidden
name: 'Run times'
icon: mdi:camera-timer
entities:
- input_number.retic_program2_station1_run_time
- input_number.retic_program2_station2_run_time
switch: # Solenoid control (will be signals to NodeMCU)
- platform: mqtt
name: "Retic Station 1 Valve"
state_topic: "retic/station1/state"
command_topic: "retic/station1/cmd"
payload_on: "1"
payload_off: "0"
optimistic: false
qos: 0
retain: true
- platform: mqtt
name: "Retic Station 2 Valve"
state_topic: "retic/station2/state"
command_topic: "retic/station2/cmd"
payload_on: "1"
payload_off: "0"
optimistic: false
qos: 0
retain: true
automation:
- alias: Reticulation Run Program 1 # start program 1 at designated time if it is enabled and today is selected as a watering day
initial_state: 'on'
trigger:
- platform: template
value_template: '{{ states.sensor.time.state == (states.input_datetime.retic_program1_start_time.attributes.timestamp | int | timestamp_custom("%H:%M", False)) }}'
condition:
condition: and
conditions:
- condition: state
entity_id: input_boolean.retic_program1_enable
state: 'on'
- condition: state
entity_id: sensor.retic_program1_watering_day
state: 'true'
action:
- service: script.turn_on
entity_id: script.retic_program1_run
- alias: Reticulation Run Program 2 # start program 2 at designated time if it is enabled and today is selected as a watering day
initial_state: 'on'
trigger:
- platform: template
value_template: '{{ states.sensor.time.state == (states.input_datetime.retic_program2_start_time.attributes.timestamp | int | timestamp_custom("%H:%M", False)) }}'
condition:
condition: and
conditions:
- condition: state
entity_id: input_boolean.retic_program2_enable
state: 'on'
- condition: state
entity_id: sensor.retic_program2_watering_day
state: 'true'
action:
- service: script.turn_on
entity_id: script.retic_program2_run
script:
retic_program1_run: #run retic program 1 through each station for selected time
alias: Program 1 Run
sequence:
- service: switch.turn_on
data:
entity_id: switch.retic_station_1_valve
- delay: "00:{{ states('input_number.retic_program1_station1_run_time')|int }}:00"
- service: switch.turn_off
data:
entity_id: switch.retic_station_1_valve
- service: switch.turn_on
data:
entity_id: switch.retic_station_2_valve
- delay: "00:{{ states('input_number.retic_program1_station2_run_time')|int }}:00"
- service: switch.turn_off
data:
entity_id: switch.retic_station_1_valve
retic_program2_run: #run retic program 2 through each station for selected time
alias: Program 2 Run
sequence:
- service: switch.turn_on
data:
entity_id: switch.retic_station_1_valve
- delay: "00:{{ states('input_number.retic_program2_station1_run_time')|int }}:00"
- service: switch.turn_off
data:
entity_id: switch.retic_station_1_valve
- service: switch.turn_on
data:
entity_id: switch.retic_station_2_valve
- delay: "00:{{ states('input_number.retic_program2_station2_run_time')|int }}:00"
- service: switch.turn_off
data:
entity_id: switch.retic_station_1_valve
and this in in groups.yaml for the frontend tab
retic:
name: Retic
view: yes
icon: mdi:barley
entities:
- group.retic_program1
- group.retic_program2
- group.retic_manual
which should all then give you this interface:
and if you click the watering days section:
and clicking the run times section gives:
You can disable a program if you want (without having to turn off all the watering days). The program run will allow you to force the program to run now, or shows when it is currently running plus allows you to stop it. Manual station control is pretty obvious on the right hand side if you want to force a station for sprinkler tester etc.
It is currently set up for 2 programs and 2 stations but the code can be replicated to as many as you want very easily.
I hope you like it!
Like the way you did the grouping
I have mine pretty much ready now too but I was wondering if there is a limit to the length of code posts?
Mine ended up using a ton of inputs and sensors so is quite long but the whole thing is pretty much a portable package irrespective of how many zones you have so might be useful to others. I also have some rainfall and temperature adjustment calculations that someone might be able to improve on.
try to post it, then we’ll now. nothing to loose
OK here goes…
My package conists of 3 files:
garden_globals.yaml
---- is all the groups, inputs, sensors, switches etc.,
garden_weather_calculations.yaml
---- does just what it says,
garden_irrigation
---- contains the logic.
I’m pretty new to all this so I won’t vouch for how well it has been implemented but it seems to work, albeit without actually having watered anything yet!
The switches are sonoffs that control four valves (or zones) but I have tried to write it in such a way that there is as little code replication as possible which means that if you want a different number of zones then you more or less have to just add more inputs and the logic largely takes care of it. There are a couple of automations that will also need to be replicated but I think (hope) it should be self explanatory
The weather calculations are a bit of an experiment and to be honest with hindsight I think that whole idea might be a bit of overkill and I don’t know if we will ever actually use them! We’re not watering a prize winning garden we just don’t want it to die when we are on holiday!
I’d love feedback especially if you think I could have done something better. Like I said, I am still learning this.
Thanks of course go to those who have helped me on this forum and to the posters in this thread, some of whose ideas I have of course used.
It looks like this:
And yes, there is a limit to post size so I will have to post the three files in separate posts.
great. can’t wait to see all the files of the package.
including packages is so much more convenient than adding all yaml stuff seperately. it also makes it much easier to try things out and keep all in one place.
Sorry for the delay…
garden_globals.yaml
#===========
#=== Groups
#===========
group:
irrigation_information:
control: hidden
name: Irrigation Information
entities:
- group.irrigation_weather_information
- input_number.temperature_baseline
- input_number.rainfall_threshold
- sensor.last_irrigated_time
- sensor.zone1_time_today
- sensor.zone2_time_today
- sensor.zone3_time_today
- sensor.zone4_time_today
irrigation_cycle1:
control: hidden
name: 'Morning Cycle'
entities:
- input_boolean.cycle1_enable
- sensor.cycle1_next_run_time
- input_boolean.cycle1_manual_run
- input_select.cycle1_schedule_time
- input_select.cycle1_watering_days
- input_number.cycle1_zone1_duration
- input_number.cycle1_zone2_duration
- input_number.cycle1_zone3_duration
- input_number.cycle1_zone4_duration
irrigation_cycle1_status:
control: hidden
name: 'Morning Cycle Status'
entities:
- sensor.cycle1_running
- sensor.cycle1_zone_being_watered
- timer.cycle1_zone_duration
- group.cycle1_weather_settings
irrigation_cycle2:
control: hidden
name: 'Afternoon Cycle'
entities:
- input_boolean.cycle2_enable
- sensor.cycle2_next_run_time
- input_boolean.cycle2_manual_run
- input_select.cycle2_schedule_time
- input_select.cycle2_watering_days
- input_number.cycle2_zone1_duration
- input_number.cycle2_zone2_duration
- input_number.cycle2_zone3_duration
- input_number.cycle2_zone4_duration
irrigation_cycle2_status:
control: hidden
name: 'Afternoon Cycle Status'
entities:
- sensor.cycle2_running
- sensor.cycle2_zone_being_watered
- timer.cycle2_zone_duration
- group.cycle2_weather_settings
irrigation_valves:
name: 'Valves'
entities:
- switch.zone1_valve
- switch.zone2_valve
- switch.zone3_valve
- switch.zone4_valve
cycle1_weather_settings:
control: hidden
name: Morning cycle weather settings
icon: mdi:weather-partlycloudy
entities:
- input_boolean.cycle1_use_weather_adjustment
- sensor.cycle1_zone1_duration_adjusted
- sensor.cycle1_zone2_duration_adjusted
- sensor.cycle1_zone3_duration_adjusted
- sensor.cycle1_zone4_duration_adjusted
cycle2_weather_settings:
control: hidden
name: Afternoon cycle weather settings
icon: mdi:weather-partlycloudy
entities:
- input_boolean.cycle2_use_weather_adjustment
- sensor.cycle2_zone1_duration_adjusted
- sensor.cycle2_zone2_duration_adjusted
- sensor.cycle2_zone3_duration_adjusted
- sensor.cycle2_zone4_duration_adjusted
irrigation_weather_information:
# Uses the Weather Underground weather sensor
name: Weather Information History
icon: mdi:weather-partlycloudy
# icon: mdi:settings
entities:
- sensor.temp_high_2days
- sensor.temp_high_5days
- sensor.temp_minus0
- sensor.temp_minus1
- sensor.temp_minus2
- sensor.temp_minus3
- sensor.temp_minus4
- sensor.rain_3days_ratio
- sensor.rain_minus0
- sensor.rain_minus1
- sensor.rain_minus2
- sensor.rain_minus3
#================
#=== Input_Texts
#================
input_text:
cycle1_current_zone:
name: Cycle 1 current zone
cycle2_current_zone:
name: Cycle 2 current zone
#==================
#=== Input_Selects
#==================
input_select:
cycle1_watering_days:
name: Morning cycle watering days
options:
- 'Daily'
- 'Alternate'
icon: mdi:calendar
cycle2_watering_days:
name: Afternoon cycle watering days
options:
- 'Daily'
- 'Alternate'
icon: mdi:calendar
cycle1_schedule_time:
name: Morning cycle schedule start time
options:
- '08:00'
- '09:00'
- '10:00'
- '11:00'
- '12:00'
icon: mdi:alarm
cycle2_schedule_time:
name: Afternoon cycle schedule start time
options:
- '16:00'
- '17:00'
- '18:00'
- '19:00'
- '20:00'
icon: mdi:alarm
#==================
#=== Input_Numbers
#==================
input_number:
# CYCLE 1
cycle1_zone1_duration:
name: Zone 1 duration
min: 0
max: 30
step: 1
icon: mdi:camera-timer
cycle1_zone2_duration:
name: Zone 2 duration
min: 0
max: 30
step: 1
icon: mdi:camera-timer
cycle1_zone3_duration:
name: Zone 3 duration
min: 0
max: 30
step: 1
icon: mdi:camera-timer
cycle1_zone4_duration:
name: Zone 4 duration
min: 0
max: 30
step: 1
icon: mdi:camera-timer
# CYCLE 2
cycle2_zone1_duration:
name: Zone 1 duration
min: 0
max: 30
step: 1
icon: mdi:camera-timer
cycle2_zone2_duration:
name: Zone 2 duration
min: 0
max: 30
step: 1
icon: mdi:camera-timer
cycle2_zone3_duration:
name: Zone 3 duration
min: 0
max: 30
step: 1
icon: mdi:camera-timer
cycle2_zone4_duration:
name: Zone 4 duration
min: 0
max: 30
step: 1
icon: mdi:camera-timer
# The temperature above or below which the duration is adjusted
temperature_baseline:
name: Temperature baseline
min: 15
max: 25
icon: mdi:thermometer
unit_of_measurement: '°C'
# How much rain is needed before the duration is reduced
rainfall_threshold:
name: Rainfall threshold
min: 5
max: 30
icon: mdi:weather-rainy
unit_of_measurement: 'mm'
# Adjusted duration times can be extreme during calculations
# depending on weather conditions so min and max are set high
adjusted_cycle1_zone1_duration:
name: Adjusted cycle1 zone1 duration
min: -60
max: 60
adjusted_cycle1_zone2_duration:
name: Adjusted cycle1 zone2 duration
min: -60
max: 60
adjusted_cycle1_zone3_duration:
name: Adjusted cycle1 zone3 duration
min: -60
max: 60
adjusted_cycle1_zone4_duration:
name: Adjusted cycle1 zone4 duration
min: -60
max: 60
adjusted_cycle2_zone1_duration:
name: Adjusted cycle1 zone1 duration
min: -60
max: 60
adjusted_cycle2_zone2_duration:
name: Adjusted cycle1 zone2 duration
min: -60
max: 60
adjusted_cycle2_zone3_duration:
name: Adjusted cycle1 zone3 duration
min: -60
max: 60
adjusted_cycle2_zone4_duration:
name: Adjusted cycle1 zone4 duration
min: -60
max: 60
# Temperature
temp_minus0:
name: Temp today
min: 0
max: 40
icon: mdi:thermometer
temp_minus1:
name: Temp yesterday
min: 0
max: 40
icon: mdi:thermometer
temp_minus2:
name: Temp 2 days ago
min: 0
max: 40
icon: mdi:thermometer
temp_minus3:
name: Temp 3 days ago
min: 0
max: 40
icon: mdi:thermometer
temp_minus4:
name: Temp 4 days ago
min: 0
max: 40
icon: mdi:thermometer
temp_high_2days:
name: Avg 2 day temp
min: 0
max: 40
mode: box
icon: mdi:thermometer
temp_high_5days:
name: Avg 5 day temp
min: 0
max: 40
mode: box
icon: mdi:thermometer
# Rainfall
rain_minus0:
name: Rain today
min: 0
max: 100
icon: mdi:weather-rainy
rain_minus1:
name: Rain yesterday
min: 0
max: 100
icon: mdi:weather-rainy
rain_minus2:
name: Rain 2 days ago
min: 0
max: 100
icon: mdi:weather-rainy
rain_minus3:
name: Rain 3 days ago
min: 0
max: 100
icon: mdi:weather-rainy
rain_3days_ratio:
name: Last 3 days rain adj
min: 0
max: 500
step: 0.01
mode: box
icon: mdi:weather-rainy
#===================
#=== Input_Booleans
#===================
input_boolean:
cycle1_enable:
name: Enable schedule
icon: mdi:pipe
cycle2_enable:
name: Enable schedule
icon: mdi:pipe
cycle1_use_weather_adjustment:
name: Use weather adjustment
icon: mdi:weather-partlycloudy
cycle2_use_weather_adjustment:
name: Use weather adjustment
icon: mdi:weather-partlycloudy
cycle1_manual_run:
name: Run morning cycle now
icon: mdi:arrow-right-drop-circle
cycle2_manual_run:
name: Run afternoon cycle now
icon: mdi:arrow-right-drop-circle
cycle1_running:
name: Cycle 1 running
cycle2_running:
name: Cycle 2 running
#====================
#=== Input_Datetimes
#====================
input_datetime:
cycle1_next_run_time:
has_date: true
has_time: true
cycle2_next_run_time:
has_date: true
has_time: true
last_irrigated_time:
has_date: true
has_time: true
#===========
#=== timers
#===========
timer:
cycle1_zone_duration:
name: Time remaining
cycle2_zone_duration:
name: Time remaining
#============
#=== Sensors
#============
sensor:
- platform: template
sensors:
cycle1_next_run_time:
friendly_name: "Next scheduled run time"
value_template: >
{% if is_state('input_boolean.cycle1_enable', 'on') %}
{{ (as_timestamp(states.input_datetime.cycle1_next_run_time.state)) | timestamp_custom("%a %d %h at %H:%M") }}
{% else %}
None
{% endif %}
icon_template: mdi:clock-start
cycle2_next_run_time:
friendly_name: "Next scheduled run time"
value_template: >
{% if is_state('input_boolean.cycle2_enable', 'on') %}
{{ (as_timestamp(states.input_datetime.cycle2_next_run_time.state)) | timestamp_custom("%a %d %h at %H:%M") }}
{% else %}
None
{% endif %}
icon_template: mdi:clock-start
cycle1_running:
friendly_name: "Morning cycle"
value_template: >
{% if is_state('input_boolean.cycle1_running', 'on') %}
Running
{% else %}
Not running
{% endif %}
icon_template: >
{% if is_state('input_boolean.cycle1_running', 'on') %}
mdi:run
{% else %}
mdi:human-handsdown
{% endif %}
cycle2_running:
friendly_name: "Afternoon cycle"
value_template: >
{% if is_state('input_boolean.cycle2_running', 'on') %}
Running
{% else %}
Not running
{% endif %}
icon_template: >
{% if is_state('input_boolean.cycle2_running', 'on') %}
mdi:run
{% else %}
mdi:human-handsdown
{% endif %}
cycle1_zone_being_watered:
friendly_name: "Zone being watered"
value_template: "{{ states('input_text.cycle1_current_zone') }}"
icon_template: mdi:square-inc
cycle2_zone_being_watered:
friendly_name: "Zone being watered"
value_template: "{{ states('input_text.cycle2_current_zone') }}"
icon_template: mdi:square-inc
last_irrigated_time:
friendly_name: "Last irrigation cycle ended"
value_template: >
{{ (as_timestamp(states.input_datetime.last_irrigated_time.state)) | timestamp_custom("%a %d %h at %H:%M") }}
icon_template: mdi:update
# Zone Times - templated on history_stats sensors
zone1_time_today:
friendly_name: Zone 1 total watering time today
value_template: >
{% set duration = states('sensor.zone1_time') %}
{{ (float(duration) * 60) | round }}
unit_of_measurement: minutes
icon_template: mdi:water
zone2_time_today:
friendly_name: Zone 2 total watering time today
value_template: >
{% set duration = states('sensor.zone2_time') %}
{{ (float(duration) * 60) | round }}
unit_of_measurement: minutes
icon_template: mdi:water
zone3_time_today:
friendly_name: Zone 3 total watering time today
value_template: >
{% set duration = states('sensor.zone3_time') %}
{{ (float(duration) * 60) | round }}
unit_of_measurement: minutes
icon_template: mdi:water
zone4_time_today:
friendly_name: Zone 4 total watering time today
value_template: >
{% set duration = states('sensor.zone4_time') %}
{{ (float(duration) * 60) | round }}
unit_of_measurement: minutes
icon_template: mdi:water
cycle1_zone1_duration_adjusted:
friendly_name: "Zone 1 adjusted duration"
value_template: "{{ states('input_number.adjusted_cycle1_zone1_duration') | int }}"
icon_template: mdi:camera-timer
cycle1_zone2_duration_adjusted:
friendly_name: "Zone 2 adjusted duration"
value_template: "{{ states('input_number.adjusted_cycle1_zone2_duration') | int }}"
icon_template: mdi:camera-timer
cycle1_zone3_duration_adjusted:
friendly_name: "Zone 3 adjusted duration"
value_template: "{{ states('input_number.adjusted_cycle1_zone3_duration') | int }}"
icon_template: mdi:camera-timer
cycle1_zone4_duration_adjusted:
friendly_name: "Zone 4 adjusted duration"
value_template: "{{ states('input_number.adjusted_cycle1_zone4_duration') | int }}"
icon_template: mdi:camera-timer
cycle2_zone1_duration_adjusted:
friendly_name: "Zone 1 adjusted duration"
value_template: "{{ states('input_number.adjusted_cycle2_zone1_duration') | int }}"
icon_template: mdi:camera-timer
cycle2_zone2_duration_adjusted:
friendly_name: "Zone 2 adjusted duration"
value_template: "{{ states('input_number.adjusted_cycle2_zone2_duration') | int }}"
icon_template: mdi:camera-timer
cycle2_zone3_duration_adjusted:
friendly_name: "Zone 3 adjusted duration"
value_template: "{{ states('input_number.adjusted_cycle2_zone3_duration') | int }}"
icon_template: mdi:camera-timer
cycle2_zone4_duration_adjusted:
friendly_name: "Zone 4 adjusted duration"
value_template: "{{ states('input_number.adjusted_cycle2_zone4_duration') | int }}"
icon_template: mdi:camera-timer
# Weather information sensors
# Temperature
temp_minus0:
friendly_name: Temp today
value_template: "{{ states('input_number.temp_minus0') | int }}"
icon_template: mdi:thermometer
temp_minus1:
friendly_name: Temp yesterday
value_template: "{{ states('input_number.temp_minus1') | int }}"
icon_template: mdi:thermometer
temp_minus2:
friendly_name: Temp 2 days ago
value_template: "{{ states('input_number.temp_minus2') | int }}"
icon_template: mdi:thermometer
temp_minus3:
friendly_name: Temp 3 days ago
value_template: "{{ states('input_number.temp_minus3') | int }}"
icon_template: mdi:thermometer
temp_minus4:
friendly_name: Temp 4 days ago
value_template: "{{ states('input_number.temp_minus4') | int }}"
icon_template: mdi:thermometer
temp_high_2days:
friendly_name: Avg 2 day temp
value_template: "{{ states('input_number.temp_high_2days') | int }}"
icon_template: mdi:thermometer
temp_high_5days:
friendly_name: Avg 5 day temp
value_template: "{{ states('input_number.temp_high_5days') | int }}"
icon_template: mdi:thermometer
# Rainfall
rain_minus0:
friendly_name: Rain today
value_template: "{{ states('input_number.rain_minus0') | int }}"
icon_template: mdi:weather-rainy
rain_minus1:
friendly_name: Rain yesterday
value_template: "{{ states('input_number.rain_minus1') | int }}"
icon_template: mdi:weather-rainy
rain_minus2:
friendly_name: Rain 2 days ago
value_template: "{{ states('input_number.rain_minus2') | int }}"
icon_template: mdi:weather-rainy
rain_minus3:
friendly_name: Rain 3 days ago
value_template: "{{ states('input_number.rain_minus3') | int }}"
icon_template: mdi:weather-rainy
rain_3days_ratio:
friendly_name: Last 3 days rain adj. multiplyer
value_template: "{{ states('input_number.rain_3days_ratio') | int }}"
icon_template: mdi:weather-rainy
# History sensors
# Zone Times
- platform: history_stats
name: zone1_time
entity_id: switch.zone1_valve
state: 'on'
type: time
start: '{{ now().replace(hour=0).replace(minute=0).replace(second=0) }}'
end: '{{ now() }}'
- platform: history_stats
name: zone2_time
entity_id: switch.zone2_valve
state: 'on'
type: time
start: '{{ now().replace(hour=0).replace(minute=0).replace(second=0) }}'
end: '{{ now() }}'
- platform: history_stats
name: zone3_time
entity_id: switch.zone3_valve
state: 'on'
type: time
start: '{{ now().replace(hour=0).replace(minute=0).replace(second=0) }}'
end: '{{ now() }}'
- platform: history_stats
name: zone4_time
entity_id: switch.zone4_valve
state: 'on'
type: time
start: '{{ now().replace(hour=0).replace(minute=0).replace(second=0) }}'
end: '{{ now() }}'
#=============
#=== Switches
#=============
switch:
# sonoff (4ch)
# Zone 1
- platform: mqtt
name: "Zone1 valve"
state_topic: "stat/sonoff4ch01/POWER1"
command_topic: "cmnd/sonoff4ch01/power1"
availability_topic: "tele/sonoff4ch01/LWT"
qos: 1
payload_on: "ON"
payload_off: "OFF"
payload_available: "Online"
payload_not_available: "Offline"
retain: true
# Zone 2
- platform: mqtt
name: "Zone2 valve"
state_topic: "stat/sonoff4ch01/POWER2"
command_topic: "cmnd/sonoff4ch01/power2"
availability_topic: "tele/sonoff4ch01/LWT"
qos: 1
payload_on: "ON"
payload_off: "OFF"
payload_available: "Online"
payload_not_available: "Offline"
retain: true
# Zone 3
- platform: mqtt
name: "Zone3 valve"
state_topic: "stat/sonoff4ch01/POWER3"
command_topic: "cmnd/sonoff4ch01/power3"
availability_topic: "tele/sonoff4ch01/LWT"
qos: 1
payload_on: "ON"
payload_off: "OFF"
payload_available: "Online"
payload_not_available: "Offline"
retain: true
# Zone 4
- platform: mqtt
name: "Zone4 valve"
state_topic: "stat/sonoff4ch01/POWER4"
command_topic: "cmnd/sonoff4ch01/power4"
availability_topic: "tele/sonoff4ch01/LWT"
qos: 1
payload_on: "ON"
payload_off: "OFF"
payload_available: "Online"
payload_not_available: "Offline"
retain: true
garden_weather_calculations.yaml
#=================
# === Automations
#=================
automation:
#=====================================================================
#=== Adjust weather durations if:
#=== the baseline duration is changed
#=== the temperature threshold or rainfall baseline are changed
#=== use weather adjustment is turn on
#=====================================================================
- alias: Duration changed in cycle1
initial_state: 'on'
trigger:
- platform: state
entity_id:
- input_number.cycle1_zone1_duration
- input_number.cycle1_zone2_duration
- input_number.cycle1_zone3_duration
- input_number.cycle1_zone4_duration
action:
- service: script.adjust_cycle1_durations
- alias: Duration changed in cycle2
initial_state: 'on'
trigger:
- platform: state
entity_id:
- input_number.cycle2_zone1_duration
- input_number.cycle2_zone2_duration
- input_number.cycle2_zone3_duration
- input_number.cycle2_zone4_duration
action:
- service: script.adjust_cycle2_durations
- alias: Change in rain baseline or temp baseline
initial_state: 'on'
trigger:
- platform: state
entity_id:
- input_number.temperature_baseline
- input_number.rainfall_threshold
action:
- service: script.adjust_cycle1_durations
- service: script.adjust_cycle2_durations
- alias: Use weather adjustment turned on
initial_state: 'on'
trigger:
- platform: state
entity_id:
- input_boolean.cycle1_use_weather_adjustment
- input_boolean.cycle2_use_weather_adjustment
to: 'on'
action:
- service: script.adjust_cycle1_durations
- service: script.adjust_cycle2_durations
#===============================================
#=== Cycle historic weather data in the history
#===============================================
- alias: Collect weather data
initial_state: 'on'
trigger:
- platform: time
at: '23:55:00'
action:
# Cycle the temperature figures
- service: input_number.set_value
data_template:
entity_id: input_number.temp_minus5
value: >
{{ states('input_number.temp_minus4') }}
- service: input_number.set_value
data_template:
entity_id: input_number.temp_minus4
value: >
{{ states('input_number.temp_minus3') }}
- service: input_number.set_value
data_template:
entity_id: input_number.temp_minus3
value: >
{{ states('input_number.temp_minus2') }}
- service: input_number.set_value
data_template:
entity_id: input_number.temp_minus2
value: >
{{ states('input_number.temp_minus1') }}
- service: input_number.set_value
data_template:
entity_id: input_number.temp_minus1
value: >
{{ states('input_number.temp_minus0') }}
# Reset todays temp to low - the average weather calculations happen every
# 30 mins and will only update todays temperature if it goes up.
# This is because the DarkSky max temperature appears to change during
# the day to reflect max temperature for the remainder of the day.
- service: input_number.set_value
data_template:
entity_id: input_number.temp_minus0
value: '0'
# Cycle the rainfall figures
- service: input_number.set_value
data_template:
entity_id: input_number.rain_minus3
value: >
{{ states('input_number.rain_minus2') }}
- service: input_number.set_value
data_template:
entity_id: input_number.rain_minus2
value: >
{{ states('input_number.rain_minus1') }}
- service: input_number.set_value
data_template:
entity_id: input_number.rain_minus1
value: >
{{ states('input_number.rain_minus0') }}
# Set today's forecast rain
# DarkSky rain is measured in mm/h so multiply by 24 then multiply by the probibility of rain.
# This is done here so that it is only done once a day after midnight.
# The forcast figues go up and down all day so the the best we can do for history
# is take the whole day forecast once only.
# We do NOT want to do it every time a re-calculation of the averages is performed.
- wait_template: "{{ states.sensor.time.state == '00:10' }}"
- service: input_number.set_value
data_template:
entity_id: input_number.rain_minus0
value: >
{{ float(states.sensor.dark_sky_precip_intensity.state) * 24 *
(float(states.sensor.dark_sky_precip_probability.state) / 100) }}
# Calculate temperature and rainfall averages
- service: script.calculate_average_weather_conditions
- wait_template: "{{ is_state('script.calculate_average_weather_conditions', 'off') }}"
# Adjust Cycle 1 durations
- service: script.adjust_cycle1_durations
- wait_template: "{{ is_state('script.adjust_cycle1_durations', 'off') }}"
# Adjust Cycle 2 durations
- service: script.adjust_cycle2_durations
- wait_template: "{{ is_state('script.adjust_cycle2_durations', 'off') }}"
#=================================================
#=== Recalculate average weather conditions every
#=== 30 minutes to account for todays weather
#=================================================
- alias: Update average weather every 30 mins
initial_state: 'on'
trigger:
- platform: time
minutes: '/30'
seconds: 00
action:
- service: script.calculate_average_weather_conditions
#============
#=== Scripts
#============
script:
#=========================================
#=== Calculate average weather conditions
#=========================================
calculate_average_weather_conditions:
sequence:
# Set today's forecast high temperature
# but only if it has gone up
# temp_minus0 is set to low evry night at 23:50 when the weather
# information is cycled
- service: input_number.set_value
data_template:
entity_id: input_number.temp_minus0
value: >
{% if states.input_number.temp_minus0.state | float < states.sensor.dark_sky_daily_high_temperature.state | float %}
{{ states('sensor.dark_sky_daily_high_temperature') }}
{% else %}
{{ states('input_number.temp_minus0') }}
{% endif %}
# Calculate average high temp for the today and yesterday
- service: input_number.set_value
data_template:
entity_id: input_number.temp_high_2days
value: >
{{ ((float(states.input_number.temp_minus0.state) +
float(states.input_number.temp_minus1.state)) / 2 ) | round }}
# Calculate average high temp for the today and yesterday and previous 3 days
- service: input_number.set_value
data_template:
entity_id: input_number.temp_high_5days
value: >
{{ ((float(states.input_number.temp_minus0.state) +
float(states.input_number.temp_minus1.state) +
float(states.input_number.temp_minus2.state) +
float(states.input_number.temp_minus3.state) +
float(states.input_number.temp_minus4.state)) / 5) | round }}
# Adjust the total amount of rain depending on how many days ago it was.
# If 3 days ago take 20% of the rain.
# If 2 days ago take 50% of the rain.
# If yesterday take 80% of the rain.
- service: input_number.set_value
data_template:
entity_id: input_number.rain_3days_ratio
value: >
{{ (float(states.input_number.rain_minus1.state) * 0.8) +
(float(states.input_number.rain_minus2.state) * 0.5) +
(float(states.input_number.rain_minus3.state) * 0.2) }}
# Add in todays forecast rain
- service: input_number.set_value
data_template:
entity_id: input_number.rain_3days_ratio
value: >
{{ float(states.input_number.rain_3days_ratio.state) +
(float(states.input_number.rain_minus0.state)) }}
# Convert into a ratio (maximum 1.00) used to reduce irrigation time or stop it altogether:
# Rain needed in last 3 days to stop grass irrigation is set in RainfallThreshold
# Rain levels less than this amount will be used to reduce irrigation run times proportionally
- service: input_number.set_value
data_template:
entity_id: input_number.rain_3days_ratio
value: >
{{ states.input_number.rain_3days_ratio.state | float / states.input_number.rainfall_threshold.state | float }}
- service: input_number.set_value
data_template:
entity_id: input_number.rain_3days_ratio
value: >
{% if states.input_number.rain_3days_ratio.state | float > 1 %}
1
{% else %}
{{ states.input_number.rain_3days_ratio.state }}
{% endif %}
#=========================================
#=== Adjust duration for zones in cycle 1
#=========================================
adjust_cycle1_durations:
sequence:
- service: script.calculate_adjusted_zone_durations
data:
cycle: '1'
zone: '1'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
- service: script.calculate_adjusted_zone_durations
data:
cycle: '1'
zone: '2'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
- service: script.calculate_adjusted_zone_durations
data:
cycle: '1'
zone: '3'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
- service: script.calculate_adjusted_zone_durations
data:
cycle: '1'
zone: '4'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
#=========================================
#=== Adjust duration for zones in cycle 2
#=========================================
adjust_cycle2_durations:
sequence:
- service: script.calculate_adjusted_zone_durations
data:
cycle: '2'
zone: '1'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
- service: script.calculate_adjusted_zone_durations
data:
cycle: '2'
zone: '2'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
- service: script.calculate_adjusted_zone_durations
data:
cycle: '2'
zone: '3'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
- service: script.calculate_adjusted_zone_durations
data:
cycle: '2'
zone: '4'
- wait_template: "{{ is_state('script.calculate_adjusted_zone_durations', 'off') }}"
#========================================================
#=== Adjust zone duration for average weather conditions
#=== is passed:
#=== {{ cycle }}
#=== {{ zone }}
#========================================================
calculate_adjusted_zone_durations:
sequence:
# Adjust for average daily temperature
# Calculate any change in run time based on daily average temperature.
# The default run time will occur at TemperatureBaseline degrees.
# As the daily average temperature increases above this the run time will
# also increase.
# As the average temp drops below TemperatureBaseline the run time decreases.
# The forumla used ‐ based on a 20 degree TemperatureBaseline would be:
# (((TwoDayHighAverageTemp ‐ 20) / 20) +1) * BaseLineDuration
# So: the percentage change in duration is the same as the percentage
# difference between the actual temperature and the baseline temperature
# i.e. a 10% increase in duration when the baseline temperataure
# is 20 degrees and the actual temperature is 22 degrees
- service: input_number.set_value
data_template:
entity_id: input_number.adjusted_cycle{{ cycle }}_zone{{ zone }}_duration
value: >
{% set duration = states('input_number.cycle' + cycle + '_zone' + zone + '_duration') %}
{{ (((float(states.input_number.temp_high_2days.state) - float(states.input_number.temperature_baseline.state)) / float(states.input_number.temperature_baseline.state)) + 1) * float(duration) }}
# Adjust for average daily rainfall
- service: input_number.set_value
data_template:
entity_id: input_number.adjusted_cycle{{ cycle }}_zone{{ zone }}_duration
value: >
{% set duration = states('input_number.cycle' + cycle + '_zone' + zone + '_duration') %}
{% set adj_duration = states('input_number.adjusted_cycle' + cycle + '_zone' + zone + '_duration') %}
{{ float(adj_duration) - (float(duration) * float(states.input_number.rain_3days_ratio.state)) }}
# Make sure new duration is not less than zero
- service: input_number.set_value
data_template:
entity_id: input_number.adjusted_cycle{{ cycle }}_zone{{ zone }}_duration
value: >
{% if states('input_number.adjusted_cycle' + cycle + '_zone' + zone + '_duration') | float < 0 %}
0
{% elif states('input_number.adjusted_cycle' + cycle + '_zone' + zone + '_duration') | float > 30 %}
30
{% else %}
{{ states('input_number.adjusted_cycle' + cycle + '_zone' + zone + '_duration') }}
{% endif %}
garden_irrigation.yaml
#================
#=== Automations
#================
automation:
#============================================================
#=== Set next run time when schedule enabled or time changed
#============================================================
- alias: Set next run time
trigger:
- platform: state
entity_id:
- input_boolean.cycle1_enable
- input_boolean.cycle2_enable
to: 'on'
- platform: state
entity_id:
- input_select.cycle1_schedule_time
- input_select.cycle2_schedule_time
action:
- service: input_datetime.set_datetime
data_template:
entity_id: >
{% if trigger.entity_id == 'input_boolean.cycle1_enable' or
trigger.entity_id == 'input_select.cycle1_schedule_time' %}
input_datetime.cycle1_next_run_time
{% else %}
input_datetime.cycle2_next_run_time
{% endif %}
date: >
{% if trigger.entity_id == 'input_boolean.cycle1_enable' or
trigger.entity_id == 'input_select.cycle1_schedule_time' %}
{% set time = states('input_select.cycle1_schedule_time') %}
{% else %}
{% set time = states('input_select.cycle2_schedule_time') %}
{% endif %}
{% if now().strftime('%H:%M') < time %}
{{ as_timestamp(now()) | timestamp_custom("%Y-%m-%d") }}
{% else %}
{{ (as_timestamp(now()) + 24 * 3600 ) | timestamp_custom("%Y-%m-%d") }}
{% endif %}
time: >
{% if trigger.entity_id == 'input_boolean.cycle1_enable' or
trigger.entity_id == 'input_select.cycle1_schedule_time' %}
{{ states('input_select.cycle1_schedule_time') }}
{% else %}
{{ states('input_select.cycle2_schedule_time') }}
{% endif %}
#==================================================================
#=== Run irrigation cycles at the right time and on the right days
#==================================================================
#=== Cycle 1
- alias: Run Irrigation Cycle 1
initial_state: 'on'
trigger:
- platform: time
minutes: 00
seconds: 00
condition:
- condition: template
value_template: >
{{ now().strftime('%Y-%m-%d %H:%M:00') == states('input_datetime.cycle1_next_run_time') }}
- condition: state
entity_id: input_boolean.cycle1_enable
state: 'on'
action:
- service: script.run_a_cycle
data_template:
cycle: 1
#=== Cycle 2
- alias: Run Irrigation Cycle 2
initial_state: 'on'
trigger:
- platform: time
minutes: 00
seconds: 00
condition:
- condition: template
value_template: >
{{ now().strftime('%Y-%m-%d %H:%M:00') == states('input_datetime.cycle2_next_run_time') }}
- condition: state
entity_id: input_boolean.cycle2_enable
state: 'on'
action:
- service: script.run_a_cycle
data_template:
cycle: 2
#======================
# Run A Cycle Manually
#======================
- alias: Run Cycle a Maually
trigger:
- platform: state
entity_id:
- input_boolean.cycle1_manual_run
- input_boolean.cycle2_manual_run
from: 'off'
to: 'on'
# Don't run if the other cycle is already running
condition:
- condition: template
value_template: >
{% if trigger_entity_id == 'input_boolean.cycle1_manual_run' %}
{{ states('sensor.cycle2_running') == 'Not running' }}
{% else %}
{{ states('sensor.cycle1_running') == 'Not running' }}
{% endif %}
action:
# Update progress in ui
- service: input_text.set_value
data_template:
entity_id: >
{% if trigger.entity_id == 'input_boolean.cycle1_manual_run' %}
input_text.cycle1_current_zone
{% else %}
input_text.cycle2_current_zone
{% endif %}
value: 'Initialising...'
# Make sure nothing in the system is running
# turn off valves
- service: homeassistant.turn_off
data_template:
entity_id: group.irrigation_valves
# turn off scripts
- service: homeassistant.turn_off
entity_id: script.run_a_cycle
- service: homeassistant.turn_off
entity_id: script.irrigate_a_zone
# disable both programmes
- service: homeassistant.turn_off
entity_id:
- input_boolean.cycle1_enable
- input_boolean.cycle2_enable
# run a cycle
- service: script.run_a_cycle
data_template:
cycle: >
{% if trigger.entity_id == 'input_boolean.cycle1_manual_run' %}
1
{% else %}
2
{% endif %}
# wait until script is finished
- wait_template: "{{ is_state('script.run_a_cycle', 'off') }}"
# turn off both manual run booleans (in case one was turned on
# while the other was already running)
- service: homeassistant.turn_off
entity_id:
- input_boolean.cycle1_manual_run
- input_boolean.cycle2_manual_run
#=======================
# Cancel A Manual Cycle
#=======================
- alias: Cancel A Manual Cycle
trigger:
- platform: state
entity_id:
- input_boolean.cycle1_manual_run
- input_boolean.cycle2_manual_run
from: 'on'
to: 'off'
action:
# turn off valves
- service: homeassistant.turn_off
data_template:
entity_id: group.irrigation_valves
# turn off scripts
- service: homeassistant.turn_off
entity_id: script.run_a_cycle
- service: homeassistant.turn_off
entity_id: script.irrigate_a_zone
# Cancel the timer
- service: timer.cancel
data_template:
entity_id: >
{% if trigger.entity_id == 'input_boolean.cycle1_manual_run' %}
timer.cycle1_zone_duration
{% else %}
timer.cycle2_zone_duration
{% endif %}
# Update progress in ui
- service: homeassistant.turn_off
data_template:
entity_id: >
{% if trigger.entity_id == 'input_boolean.cycle1_manual_run' %}
input_boolean.cycle1_running
{% else %}
input_boolean.cycle2_running
{% endif %}
- service: input_text.set_value
data_template:
entity_id: >
{% if trigger.entity_id == 'input_boolean.cycle1_manual_run' %}
input_text.cycle1_current_zone
{% else %}
input_text.cycle2_current_zone
{% endif %}
value: 'None'
#===================================================
#=== Update the last time an irrigation cycle ended
#===================================================
- alias: Update last run time
trigger:
- platform: state
entity_id: group.irrigation_valves
to: 'off'
for: '00:00:05'
action:
- service: input_datetime.set_datetime
data_template:
entity_id: input_datetime.last_irrigated_time
date: >
{{ as_timestamp(now()) | timestamp_custom("%Y-%m-%d ") }}
time: >
{{ as_timestamp(now()) | timestamp_custom("%H:%M") }}
#============
#=== Scripts
#============
script:
#==============================
#=== Script to run a cycle
#=== is passed:
#=== {{ cycle }}
#==============================
run_a_cycle:
sequence:
# Update next runtime
- service: input_datetime.set_datetime
data_template:
entity_id: input_datetime.cycle{{ cycle }}_next_run_time
date: >
{% if states('input_select.cycle' + cycle + '_watering_days') == 'Daily' %}
{{ (as_timestamp(now() ) + 24 * 3600 ) | timestamp_custom("%Y-%m-%d ") }}
{% else %}
{{ (as_timestamp(now() ) + 48 * 3600 ) | timestamp_custom("%Y-%m-%d ") }}
{% endif %}
time: >
{{ states('input_select.cycle' + cycle + '_schedule_time') }}
# Only continue if no cycle is running
- condition: state
entity_id: 'sensor.cycle1_running'
state: 'Not running'
- condition: state
entity_id: 'sensor.cycle2_running'
state: 'Not running'
# Update ui to show cycle is running
- service: homeassistant.turn_on
data_template:
entity_id: input_boolean.cycle{{ cycle }}_running
# Call the script to irrigate zone 1
- service: script.irrigate_a_zone
data_template:
cycle: '{{ cycle }}'
zone: 1
# Wait for irrigate script to end
- wait_template: "{{ is_state('script.irrigate_a_zone', 'off') }}"
# Call the script to irrigate zone 2
- service: script.irrigate_a_zone
data_template:
cycle: '{{ cycle }}'
zone: 2
# Wait for script.irrigate_a_zone to end
- wait_template: "{{ is_state('script.irrigate_a_zone', 'off') }}"
# Call the script to irrigate zone 3
- service: script.irrigate_a_zone
data_template:
cycle: '{{ cycle }}'
zone: 3
# Wait for script.irrigate_a_zone to end
- wait_template: "{{ is_state('script.irrigate_a_zone', 'off') }}"
# Call the script to irrigate zone 4
- service: script.irrigate_a_zone
data_template:
cycle: '{{ cycle }}'
zone: 4
# Wait for script.irrigate_a_zone to end
- wait_template: "{{ is_state('script.irrigate_a_zone', 'off') }}"
# Update progress in ui
- service: input_text.set_value
data_template:
entity_id: input_text.cycle{{ cycle }}_current_zone
value: 'None'
- service: homeassistant.turn_off
data_template:
entity_id: input_boolean.cycle{{ cycle }}_running
#==============================
#=== Script to irrigate a zone
#=== is passed:
#=== {{ cycle }}
#=== {{ zone }}
#==============================
irrigate_a_zone:
sequence:
# Don't continue if duration is zero
- condition: template
value_template: >
{% set n = states('input_number.cycle' + cycle + '_zone' + zone + '_duration') | int %}
{{ n != 0 }}
# wait 3 seconds for good measure to enable previous zone to completly finish
- delay: "00:00:03"
# Update progress in ui
- service: input_text.set_value
data_template:
entity_id: 'input_text.cycle{{ cycle }}_current_zone'
value: '{{ zone }}'
- service: switch.turn_on
data_template:
entity_id: switch.zone{{ zone }}_valve
# Start timer for zone duration
########################################
# CHANGE DURATION BACK TO MINUTES AFTER TESTING
# 00:{{ '%02i' | format(adj_duration) }}:00
# 00:{{ '%02i' | format(duration) }}:00
#
#
# Use seconds for testing
# 00:00:{{ '%02i' | format(adj_duration) }}
# 00:00:{{ '%02i' | format(duration) }}
########################################
# - service: timer.start
# data_template:
# entity_id: timer.cycle{{ cycle }}_zone_duration
# duration: >
# {% set duration = states('input_number.cycle' + cycle + '_zone' + zone + '_duration') | int %}
# {% set adj_duration = states('input_number.adjusted_cycle' + cycle + '_zone' + zone + '_duration') | int %}
# {% if is_state('input_boolean.cycle' + cycle + '_use_weather_adjustment', 'on') %}
# 00:00:{{ '%02i' | format(adj_duration) }}
# {% else %}
# 00:00:{{ '%02i' | format(duration) }}
# {% endif %}
# - wait_template: >
# {% set entity = 'timer.cycle' + cycle + '_zone_duration' %}
# {{ is_state(entity , 'idle') }}
##########################################
- service: timer.start
data_template:
entity_id: timer.cycle{{ cycle }}_zone_duration
duration: >
{% set duration = states('input_number.cycle' + cycle + '_zone' + zone + '_duration') | int %}
{% set adj_duration = states('input_number.adjusted_cycle' + cycle + '_zone' + zone + '_duration') | int %}
{% if is_state('input_boolean.cycle' + cycle + '_use_weather_adjustment', 'on') %}
00:{{ '%02i' | format(adj_duration) }}:00
{% else %}
00:{{ '%02i' | format(duration) }}:00
{% endif %}
- wait_template: >
{% set entity = 'timer.cycle' + cycle + '_zone_duration' %}
{{ is_state(entity , 'idle') }}
- service: switch.turn_off
data_template:
entity_id: switch.zone{{ zone }}_valve
# Update progress in ui
- service: input_text.set_value
data_template:
entity_id: input_text.cycle{{ cycle }}_current_zone
value: 'Changing zone...'
thanks i’ll try that at the weekend!!
Hello, sorry I tried your configuration that I find it very interesting, unfortunately gives me errors, I created the three yaml files that you have published but gives me the following error “Component not found: garden” in the file configuration.yaml how they should be referred to ex. I have indicated
"garden global: !include garden_globals.yaml
garden weather: !include garden_weather_calculations.yaml
garden irrigation: !include garden_irrigation.yaml "
is correct?
thanks
@gojonny I use packages.
In my configuration.yaml I have
homeassistant:
packages: !include_dir_named packages/
create the folder packages
Put the three files in that folder.
@klogg Really liked your irrigation package for HA.
I implemented it to my setup with 5 zones.
I am getting the below listed error for all 5 sensors.
homeassistant.exceptions.InvalidStateError: Invalid state encountered for entity id: sensor.zone1_time_today. State max length is 255 characters.
This isn’t going to be very helpful but I remember getting that message too when was writing it.
I am pretty sure (but really can’t remember) that it turned out to be a simple syntax error that got through the config check.
Have you looked at the full Home Assistant Log? Sometimes that gives more information
Sorry that I can’t be more helpful. At the bottom of the ‘Info’ page in developers tools see ‘Press the button to load the full Home Assistant log’