Ideas on building and controlling an indoor irrigation system (for potted plants)

I have a few potted plants indoors and I want to automate their irrigation.

I don’t have any water line nearby, so I’m thinking of doing something that pulls water from a tank. Is there anything out there I could use or hack together?

Thanks for any advise.

I have never found sprayers etc to be that effective on an automated setup. The joints pop out and suddenly great gouts of water leap out.

My suggestion is a drip system, feed it with a pump if you don’t have a tap nearby. Control the pump with a relay controlled by tasmota or esphome.

Thanks for the reply @nickrout. That sounds like a sensible plan. Do you know if there are flow meters or something similar I could incorporate on the setup?

That I don’t know.

I have some code you could use. It runs on an ESP8266 at the moment, has been setup for 2 stations but I only used 1, and has a flow switch to confirm flow. The plan was to upgrade my code to include notifications if: 1) there was no flow when there should be, 2) there is flow when there shouldn’t be… but I never bothered to do so. It would be very easy to add that.

reticulation.yaml (package)

########################################
#
#   This is a full reticulation
#   control package using ESPHOMEYAML
#   as the soleniod control via a NodeMCU
#    
#   
#
########################################

homeassistant:
  customize:
    switch.retic_station_1_valve:
      icon: mdi:water-pump
    switch.retic_station_2_valve:
      icon: mdi:water-pump
    input_boolean.retic_program1_enable:
      icon: mdi:traffic-light
    input_boolean.retic_program2_enable:
      icon: mdi:traffic-light
#    switch.retic_moisture_test_30s:
#      assumed_state: false


      
sensor:
  - platform: template    # determine if today is selected as a watering day for program 1
    sensors:
      retic_program1_watering_day:
        entity_id: 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
        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:
        entity_id: 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
        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') }}



# Rain sensors from BOM forecast of today

      possible_rainfall_today:
        entity_id: sensor.bom_forecast_perth_weather_forecast_0
        friendly_name: "Possible Rainfall Today"
        value_template:  >
          {{ state_attr('sensor.bom_forecast_perth_weather_forecast_0', 'Possible Rainfall') | replace("mm", "") | float }}

      chance_of_rain_today:
        entity_id: sensor.bom_forecast_perth_weather_forecast_0
        friendly_name: "Chance Of Rain Today"
        value_template:  >
          {{ state_attr('sensor.bom_forecast_perth_weather_forecast_0', 'Chance of Rain') | replace("%", "") | float }}



    
input_datetime:
  retic_program1_start_time:    # program start time control
    name: Program 1 Start Time
    has_date: false
    has_time: true

  retic_program2_start_time:
    name: Program 2 Start Time
    has_date: false
    has_time: true


input_number:
  retic_program1_station1_run_time:   # station run time control
    name: Station 1 Run Time
    min: 0
    max: 30
    step: 1
    icon: mdi:camera-timer

  retic_program1_station2_run_time:
    name: Station 2 Run Time
    min: 0
    max: 30
    step: 1
    icon: mdi:camera-timer

  retic_program2_station1_run_time:
    name: Station 1 Run Time
    min: 0
    max: 30
    step: 1
    icon: mdi:camera-timer

  retic_program2_station2_run_time:
    name: Station 2 Run Time
    min: 0
    max: 30
    step: 1
    icon: mdi:camera-timer  

  allowable_rain_quantity:
    name: 'Allowable Rain (mm)'
    min: 0
    max: 5
    step: 0.1
    icon: mdi:cup-water

  allowable_rain_percentage:
    name: 'Allowable Rain (%)'
    min: 0
    max: 100
    step: 1
    icon: mdi:water-percent

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_program1_enable:   # enable program to run
    name: Enable
    
  retic_program2_enable:
    name: Enable


  retic_rain_parameters_met:   # set to ON if rain today values are below levels set in input_numbers
    name: Rain Parameters Met
    icon: mdi:water
  retic_rain_override:         # set to ON to run retic even if rain parameters are not met
    name: Rain Override
    icon: mdi:water

group:                  # frontend interface setup
  retic_manual:
    control: hidden
    name: 'Manual Control'
    entities:
      - switch.retic_station_1_valve
      - switch.retic_station_2_valve
  
  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

  retic_status:
    control: hidden
    name: 'Status'
    icon: mdi:water
    entities:
      - binary_sensor.retic_station_1_flow
      - switch.retic_moisture_sensor_control
      - sensor.retic_moisture_sensor_reading
      
#switch:                      # Solenoid control (will be signals to NodeMCU) NOT USED HERE BECAUSE CONTROL IS NOW VIA ESPHOMEYAML ADDON
#  - 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: Check rain parameters     # check that todays rain doesnt need to disable the retic from running
    initial_state: 'on'
    trigger:
      - platform: template
        value_template: "{{ states('sensor.time') == ((states.input_datetime.retic_program1_start_time.attributes.timestamp - 600) | int | timestamp_custom('%H:%M', False)) }}"
      - platform: state
        entity_id: input_number.allowable_rain_quantity
      - platform: state
        entity_id: input_number.allowable_rain_percentage

##    condition:
##      conditions:
##        - condition: template
##          value_template: "{{ states('sensor.bom_current_weather_rain_today') <= states('input_number.allowable_rain_quantity') }}"
##        - condition: template
##          value_template: "{{ states('sensor.possible_rainfall_today') <= states('input_number.allowable_rain_percentage') }}"

    action:
#      - service_template: >
#          {% if states('sensor.bom_perth_rain_today') <= states('input_number.allowable_rain_quantity') and states('sensor.possible_rainfall_today') <= states('input_number.allowable_rain_percentage') %}
#            input_boolean.turn_on
#          {% else %}
#            input_boolean.turn_off
#          {% endif %}
#          entity_id: input_boolean.retic_rain_parameters_met
      - service_template: >
          input_boolean.turn_{{'on' if states('sensor.bom_perth_rain_today') <= states('input_number.allowable_rain_quantity') and 
                                       states('sensor.possible_rainfall_today') <= states('input_number.allowable_rain_percentage')  else 'off'}}
        entity_id: input_boolean.retic_rain_parameters_met


  - 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') == (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'
        - condition: or
          conditions:
            - condition: state
              entity_id: input_boolean.retic_rain_parameters_met
              state: 'on'
            - condition: state
              entity_id: input_boolean.retic_rain_override
              state: 'on'
    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') == (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'
        - condition: or
          conditions:
            - condition: state
              entity_id: input_boolean.retic_rain_parameters_met
              state: 'on'
            - condition: state
              entity_id: input_boolean.retic_rain_override
              state: 'on'
    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_2_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_2_valve

ESPhome code (on the ESP8266)

esphomeyaml:
  name: ha_retic_controller_1
  platform: ESP8266
  board: nodemcuv2

wifi:
  ssid: 'xxxx'
  password: 'xxxx'
  manual_ip:
    static_ip: 192.168.0.61
    gateway: 192.168.0.1
    subnet: 255.255.255.0

api:

# Enable logging
logger:

ota:
  password: 'xxxx'

switch:
  - platform: gpio
    name: "Retic Station 1 Valve"
#    id: s1
    icon: mdi:water-pump
    pin: 
      number: D1
      inverted: true
  - platform: gpio
    name: "Retic Station 2 Valve"
#    id: s2
    icon: mdi:water-pump
    pin: 
      number: D2
      inverted: true
  - platform: gpio
    name: "Retic Moisture Sensor Control"
    id: s3
    icon: mdi:water-percent
    pin:
      number: D3
      inverted: false
  - platform: template
    name: "Retic Moisture Test 30s"
    id: s4
    icon: mdi:water-percent
    optimistic: yes
    turn_on_action:
    - switch.turn_on: s3
    - delay: 30s
    - switch.turn_off: s3
    - switch.turn_off: s4

binary_sensor:
  - platform: gpio
    name: "Retic Station 1 Flow"
    pin: 
      number: D4
      inverted: true
      mode: INPUT_PULLUP
#  - platform: gpio
#    name: "Retic Station 1 Manual Button"
#    pin:
#      number: D5
#      inverted: true
#      mode: INPUT_PULLUP
#      filters:
#        - delayed_on: 10ms
#    on_press:
#      then:
#        - switch.toggle: s1

sensor:
  - platform: adc
    pin: A0
    name: "Retic Moisture Sensor Reading"
    icon: mdi:water-percent
    unit_of_measurement: "%"
    accuracy_decimals: 1
    filters:
      - lambda: return ((1- x) / 1) * 140; # multiplying by 140 to scale value since reading is only 70% in water
#      - filter_out: > 100

Lovelace screen

The moisture sensor reports over 100% when its turned off. I only run it for a short period because extended time on will corrode the sensor. I will actually be getting rid of it this week as I now have Mi Flora sensors instead which are much better.

4 Likes

Your garden is far too tidy.

Haha, thanks :thinking: That image is of my new place which I literally move into this afternoon, hopefully I can keep it that way :zipper_mouth_face:.

The code etc is for the pot plant watering I had in a rental before buying the above place. Yesterday I coded a new ESP program for a much more complicated retic controller which takes timing data from HA but can run independently in the event that HA is down (normally caused by me f’ing around too much), just running on last known settings. I haven’t tested it yet though so it’s not ready to share.

Hello! I build complete system irrigation my plants. For control humidity level MiFlora. If humidity go dawn, automation HA send signal to sonoff ON. Sonoff is build in old ATX. Inside is ESP8266 too, which control on-off relays for 6V small water pumps. I control level water in tank too. I can live my plants for 1-2 weeks for vacations. Everything works automatically under HA. If someone more interested I can explain more details.

2 Likes

Great project, can you share detailed production methods? thank!

I’m trying to do the same. I was looking at this kit that is available on Amazon, but I would like to connect the pump relay board to something like an ESP32 and connect to HA, as well as use the Mi Flora sensors. Just not sure how to do it.

Replace the arduino with an esp8266 or an esp32 and run esphome.

1 Like