Self-watering garden proof of concept driven by MicroPython on ESP12 / ESP8266
ESP modules are very versatile and carry enough RAM / flash memory to run high level code written with MicroPython.
Here you will find a (functional) proof of concept of autonomous watering of orchids and houseplants. The cost is a few euros.
See programmation paragraph to know how the workflow works.
-
ESP-12F
Based on a ESP8266; supporting network connectivity via WiFi. Associated or not with a development board.
-
Capacitive Moisture Sensor
This one is corrosion resistant. Contrary to resistive sensors, there are no metal parts (probes) exposed with the soil. Thus, there will be no oxidation due to electrolysis degrading the sensor in the short term.
-
Nebulizer disc with capillary (Ø 20mm)
-
USB mini pump
-
Two low active relays are used:
- for a classic pump
- for water nebulizers
PS: Active high relay is possible but will require a little modification in the code.
-
Silicone/polyethylene pipes
- EN (CH_PD) Enable Pin has to be pulled up => resistance not / not very useful
- RESET Pin has to be pulled up (R5)
- GPIO15 has to be pulled down => must be LOW to boot, no resistor here but it's mandatory if the port is used
- GPIO2 has to be pulled up Internal pull-up is available and used (no external resistor required)
- GPIO0: Manual LOW for flash mode
- GPIO16: Connected to RST in order to use wakeups based on timers (deepsleep mode)
See more on esp8266-pinout-reference-gpios.
- Classic pump: Pin 2
- Water nebulizers: Pin 12
- Humidity sensor: ADC0
Relay pinout | ESP pinout | Description |
---|---|---|
IN1 | GPIO2 (OUTPUT) | Control of the first relay |
IN2 | GPIO12 (OUTPUT) | Control of the second relay |
right GND | GND | Common ground |
right VCC | 3.3V | Optocoupler power supply |
left GND | - | Common ground |
JD-VCC | 5V (USB) | Relays power supply |
JD-VCC pin is optionally used to power the relay with a different voltage from that of the optocoupler (ESP side). This will guarantee a perfect galvanic isolation.
100uF capacitor shown on the seller's pictures is frequently missing. It should limit noise on the power supply but everything seems to work without it.
If the ESP12F/ESP12E support a maximum Input High Voltage (VIH) of 3.6V, their analog-digital converter accepts a voltage range from 0 to 1V (datasheet).
AD conversion, Input voltage range 0-1V, the value range is 0-1024.
See also: esp8266-adc-reading-analog-values-with-nodemcu.
Contrary to what is mentioned everywhere on the web, the sensor must be supplied with a minimum of 5V (does not work at 3.3V). The NE555 circuit (timer), responsible for the output voltage, operates between 5 to 16V. The datasheet indicates that the output voltage is however limited to 3.3V for a VCC of 5V.
However, some PCBs use the ICM7555 timer (datasheet)
VOH: typical voltage: 4.5V for VCC 5V
Warning!!! In practice I have already measured 3.8 to 4V on this pin.
If you use a bare ESP device (not on dev board with an internal voltage divider) you WILL need a voltage divisor for this sensor. Adapt the voltage divider bridge to YOUR situation.
See calculator:
http://www.learningaboutelectronics.com/LesArticles/Calculatrice-diviseur-de-tension.php
Example of divisor bridge 4V => 1V:
Sensor output --- R1 --- GPIO 1V --- R2 --- GND
Vout_gpio = Vin_sensor * R2 / (R1 + R2)
Let's choose R2 = 5K; R1 = 10K
Or R2 = 2.6K; R1 = 5K
100% water:
2.05V
analogRead: 297
0% water:
3.83-4V
analogRead: 378
By default the module will wake up every 1 hour to check if something needs to be done (the deep sleep timer cannot exceed this duration by much). Nebulisators are triggered every 12hours for ~2minutes. Pump is triggered every week; however a humidity check can postpone a trigger during the 5 next days if humidity is satisfying. Relay is triggered 2 times during 7s each, with a pause of 5 minutes.
For safety purpose, if case of reboot due to a power failure, the pump counter is set to half the value of _PUMP_COUNTER. Thus nebulisator counter is set to 0 for instant triggering.
For logging purpose, at the end of a wakeup, a report url is forged with current status of timers and sensors.
Configuration is available in global variables at the top of the program. To disable a trigger, put a duration of 0.
Underscore "_" is a memory optimization for MicroPython (See MicroPython - Memory).
# Pinout
# Relays are low level triggered: default value to HIGH
PUMP_RELAY = Pin(2, mode=Pin.OUT, pull=Pin.PULL_UP, value=True)
NEBULISATORS_1 = Pin(12, mode=Pin.OUT, pull=Pin.PULL_UP, value=True)
HUMIDITY_SENSOR = ADC(0)
# Network config
ESSID = ""
PASSWORD = ""
LAN_CONFIG = ("192.168.1.77", "255.255.255.0", "192.168.1.1", "192.168.1.3")
REPORT_URL = "http://192.168.1.3/esp8266?"
# Accepted humidity level; if below: pump is triggered
_HUMIDITY_THRESHOLD = const(60)
# Nb of wakeups (in hours) between each trigger
_PUMP_COUNTER = const(6 * 24) # every day
_NEBULISATORS_COUNTER = const(12) # every 12hours
# Durations (in seconds)
_NEBULISATORS_DURATION = const(135) # 2min15
_PUMP_DURATION = const(7) # 7s Duration for each trigger
_PUMP_INTER_SLEEP = const(300) # 5 * 60 # Small pause between 2 triggers in a same session
Keep in mind that time management is not accurate. The RTC clock drifts about 10 minutes in either direction, every hour. It does not matter for this type of application.
The humidity sensor should be calibrated by measuring the returned voltage in different situations to determine the desired threshold for triggering watering. Ex: out of water, in dry earth, in damp earth, in water.
Ex:
Dry: [520 430]
Wet: [430 350]
Water: [350 260]
From the docstring of get_humidity_percent()
.
Calculation of coefficients
Solve the following system:
100% = MaxRawValue * x + y
40% = MinRawValue * x + y
With MaxRawValue=297 for 100% water, MinRawValue=378 for 0% water
y = 40 - MinRawValue (60 / (MaxRawValue - MinRawValue))
x = 60 / (MaxRawValue - MinRawValue)
... or just copy code from https://rosettacode.org/wiki/Map_range#Python
Install requirements:
$ pip3 install -r requirements.txt
or
$ make install
Flash command:
$ ampy -p /dev/ttyUSB0 put main.py
or
$ make upload
Bytecode compilation for ESP8266:
$ mpy-cross -march=xtensa main.py
or
$ make upload_bytecode
Do not forget to add the following lines to your boot.py
on the device:
import main
main.main()
Reset/reboot:
RST pin to LOW
Reboot in bootloader mode:
GPIO0 to low
- Post logs to a MQTT server
- Get correction orders from user via a MQTT server
- Display stats and orders on a web page
- Use an air humidity sensor to control operation