Open jcallaghan opened 3 years ago
This is my existing pump unit. I might consider replacing this with a pump and parts that I can source individually to make it easier to get replacement parts etc https://www.amazon.co.uk/gp/product/B07PDM4KSC/
This is the UV light I brought which I will likely upgrade to something large that I can fit on the ceiling https://www.amazon.co.uk/gp/product/B07GB28WCH
Solar-powered watering system example https://twitter.com/zimmergren/status/1282599157732126721
βGreat start of the week. My 3yo daughter helped me build and install a solar-powered automatic irrigation system for the vertical herb-wall. Re-using rain water only. No electricity needed, only solar-driven pumps. We built a wooden box to hide the water container.β
As this was all tested without the ESPHome node some fake entities were created so the automation could be created and tested. All fake entities need to be replaced. It assumes an ESPHome device would provide a moisture sensor and a relay/switch for the pump.
The automation has some //TODO
items but two considerations or improvements are catching when the pump last ran. This is currently checked via the last_triggered
attribute from the automation
. I'm not sure if the state will persist after a reboot so worth considering leveraging a date_time
helper. The other item is the time between runs, effectively a throttle to avoid the automation running multiple times. This is currently driven by an input_number
helper and assumes the pump runs once a day. This is an area I'd like to spend a little more time on.
alias: 'Zone 1 Watering'
trigger:
# When the moisture falls below the moisture low threshold.
- platform: template
value_template: "{{ states('input_number.fake_zone1_moisture') | int < states('input_number.fake_zone1_moisture_threshold') | int }}"
# When the time matches the water at helper.
- platform: template
value_template: "{{ states('sensor.time') == (state_attr('input_datetime.fake_zone1_water_time1','timestamp') | int | timestamp_custom('%H:%M', False)) }}"
condition:
condition: and
conditions:
# Only run once a day (86400 seconds in a day).
# //TODO Consider using an input_datetime helper to avoid issues with Home Assistant restarts.
# //TODO Move throttling time to a input_number help and allow the throttling to be changed in the UI [Done].
# //TODO This might also need to be considered as a trigger too.
- condition: template
value_template: "{{ (as_timestamp(states.sensor.date_time.last_changed) - (as_timestamp(state_attr('automation.zone_1_watering','last_triggered')))) > (states('fake_zone1_time_between_watering') | int * 60) }}"
# Watering must only occur whe the moisture is below the moisture low threshold.
- condition: template
value_template: "{{ states('input_number.fake_zone1_moisture') | int < states('input_number.fake_zone1_moisture_threshold') | int }}"
# This automatic water enabled helper must be enabled for automatic watering to work.
- condition: state
entity_id: input_boolean.fake_zone1_enabled
state: "on"
# The pump should not be activated if the water is low.
- condition: state
entity_id: input_boolean.fake_zone1_water_available
state: "on"
action:
# Turn on the pump.
- service: input_boolean.turn_on
entity_id: input_boolean.fake_zone1_switch
# Add a delay to allow the pump to work based on how long we want it to run for in the UI.
- delay:
seconds: "{{ states('input_number.fake_zone1_pump_run_time') | int }}"
# Turn off the pump.
- service: input_boolean.turn_off
entity_id: input_boolean.fake_zone1_switch
# //TODO check-in notification. Send notification to say the plants have been watered and their moisture level was 20% and is now 56%. Grow biggy grow! π»
# //TODO consider creating a secondary automation to send a notification/alert when the water is low.
# Tests
# 1. The automation should only work when "automatic watering enabled" and "Water Available" are both on.
# 1. The automation will only run after the duration "xxxx" has passed since it last ran.
# 1. The automation should trigger when the "Moisture Level" from the plant falls below the "Moisture Level Threshold" or the time matches "Water at".
# 1. The pump should only run for the duration set via "Pump Run Time".
fake_zone1_enabled:
name: Automatic Watering Enabled
icon: mdi:watering-can
fake_zone1_switch:
name: Pump
icon: mdi:pump
fake_zone1_water_available:
name: Water Available
icon: mdi:water-off
fake_zone1_moisture:
name: Moisture Level
min: 0
max: 100
step: 1
unit_of_measurement: "%"
mode: box
fake_zone1_moisture_threshold:
name: Moisture Low Threshold
min: 0
max: 100
step: 1
unit_of_measurement: "%"
fake_zone1_pump_run_time:
name: Pump Run Time
min: 0
max: 60
step: 1
unit_of_measurement: "seconds"
fake_zone1_time_between_watering:
name: Minimum time between watering
min: 0
max: 1440
step: 1
unit_of_measurement: "minutes"
mode: box
fake_zone1_water_time1:
name: Water at
has_date: false
has_time: true
To avoid issues with overwatering I will replicate something I did for my air fresheners #151 and have ESPHome write to an input_datetime
helper in Home Assistant. This way regardless of how the pump is triggered it will record the last time it ran. Then logic can be added to ESPHome to avoid it running too often. If Home Assistant isn't available then it won't run to avoid overwatering.
Here's input_datetime helper:
esph_austria_watering_d1_mini_triggered: has_date: true has_time: true
Here is the esphome config (d1_mini):
substitutions:
system_name: austria_watering_d1_mini
friendly_name: Esph Austria Watering D1
relay_gpio: D5 #D5=GPIO14
#dht22_gpio: D7
button_switch_gpio: D2
soil_moisture_adc: A0
esphome:
name: "esph_${system_name}"
platform: ESP8266
board: d1_mini
wifi:
ssid: !secret ssid
password: !secret ssid_password
power_save_mode: NONE
manual_ip:
static_ip: 172.16.254.137
gateway: 172.16.254.1
subnet: 255.255.255.0
fast_connect: true
api:
ota:
time:
- platform: homeassistant
id: homeassistant_time
captive_portal:
logger:
#level: DEBUG #DEBUG, VERY_VERBOSE
text_sensor:
- platform: version
name: "esph_${system_name}_version"
on_value:
then:
- lambda: |-
ESP_LOGD("main", "The current version is %s", x.c_str());
- platform: wifi_info
ip_address:
name: esph_${system_name}_ip
ssid:
name: esph_${system_name}_ssid
bssid:
name: esph_${system_name}_bssid
switch:
## relay / pump - used by ESPHome internally, not visible from HomeAssistant
- platform: gpio
id: relay
restore_mode: ALWAYS_OFF
#name: "${system_name} Relay"
pin:
number: $relay_gpio
inverted: True
on_turn_on:
then:
# Do something
on_turn_off:
then:
- homeassistant.service:
service: input_datetime.set_datetime
data_template:
entity_id: "input_datetime.esph_${system_name}_triggered"
datetime: !lambda return id(homeassistant_time).now().strftime("%Y-%m-%d %H:%M:%S");
- homeassistant.service:
service: notify.html5_notification
data:
title: Plants Watered
data_template:
message: Plants were watered at {{ my_variable }}.
variables:
my_variable: |-
return id(homeassistant_time).now().strftime("%Y-%m-%d %H:%M:%S");
# - sensor.template.publish
# id: input_datetime.esph_${system_name}_triggered
# state: !lambda return id(irrigation_zone1_duration).state;
## Timed Pump
- platform: template
name: "esph_${system_name}_timed_pump"
id: timed_pump
icon: "mdi:siren"
lambda: !lambda |-
if (id(relay).state) {
return true;
} else {
return false;
}
turn_on_action:
- switch.turn_on: relay
- delay: !lambda return (id(zone1_pump_run_time).state * 1000);
- switch.turn_off: relay
- homeassistant.service:
service: input_datetime.set_datetime
data_template:
entity_id: "input_datetime.esph_${system_name}_triggered"
datetime: !lambda return id(homeassistant_time).now().strftime("%Y-%m-%d %H:%M:%S");
## Normal Pump
- platform: template
name: "esph_${system_name}_pump"
id: pump
icon: "mdi:siren"
lambda: !lambda |-
if (id(relay).state) {
return true;
} else {
return false;
}
turn_on_action:
- switch.turn_on: relay
turn_off_action:
- switch.turn_off: relay
- homeassistant.service:
service: input_datetime.set_datetime
data_template:
entity_id: "input_datetime.esph_${system_name}_triggered"
datetime: !lambda return id(homeassistant_time).now().strftime("%Y-%m-%d %H:%M:%S");
binary_sensor:
#Breadboard Button
- platform: gpio
id: button_switch
pin:
number: $button_switch_gpio
mode: INPUT_PULLUP
inverted: TRUE
filters:
- delayed_on_off: 200ms
on_press:
then:
- switch.toggle: relay
sensor:
- platform: homeassistant
name: "Pump Runtime"
entity_id: input_number.zone1_pump_run_time
id: "zone1_pump_run_time"
- platform: wifi_signal
name: "esph_${system_name}_wifi_signal"
update_interval: 300s
- platform: uptime
name: "esph_${system_name}_uptime"
update_interval: 300s
- platform: adc #Volts will flow to Template Sensor Below
pin: $soil_moisture_adc
name: "esph_${system_name}_soil_v"
id: soil_v
update_interval: 60s
unit_of_measurement: 'v'
accuracy_decimals: 2
- platform: template
name: "esph_${system_name}_soil_percent"
id: soil_percent
unit_of_measurement: '%'
icon: "mdi:water-percent"
update_interval: 60s
accuracy_decimals: 0
# Bryan Reading: 0.44 = in water, 0.84 = dry
lambda: |-
const float x = id(soil_v).state;
if (x > 0.8) {
return 0;
} else if (x < 0.4) {
return 100;
} else {
return (0.84 - x) / (0.84-0.44) * 100.0;
}
ESP_LOGD("main", "Coolaboola -- we have soil value in volts : %d", x);
input_datetime
integration documentation - https://www.home-assistant.io/integrations/input_datetime/Home Assistant
Instructions on how to integrate the Input Datetime integration into Home Assistant.
input_number
integration documentation - https://www.home-assistant.io/integrations/input_number/Still not happy about manual button. If button is pressed, it is not updating last watered date, so it is defeating the system. Sure moisture readings would still be there. Need to find a way to have the button action "Normal Pump" motion.
https://hometechhacker.com/how-home-assistant-runs-my-irrigation-controller/
HomeTechHacker
Here's how Home Assistant locally schedules my EtherRain irrigation controller and takes the weather forecast into consideration.
GitHub
My personal knowledge dump, of which you are welcome to share! - brianhanifin/brianhanifin.com
https://www.wikihow.com/Grow-Plants-With-Grow-Lights https://en.wikipedia.org/wiki/Grow_light
wikiHowPlants need light to grow and flourish. Some plants cannot survive outdoors in the winter, and if you do not have a yard, your only choice might be to grow plants indoors. Indoor plant growing can be difficult, though. Positioning your...
Document the build of an automatic watering system for my kitchen garden herbs. The plan is to upgrade my existing watering solution and integrate it with Home Assistant with a friend who wants to do the same with his outdoor herbs.
Ingredients
Related: #174