Pflanzenbewässerung mit ESP32 in MicroPython - Teil 3 - Wasser marsch - AZ-Delivery

This episode is also as PDF document available.

With the lighting of our planting shell alone, the plants will certainly not be happy. The plants need nutrients and they are usually dissolved in the water. Today's contribution is about water supply. In addition to programming, there is also a little physics. In this episode, you will learn what role and how the planning can be implemented in hardware and program in terms of program.

Micropython on the ESP32 and ESP8266


Part 3 - Water On

The sowing bowl is designed in such a way that the plant pots with their holes on the ground immerse a few millimeters into the water underneath. This is easier than laying your own water pipe for every container. On the one hand, there would be a hopeless tubular war and on the other hand, a pressure compensation between the individual lines would have to be established, otherwise they drink some plants, while the others withdraw because they do not get anything.

Of course, a water supply vessel must be there so that the tub can be refilled using a pump. In this context, however, there is a hidden catch and that is the line from the storage vessel to the tub.

Figure 1: The hydrostatic pressure can cause trouble

Figure 1: The hydrostatic pressure can cause trouble

The pump works like the lye pump of a washing machine with a whipped wheel in a chamber. The water is sucked in by a hole on the front and transported into the hose by a pipe socket. If the engine stands still, this chamber is permeable in both directions, there are no valves.

Once the pump has filled the hose, a hydrostatic pressure, which allows the water continue, builds up in the right part of the height difference, even if the pump is standing. The hose acts as a suction lift as long as the water is higher in the glass than in the tub.

The normal air pressure has an effect on the open surfaces in the glass and at the hose end. Print spreads evenly on all sides. This leads to the pressure P1 In the hose on the upper brand, air pressure is also the same. At the end of the hose, however, the hydrostatic pressure p is coming from the insideH of the water column. The pressure force perpendicular to the cross -sectional area of ​​the hose transports the water to the outside.

PH = ρ • g • h

ρ is the density of the liquid, g the earth acceleration and h the height difference.

This effect can lead to the tub overflows in the worst case. The plant pots definitely go swimming. So that this does not happen, you just have to put the tub so high that the water level is always higher than that in the glass. Then the water flows out of the hose after the engine is parked, after the same physical reasoning, back into the glass.

However, a similar effect occurs when the hose in the tub extends to the ground. Once the pump has been active for a while, water has accumulated in the tub, into which the hose immerses. If the water level is higher in the tub than in the glass, water will flow back into it. The effect can be desired if it is important to only dive the planters briefly. This can make sense, because then the plants do not constantly have wet feet. However, a time control would then have to put the pump in action regularly because the irrigation process can no longer control itself, as is the case in the present program.


As a controller, I chose an ESP32 because it can come up with sufficient freely selectable GPIO connections, we need 10 pieces up when fully removed.

The ESP32 models in the partial list are all useful. Only with the ESP32-Lolin-Board must be used for the I2C connection SDA instead of GPIO21 of the GPIO25 PIN.


ESP32 Dev Kit C unpleasant or

ESP32 Dev Kit C V4 unplacerated or

ESP32 NODEMCU Module WiFi Development Board with CP2102 or

Nodemcu-ESP-32S kit or

ESP32 Lolin Lolin32 WiFi Bluetooth Dev Kit


0.91 inch OLED I2C Display 128 x 32 pixels


Mini water pump 5V / 450mA


Resistance 10k


Resistance 1K


NPN transistor BC548 or similar


NPN transistor BC517 or the likeC > = 1a


MB-102 Breadboard Pug with 830 contacts


Jumper Wire cable 3 x 40 pcs. 20 cm M2M / F2M / F2F each possibly too

65stk. Jumper wire cable plug -in bridges for Breadboard


Power supply 5V / 3A


Logic Analyzer

The software

For flashing and programming the ESP32:

Thonny or


Used firmware for the ESP32:

V1.19.1 (2022-06-18).

The micropython programs for the project:

SSD1306.PY Hardware driver for the OLED display API for the OLED display The program for light control

Micropython - Language - Modules and Programs

To install Thonny you will find one here Detailed instructions (English version). There is also a description of how that Micropython firmware (As of 18.06.2022) on the ESP chip burned becomes.

Micropython is an interpreter language. The main difference to the Arduino IDE, where you always flash entire programs, is that you only have to flash the Micropython firmware once on the ESP32 so that the controller understands micropython instructions. You can use Thonny, µpycraft or ESPTOOL.PY. For Thonny I have the process here described.

As soon as the firmware has flashed, you can easily talk to your controller in a dialogue, test individual commands and see the answer immediately without having to compile and transmit an entire program beforehand. That is exactly what bothers me on the Arduino IDE. You simply save an enormous time if you can check simple tests of the syntax and hardware to trying out and refining functions and entire program parts via the command line before knitting a program from it. For this purpose, I always like to create small test programs. As a kind of macro, they summarize recurring commands. Whole applications then develop from such program fragments.


If the program is to start autonomously by switching on the controller, copy the program text into a newly created blank tile. Save this file under in WorkSpace and upload it to the ESP chip. The program starts automatically the next time the reset or switching on.

Test programs

Programs from the current editor window in the Thonny-IDE are started manually via the F5 button. This can be done faster than the mouse click on the start button, or via the menu run. Only the modules used in the program must be in the flash of the ESP32.

In between, Arduino id again?

Should you later use the controller together with the Arduino IDE, just flash the program in the usual way. However, the ESP32/ESP8266 then forgot that it has ever spoken Micropython. Conversely, any espressif chip that contains a compiled program from the Arduino IDE or AT-Firmware or Lua or ... can be easily provided with the micropython firmware. The process is always like here described.


Figure 2 shows the circuit of the project. The part of the already discussed from the first and second Blog sequence.

Figure 2: Waterwork circuit

Figure 2: Waterwork circuit

Like the LED panels, the pump is also operated on the external voltage source, because with a current consumption of almost 0.5A, the supply of the USB bus is limping and the pump only tortures tired. In order for the water to create a height difference of 10 to 15cm, you need 5 volts and a power source that keeps this voltage even when loaded. The freewheel diode on the pump engine is important. It prevents tension tips from killing the transistor at the coil. But please pay attention to the direction of the component when installing.

When booting the ESP32, all GPIOs are switched as inputs. So that the level on the base of the BC517 is clearly determined, I have placed a 10kΩ resistance from base to GND so that the transistor is safe. A high of GPIO12 lifts the level to 2.2 volts, which means that the transistor switches through safely. The power supply lines to the pump should be kept as short as possible and should not be too thin. Jumper cables are unsuitable for production mode because the relatively high line resistance simply drops too much tension. What is converted into heat from the supply line is missing for the mechanical work of the pump.

We check the water level in the glass and in the tub with two soil moisture sensors.

Figure 3: moisture sensor

Figure 3: moisture sensor

Figure 4: soil moisture module

Figure 4: soil moisture module

The trim pots on the two boards are set in such a way that the smallest contact of the sensory bars with the water surface brings the green LED (s) on the bob (Break out board) to light up. The digital output do then goes to low (0V). If the water level drops, the patio rods are released and Do becomes high (3.3V). The sensors must now be placed in the container so that the unit in the tub goes on high when the water level is just below the bottom of the plant pots. Do the unit in the glass must go to high when the falling level in the glass is five millimeters above the suction opening of the pump.

The pump must not run dry!

Figure 5: water supply

Figure 5: water supply

It becomes critical for the plants when there is no more water in the glass. In this case, the alarm is used. I chose an active piezo buzzer because I don't have to worry about creating the sound frequency. For this I let the buzzer sound interval. More on this in the program discussion. As a driver transistor, a BC548 is sufficient here, which I control in the same way as the BC517 on the pump.

The program

The import business is done with four lines.

From machine import Softi2c, Pin code, PWM
From time import sleep,Ticks_MS
From OLED import OLED
import sys

Softi2c I need for the display Pin code for the Softi2c And the transistor control. With PWM I implement the buzzer's impulse control. Breaks with sleep created and Ticks_MS I need for a timer. The class OLED offers an API for the OLED display and sys delivers the function exit() with which I can end the program under defined conditions. This includes that the pump is safely switched off when the program exit. If I ended with Ctrl+C, this happens at a random program area where the pump may be on and could cause "land under" until I can stop it manually.


With variable debug = True I have the option of having a state message out in the terminal area during development at certain points.

I2C=Softi2c(scl=Pin code(22),sda=Pin code(21))

The I2C object I2C I hand over to the constructor of the OLED class together with the display height Heightw in pixels. The width of 128 pixels corresponds to the default value of the optional parameter Widthw and does not have to be specified.

tub=Pin code(23, Pin code.IN)
glass =Pin code(19, Pin code.IN)

The moisture modules deliver to do digital values. A voltage of 3.3V or logical 1 means that the sensor does not immerse yourself in the water. A level of 0V or logical 0 tells us that the feelers have water contact. GPIO23 and GPIO19 feel the levels on the modules as inputs.

pump=Pin code(12,Pin code.OUT, value=0)

The control line for the pump transistor hangs on GPIO12. We declare the PIN as an output in the switched out state, value = 0.

button=Pin code(0,Pin code.IN,Pin code.Pull_up)

The use of the pin object button I have already described above.

pwmpin=Pin code(27,Pin code.OUT,value=0)

I switch the PIN 27 as an outcome with an initial state 0. I use the PIN as a PWM output. I initially set the PWM frequency to 5 Hz and switch the output level to 0 by setting the Duty Cycle to 0, which corresponds to 0%. The values ​​for the tactning ratio (also tactile degree), which are available to the function duty() to be handed over between 0 and 1023, so there are no percentage values. 1023 delivers a constant voltage of 3.3 volts on the GPIO pin. At 50% or 512, the pulse duration is half of the period.

Figure 6: Frequency, period duration and duty cycle

Figure 6: Frequency, period duration and duty cycle

def Time-out(T):
   def compare():
       return intimately(Ticks_MS()-begin) >= T
   return compare

Usually, objects that are declared within a function are not visible locally and outside the function. You hike to nirvana when the function is left. This can be avoided by the function of objects with return returns. Normally, this will be the values ​​that were calculated within the function or, for example, charged via GPIO pins.

Time-out() now does not give numerical value, but the function compare() Back, more precisely a reference to it. When calling Time-out() If a period of time in milliseconds on the parameter T hand over. In begin the current status of the millisecond counter is then saved. compare() subtract this value from the continuously updated stand and compares the difference value with the period in T and gives True back if the difference value in T exceeds. Then the timer expired.

Time-out() therefore gives a reference to the function compare() Back that we can remember in a variable.

>>> period=Time-out(5000)

This trick remains access to T, start and the function compare() even after leaving the function Time-out() receive. period is a Alias for the name compare. In period the reference is on the function compare() and we call them now.

>>> period()

We get the current status of the time of time as a return value of compare() delivered.

If the last input takes place within 5 seconds after the first instruction, it will False be then then True.

With the Closure Time-out() we have realized a software timer that does not block the program as it does sleep(5) does. Because between two calls of period() Can the ESP32 do any other things. Closures are already among the secret weapons of Micropython. For example, points counters can also be elegantly programmed in games, game status and many other things.

def pump(Val=None):
   assert Val in (0,1,None)
   IF Val is need None:
       return state[pump.value()]

The function pump() first determine whether for Val the correct value was handed over. Without handover when the value is called up, has Val The default value None. That leads in Else-Branch to ensure that the plain text "on" or "from" from the list state is returned. Is Val not None, then the value passed is used to switch the pump (1) or switch off (0).

def sound(duration,freq=8):
   while need period():

the function sound() takes in the position parameter duration A period of time in seconds and in freq A frequency in Hertz. This switches the PWM output with a Duty Cycle of 50%. The default value for freq Is 8. That means that the buzzer cheats 8 times a second. The seconds in duration Let's convert it into milliseconds and thus present the timer period. As long as period() (aka compare()) We have not yet received False. With passport If we meet the condition that a loop body must not be empty. This instruction does nothing, it is just there. Delivers period() a True, then this ends the loop and we just have to switch off the tweeter before we leave the function.

def water level():
   clan=tub.value() # 1 = empty; 0 = full
   level glass=glass.value()  
   IF debug: print("Tub",clan)
   IF clan == 0:
       IF debug: print("Tub: level OK")
       return 1 # Tub ok
       # Tub too little
       IF debug: print("Glass",level glass)
       IF level glass==0:
           IF debug: print("Glass level ok, pump")
           pump(1) # Water from the glass to the tub
           return 2
           IF debug: print("Fill the glass")
           pump(0) # Pump out
           sound(2,5) # No water in the pool
           return 0

The function water level() must map three situations:

  • The tub is sufficiently filled, ok
  • There is too little water in the tub; There is enough in the storage glass, the tub can be refilled
  • The glass is also empty; trigger alarm

We first read the water levels. If debug the value True has the level state in the terminal area. If the sensor reports a 0, then everything is ok and no action has to follow unless the pump has been on beforehand, then it has to be switched off because the water level is now right. We return 1 to the calling program.

Is clan But 1, then we should refill water. Look at whether there is still water in the glass. Then has level glass The value 0. We throw the pump on and give a 2 back.

Otherwise the water supply is over and we have to quickly switch off the pump because it shouldn't run dry. Now it is important that the sensor in the glass is not too deep so that the pump is off before the water level reaches the suction opening.

We let the buzzer beeped 5 times a second for two seconds and give 0. In the calling program, this would be False interpreted, while every other value than True is applicable.

The main loop now only has to be the function water level() call up that does everything necessary. We let the condition output in the terminal, ask the flash key and send the ESP32 to bed for a second.

Figure 7: water level sensors

Figure 7: water level sensors

Now we only lack the temperature control. In the next part, I will use a thermocouple as a heat source together with two heat sinks as a heat exchanger. In principle, this is nothing more than a heat pump. Of course, the temperature of the warm side must be monitored, because it must not be higher than 138 ° C. In addition, we measure the temperature in the substrate with a waterproof packaged DS18B20.

Stay tuned!

Until then

DisplaysEsp-32SensorenSmart home

Leave a comment

All comments are moderated before being published

Recommended blog posts

  1. ESP32 jetzt über den Boardverwalter installieren - AZ-Delivery
  2. Internet-Radio mit dem ESP32 - UPDATE - AZ-Delivery
  3. Arduino IDE - Programmieren für Einsteiger - Teil 1 - AZ-Delivery
  4. ESP32 - das Multitalent - AZ-Delivery