With our cistern, which we got last year as a buffer and with the new pipes for rainwater drainage, there is plenty of free water from the roof. At least when it rains again one day.
We have therefore laid pipes for automatic irrigation on the property, using the Gardena irrigation system, as these components were cheaper last year than the alternatives from Hunter or Rainbird.
⚠ [affiliate] Keine Produkte mit Cache für home-assistant.
Bitte affiliate-sync --lang en ausführen.
The typical irrigation valves are controlled with 24 volts alternating current. According to the data sheet, the switch-on current is 370 mA, the holding current 210 mA. According to my measurements, the actual values were somewhat lower.
As all the valves are never in operation at the same time because otherwise the water pressure would drop too much (even with the 4 bar submersible pressure pump), a 24 volt AC power supply with 1 ampere is sufficient. I still had this from an old outdoor light chain. You can also find suitable power supply units
on Ebay
.
If the valves were operated with DC voltage, the cores of the electromagnets could become permanently magnetised and the valves would “stick”. In the worst case, the core would become saturated, which could mean a higher current flow and thus the destruction of the coils.
Therefore, MOSFETs cannot be used for simple control. The simplest solution would be relays, but I didn’t want to rely on that. Firstly, the contacts can corrode and the simple Chinese relays, which are available ready-made as
4 or 8-pin boards
, are not necessarily suitable for switching low voltage. This sounds paradoxical, but most alloys used for relay contacts (AgCdO for these relays) require a short arc, which only occurs at higher voltages and currents (the so-called frit current). This burns away oxides, which ensures a permanently good contact. As there is also high humidity in the shed, relays were ruled out for me.
For my DIY controller, which I christened Waterking, I opted for
BTA08-600B triacs
, which are controlled via a
MOC3041 optocoupler
that also contains a zero-crossing triac driver. If you add 5 resistors, an NPN transistor and an LED, one channel costs less than one euro and you will never have contact problems. The LEDs indicate on the hardware side whether a valve is open and the optocoupler is activated.
As you already have the 24 volts, you can also use them to supply the ESP8266 and the display. Rectified, you get 35 V DC, which I convert very efficiently to 5 V using an
LM2596S step-down converter
.
As is often the case with my projects, a
Wemos D1 Mini Pro
is used because I bought a large quantity at a good price a long time ago. The Wemos is also utilised down to the (almost) last GPIO. I need 6 outputs to control 5 valves and our submersible pressure pump. Now you could use 6 GPIOs or use a shift register of type
SN74HC595
. This allows you to switch 8 outputs with 3 control pins. If you need more, you can cascade up to 4 SN74HC595 under
?ESPHomeESPHomeFramework for configuring ESP32/ESP8266 microcontrollers that automatically integrate into Home Assistant. Ideal for DIY sensors and actuators, for which you then need one more pin, but this gives you 32 outputs.
Originally, my controller was supposed to remain “dumb”, i.e. only make the triac outputs switchable via Home Assistant. But if you already have a microcontroller, you might as well add a few extra functions. For example, the valves switch off after a configurable time (10 minutes). If no valve is active, the pump is also deactivated. If the WLAN connection is lost during irrigation or Home Assistant has a bug, the valves and pump switch off automatically and autonomously. I built everything on a
strip grid board
. I’m “Team Strip Grid” - I just don’t like the messing around with solder on the perfboards.
Please understand that I don’t have a plan for the layout of the board. I do things like this freely and without much pre-planning directly from the circuit diagram. Just test the position of the parts and off you go. Maybe I’ll add a circuit board layout with KiCAD when I get the chance - maybe one of you would like to do that too? The circuit diagram in KiCAD is available.
Using a rotary encoder and the LED display, I can not only display the status of the valves (in addition to the LEDs on the optocoupler), but also switch them on and off directly on the controller. Other menu levels show the water level of the cistern in centimetres and litres, the strength of the WLAN signal, today’s water consumption and the time. I have described how to build the water level meter with a TL-136 sensor here:
/wasserstand-in-zisternen-mit-homeassistant-esphome-und-tl-136-drucksensor-messen/
You can change levels by simply turning the encoder. Pressing the button takes you to the setup menu for the valves. A dash indicates an inactive valve, a box an active one. The decimal point indicates which valve has just been selected and a long press on the button switches it on or off. A short press takes you back to the main menu.
I was once tempted to create a convenient menu with a simple
8-digit LED display
. It doesn’t always have to be an OLED or LC display and the LED display is very robust, which is not unimportant at -20 to 50 °C in the shed.
By checking the water level in the cistern, I can deactivate the pump if the water level drops below 12 cm. A long press on the encoder button switches off all valves and the pump immediately.
Interlocking the outputs prevents certain valves from being active at the same time. This not only prevents a drop in pressure, but also prevents the power pack from being overloaded. A maximum of 3 valves
(Gardena Micro Trip dripper
raised bed, front garden and water withdrawal) can be active and only one of the two circuits for the lawn area. The controller also provides this safety function directly - regardless of what else I would configure in Home Assistant.
To ensure that everything is properly packaged and looks good, I printed a housing from PETG and PLA. The transparent PETG allows the LEDs and the display to shine through.
For the display cut-out, I chose the layer thickness during construction so that no infill is printed. This makes it look like a transparent film.
The entire housing can be closed without screws and the circuit board is also only held in place by snap fasteners. With a handmade circuit board, the construction of a housing with a lid is not entirely trivial, but it worked on the first attempt and print.
A holder for a spare fuse is also included as a gag. Access to the connection terminals is from below. As always, I used Autodesk Fusion 360 for the design. My
Creality Ender 3
did the printing in about 10 hours.
If you don’t want to go to the trouble of controlling the valves, you can also
use
an
SSR board
instead of the triacs, which you can get for less than €20. Here you only have to control the channels with the ESP. The code below can also be used for this.
I have annotated the
?YAMLYAMLData format (YAML Ain’t Markup Language). Used in Home Assistant for configurations, automations and scenes. Easy to read but error-prone with incorrect indentation configuration in ESPHome accordingly:
esphome:name:waterkingplatform:ESP8266board:d1_mini# Switch off all outputs at startup for safety reasonson_boot:then:- switch.turn_off:v1- switch.turn_off:v2- switch.turn_off:v3- switch.turn_off:v4- switch.turn_off:v5- switch.turn_off:pump- sensor.rotary_encoder.set_value:id:encvalue:0# Switch off serial logger on RX/TX to be able to use pins for other taskslogger:baud_rate:0# Activate Home Assistant APIapi:ota:password:!secret otapass"wifi:ssid:!secret wifi_ssidpassword:!secret wifi_passworduse_address:waterking.local# Fallback hotspotap:ssid:"Bewaesserung Fallback Hotspot"password:!secret hotspotcaptive_portal:# Get time from HAtime:- platform:homeassistantid:homeassistant_time# Set global variablesglobals:- id:setpage#Setting modetype:boolrestore_value:noinitial_value:'false'- id:maxtime#maximum valve runtime as protectiontype:intrestore_value:yesinitial_value:'600000'# in ms = 10 min# Set up shift registersn74hc595:- id:'sn74hc595_hub'data_pin:D5clock_pin:D6latch_pin:D7oe_pin:D2sr_count:1# SPI for displayspi:clk_pin:D0mosi_pin:D1# Define valvesswitch:- platform:gpioname:"Valve East"id:v1pin:sn74hc595:sn74hc595_hubnumber:1inverted:falseinterlock:[v2,v4,v5]# Do not switch on certain valves at the same time -> pressure losson_turn_on:- switch.turn_on:pump- delay:!lambda "return id(maxtime);"- switch.turn_off:v1- platform:gpioname:"Valve West"id:v2pin:sn74hc595:sn74hc595_hubnumber:2inverted:falseinterlock:[v1,v4,v5]on_turn_on:- switch.turn_on:pump- delay:!lambda "return id(maxtime);"- switch.turn_off:v2- platform:gpioname:"Ventil Beet"id:v3pin:sn74hc595:sn74hc595_hubnumber:3inverted:falseinterlock:[v2]on_turn_on:- switch.turn_on:pump- delay:!lambda "return id(maxtime);"- switch.turn_off:v3- platform:gpioname:"Front garden valve"id:v4pin:sn74hc595:sn74hc595_hubnumber:4inverted:falseinterlock:[v1,v2]on_turn_on:- switch.turn_on:pump- delay:!lambda "return id(maxtime);"- switch.turn_off:v4- platform:gpioname:"Valve inlet"id:v5pin:sn74hc595:sn74hc595_hubnumber:5inverted:falseinterlock:[v2,v5]on_turn_on:- switch.turn_on:pump- delay:1h#Valve 5 may be on for max. 1 hour -> water withdrawal- switch.turn_off:v5# Solid state relay output for pump control- platform:gpioname:"SSR pump"internal:true# Do not display pump in HAid:pumppin:sn74hc595:sn74hc595_hubnumber:0inverted:false# Set up displaydisplay:- platform:max7219cs_pin:D3num_chips:1update_interval:500mslambda:|- // Display page 5 time
if ((id(enc).state == 5) && (id(setpage) == false)) {
it.print(" ");
it.strftime("%H.%M.%S", id(homeassistant_time).now());
}
// Page 4 Wifi Level
if ((id(enc).state == 4) && (id(setpage) == false)) {
it.print(" ");
it.printf("Wi %.0fdB", id(wlan_signal).state);
}
// Page 1 Water level Height
if ((id(enc).state == 1) && (id(setpage) == false)) {
it.print(" ");
it.printf("FH %.1fcn", id(cistern_cm).state);
}
// Page 2 Water level litres
if ((id(enc).state == 2) && (id(setpage) == false)) {
it.print(" ");
it.printf("FS %.0fL", id(cistern_litre).state);
}
// Page 3 Water consumption today
if ((id(enc).state == 3) && (id(setpage) == false)) {
it.print(" ");
it.printf(1,"= %.0f L", id(cistern_delta_today).state);
}
// Display page 0 status valves
if ((id(enc).state == 0) && (id(setpage) == false)) {
it.print(" ");
if ((id(v1).state)) {
it.print("o");
} else {
it.print("_");
}
if ((id(v2).state)) {
it.print(1, "o");
} else {
it.print(1,"_");
}
if ((id(v3).state)) {
it.print(2, "o");
} else {
it.print(2,"_");
}
if ((id(v4).state)) {
it.print(3, "o");
} else {
it.print(3,"_");
}
if ((id(v5).state)) {
it.print(4, "o");
} else {
it.print(4,"_");
}
if ((id(pump).state)) {
it.print(6, "P");
} else {
it.print(6,"_");
}
}
// First page setup page
if (id(setpage) == true && id(enc).state == 0) {
it.print(" S");
if ((id(v1).state)) {
it.print("o");
} else {
it.print("_");
}
if ((id(v2).state)) {
it.print(1, "o");
} else {
it.print(1,"_");
}
if ((id(v3).state)) {
it.print(2, "o");
} else {
it.print(2,"_");
}
if ((id(v4).state)) {
it.print(3, "o");
} else {
it.print(3,"_");
}
if ((id(v5).state)) {
it.print(4, "o");
} else {
it.print(4,"_");
}
if ((id(pump).state)) {
it.print(6, "P");
} else {
it.print(6,"_");
}
}
// Set valve 1
if (id(setpage) == true && id(enc).state == 1) {
if ((id(v1).state)) {
it.print("o.");
} else {
it.print("_.");
}
if ((id(v2).state)) {
it.print(1, "o");
} else {
it.print(1,"_");
}
if ((id(v3).state)) {
it.print(2, "o");
} else {
it.print(2,"_");
}
if ((id(v4).state)) {
it.print(3, "o");
} else {
it.print(3,"_");
}
if ((id(v5).state)) {
it.print(4, "o");
} else {
it.print(4,"_");
}
} // End V1
// Set valve 2
if (id(setpage) == true && id(enc).state == 2) {
if ((id(v1).state)) {
it.print("o");
} else {
it.print("_");
}
if ((id(v2).state)) {
it.print(1, "o.");
} else {
it.print(1,"_.");
}
if ((id(v3).state)) {
it.print(2, "o");
} else {
it.print(2,"_");
}
if ((id(v4).state)) {
it.print(3, "o");
} else {
it.print(3,"_");
}
if ((id(v5).state)) {
it.print(4, "o");
} else {
it.print(4,"_");
}
}
if (id(setpage) == true && id(enc).state == 3) {
if ((id(v1).state)) {
it.print("o");
} else {
it.print("_");
}
if ((id(v2).state)) {
it.print(1, "o");
} else {
it.print(1,"_");
}
if ((id(v3).state)) {
it.print(2, "o.");
} else {
it.print(2,"_.");
}
if ((id(v4).state)) {
it.print(3, "o");
} else {
it.print(3,"_");
}
if ((id(v5).state)) {
it.print(4, "o");
} else {
it.print(4,"_");
}
}
if (id(setpage) == true && id(enc).state == 4) {
if ((id(v1).state)) {
it.print("o");
} else {
it.print("_");
}
if ((id(v2).state)) {
it.print(1, "o");
} else {
it.print(1,"_");
}
if ((id(v3).state)) {
it.print(2, "o");
} else {
it.print(2,"_");
}
if ((id(v4).state)) {
it.print(3, "o.");
} else {
it.print(3,"_.");
}
if ((id(v5).state)) {
it.print(4, "o");
} else {
it.print(4,"_");
}
}
if (id(setpage) == true && id(enc).state == 5) {
if ((id(v1).state)) {
it.print("o");
} else {
it.print("_");
}
if ((id(v2).state)) {
it.print(1, "o");
} else {
it.print(1,"_");
}
if ((id(v3).state)) {
it.print(2, "o");
} else {
it.print(2,"_");
}
if ((id(v4).state)) {
it.print(3, "o");
} else {
it.print(3,"_");
}
if ((id(v5).state)) {
it.print(4, "o.");
} else {
it.print(4,"_.");
}
}sensor:- platform:rotary_encoder# Set up rotary encodername:"Rotary Encoder"id:encpublish_initial_value:truepin_a:number:TXinverted:truemode:input:truepullup:truepin_b:number:RXinverted:truemode:input:truepullup:truemax_value:5min_value:0# Get fill level in litres from HA- platform:homeassistantid:cistern_litreentity_id:sensor.cistern_litre# Get consumption today from HA- platform:homeassistantid:cistern_delta_todayentity_id:sensor.cistern_delta_today# Get fill level in cm from HA- platform:homeassistantid:cistern_cmentity_id:sensor.wasserstandraw# Emergency shutdown water level < 12 cm -> pump protectionon_value_range:- below:12then:- switch.turn_off:v1- switch.turn_off:v2- switch.turn_off:v3- switch.turn_off:v4- switch.turn_off:v5- switch.turn_off:pump# Get WLAN signal strength ... because you can- platform:wifi_signalname:"ESP Wifi Signal"update_interval:30sid:wlan_signalbinary_sensor:- platform:templatename:"Any Valve On"# If all valves are off, switch off the pumpinternal:truelambda:'return id(v1).state or id(v2).state or id(v3).state or id(v4).state or id(v5).state ;'on_release:then:- switch.turn_off:pump- platform:gpio# Set up buttons on the encoderid:encswitchpin:number:GPIO2mode:INPUT_PULLUPinverted:Trueon_click:- min_length:50ms# Short actuation to enter the valve setupmax_length:250msthen:- lambda:|- if(id(setpage)) {
id(setpage) = false;
} else {
id(setpage) = true;
}- min_length:600ms# long actuation to switch selected valve on/offmax_length:1500msthen:- if:condition:lambda:'return (id(setpage) == true && id(enc).state == 1);'then:switch.toggle:v1- if:condition:lambda:'return (id(setpage) == true && id(enc).state == 2);'then:switch.toggle:v2- if:condition:lambda:'return (id(setpage) == true && id(enc).state == 3);'then:switch.toggle:v3- if:condition:lambda:'return (id(setpage) == true && id(enc).state == 4);'then:switch.toggle:v4- if:condition:lambda:'return (id(setpage) == true && id(enc).state == 5);'then:switch.toggle:v5- min_length:3000ms# very long actuation to switch off all valves and the pumpmax_length:60000msthen:- switch.turn_off:v1- switch.turn_off:v2- switch.turn_off:v3- switch.turn_off:v4- switch.turn_off:v5- switch.turn_off:pump
Irrigation control with Home Assistant
Home Assistant will take over the actual irrigation control. As various sensors such as the rain sensor of the
LCN-WIH
weather station, rain quantity sensor and the weather forecast are already available as entities in HA, these can be used for optimal and economical irrigation.
The level measurement of the cistern is also an excellent sensor when it comes to rainfall, as it receives the rainfall from 75 square metres of roof area. If the water level in the cistern is low, you can also shorten the watering times, etc.
The most important values for irrigation come from a soil moisture sensor. Although capacitive sensors are relatively robust, they only measure the soil moisture in a narrow range of a few square centimetres. I have therefore built a resistive sensor from two 1 metre long stainless steel threaded rods, which are buried 20 mm apart at a depth of 10 cm.
Stainless steel is corrosion-resistant and robust. The two M5 rods cost [3 euros](
https://www.sonderpreis-baumarkt.de/#search:query=edelstahl
gewindestange) in the [special price DIY store](
https://www.sonderpreis-baumarkt.de/#search:query=edelstahl
gewindestange). With this sensor, you can measure a representative area and not just selectively. As the measuring current and the resulting electrolysis could cause salts and minerals to be deposited on the electrodes over time, the measurement is only activated very briefly and at longer intervals. There will be a separate article on this.
Was this post interesting or even helpful?
Hi! I'm Markus – the Fricklr. ⚡ Electrical engineer, 🎵 musician (bass, guitar, keys) and professionally 'something with the internet' 🌐 for over 30 years – nowadays with AI too 🤖 – a 55-year-old generalist from Bavaria, Germany.
Your feedback helps me write even more interesting posts. After "Yes" there's also a small option to support my work.
Enjoyed this article? Independent tech content doesn't need a paywall — but it does need your support. With a donation you support me and my work.
What do you think? Leave a comment!
Share your thoughts, questions or experiences with the community.