Dynamic Sprinkler Schedule

This project makes dynamic adjustments to sprinkler schedules using a helper, a Python script and the Rachio scheduler (though the principle should work for other integrations). The general idea being that on hot, dry days we need more water and cool, wet days we can use less.

The Helper

This helper is updated by the script any time the weather data changes or on a periodic time interval.

I’ve defined my helper as “Irrigation Coefficient” as a Number helper with range 0 to 2. Like so:

The Script

The Python script is a simple calculator that maps temperature and precipitation amounts to a multiplier from 0 to 2. Note that the values embedded in the script are in Fahrenheit and inches.

# wxcoef.py

cfg_temp_norm = 80.0  # midpoint of the temperature range
cfg_temp_width = 40.0 # set the range for temperature map
cfg_rain_limit = 0.25 # the max amount of rain to water

def get_wx_temp_coef(temp):
    coef = 2 * (temp - cfg_temp_width) / cfg_temp_norm
    return coef if (coef > 0.0) else 0.0

def get_wx_precip_coef(precip):
    coef = (cfg_rain_limit - precip) / cfg_rain_limit
    return coef if (coef > 0.0) else 0.0

temp_val = data.get('temperature', None)
precip_val = data.get('precipitation', None)
helper_id = data.get('helper_id', None)

temp_coef = get_wx_temp_coef(float(temp_val))
precip_coef = get_wx_precip_coef(float(precip_val))
wx_coef = temp_coef * precip_coef

hass.services.call('input_number', 'set_value', {
    "value": wx_coef,
    "entity_id": helper_id,
}, False)

Personally, I trigger any time the temperature changes. The service call for the script looks like the following:

service: python_script.wxcoef
data_template:
  temperature: '{{ states.weather.dark_sky.attributes.forecast[0].temperature }}'
  precipitation: '{{ states.sensor.outside_precipitation.state }}'
  helper_id: input_number.irrigation_coefficient

Note the inputs to the script in the service call… Here, we pull the current forecast high for the day from Dark Sky, along with the received precipitation from the past 24 hours. Additionally, we pass the ID for our helper defined in the first step.

With these two pieces in place, we should see the helper being updated. It also makes for a nice gauge on the UI:

Screen Shot 2022-04-27 at 20.58.42

(Side note: using the history, you can also se how this trends over time based on high temperatures and rain fall).

The Schedule

For the final piece, we combine this helper with our irrigation controller. I’m using two Rachio controllers, which have a nice integration to HA.

Schedules trigger as regular Automations, using whatever time pattern and other conditions you prefer. When it comes to calling the schedule, we simply multiple the durations by our helper. I’ve shown the action here in YAML, since the visual editor does not support data templates:

service: rachio.start_multiple_zone_schedule
data_template:
  duration: >
    {{ 7.0 * float(states.input_number.irrigation_coefficient.state) }}
target:
  entity_id:
    - switch.front_yard_aspen_trees
    - switch.front_yard_main_drip
    - switch.house_perimeter_flowers

Note the 7.0 number in the template… This is the target number of minutes that the zones will run for. By multiplying it against the helper, it will be sent to the Rachio service as our adjusted value.

The only drawback to using a Rachio being it depends on cloud connectivity and the integration only supports schedules with a single controller.

The Future

I’m still making adjustments to this project and will post updates as I go. The main things I’d like to improve are how the zone schedules are configured and, if possible, find a way to eliminate the script.

1 Like

This would be a nice companion to my irrigation project. Be good if it used HA configuration settings Celsius/Fahrenheit Millimeters/Inches.

Good work.

1 Like

This looks great! I’ll definitely give it a try. Maybe there is an obvious way to incorporate a “duration coefficient helper” into the Irrigation Unlimited schedules? Or I’ll take a look at see about submitting a PR if I can figure it out :grin:

The integration has a number of service calls one of which is adjust_time and takes a percentage (coefficient * 100) as a parameter. Just call it directly like where you set the input_number.

1 Like