HackSpace magazine

In the workshop: soil moisture

By Ben Everard. Posted

This summer has certainly been funny weatherwise. Blazing hot in spring, then a bit damp throughout June and July with occasional blasts of heat. That means it’s been a bit difficult to get into a routine of when to water. On busy days, it’s easy to forget until you suddenly see a wilted green mess where your vegetables used to be. Yes, it’s a bit late in the year to be worrying about this, but now is the time to get things up and running ready for next year.

There’s a range of soil moisture probes around with different features. The cheapest and most common have two prongs that test the resistance of the soil, but these have the disadvantage that they gradually break down due to electrolysis. The other option uses capacitive sensing to read the soil moisture – these are slightly more expensive, but should last much longer. This is the option that I went with.

As well as a sensor, we need a controller, and for almost anything wireless, the ESP32 is my controller of choice at the moment. As well as having WiFi, it’s got support for deep sleep which should mean that I can get a long run time (I’ll be running it by battery in the garden).

It wouldn’t be too much work to build a circuit from scratch, but to make matters even easier, a few companies make boards that combine everything into a single PCB. I opted for an ESP32 soil moisture meter from DIY More. These are available on direct-from-China websites for around £10, not including the 18650 Li-ion battery, which come in at about £5 for two 3600 mAh capacity batteries. This module also includes a DHT11 temperature and humidity sensor. These aren’t particularly accurate, but as it’s included, I decided I may as well monitor the output.

A key part of the puzzle for this project is energy efficiency. After all, there’s no point in this if I just replace watering every day with recharging the batteries every day. There’s a whole bunch of techniques that you can use to reduce power consumption on the ESP32 such as reducing the clock speed and minimising the WiFi usage, but I decided to focus my efforts on just one – deep sleep.

You can see the complete code for this project at: hsmag.cc/VmEzta.

The ESP32 module and DHT11 are mounted together on the top half of the PCB

On the ESP32, deep sleep isn’t really like putting your computer to sleep; it’s more akin to turning it off and back on again. Everything stored in RAM is lost (there are ways around this for small amounts of data), and the sketch starts from the beginning again. For our purposes, this isn’t a problem as we just want to read the sensor values and send them off to the internet. When it’s in deep sleep, it uses very little power (around 10 microamps), so we don’t need to worry too much about this level of current consumption when we have 3600 mAh to play with. When the unit is taking readings, it’s a short amount of time so power usage isn’t a problem.

Putting an ESP32 into deep sleep is fairly straight forward in Arduino. First, you need to set a wakeup source with:

esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);

This is done with two defined values: the amount to sleep in seconds, and the multiplication factor to take this into microseconds, which is what the ESP32 uses. When we want to go into deep sleep, we then use:


In principle, that should be enough, but for some reason, I couldn’t persuade my device to sleep for more than 25 minutes. No matter what value I put in the TIME_TO_SLEEP definition, the board would wake up after a maximum of 25 minutes. After searching for a solution for a while, I decided to go with the simplest hacky solution, and that is to count how many wake-ups there have been and only read the sensors / do some processing after a certain number of wake-ups. In other cases, I’ll just shut the device down again.

This does cause a slight problem because variables aren’t held between boots, so how can we know how many times it’s booted? The solution is in the real-time clock (RTC). This is the part of the ESP32 that wakes up the main core after a certain amount of time. There’s a small amount of memory on the RTC that we can use to store bits of information like this.

In the Arduino language, we can declare a variable that will be held in the RTC memory with the following:

RTC_DATA_ATTR int bootCount = 0;

Then, we can reboot the machine every time we don’t need it with the following at the very start of the setup:

++bootCount;   sleepus = TIME_TO_SLEEP * uS_TO_S_FACTOR;   esp_sleep_enable_timer_wakeup(sleepus); if(bootCount !=3) { esp_deep_sleep_start(); } bootCount=0; // this will only run on the 3rd boot.

This is a pretty hacky solution, but it did give me a chance to play with the RTC variables. If you can spot what the bug is in my code to make it necessary, please get in touch.

The deep sleep option on the ESP32 is great for getting large uptimes from battery-powered devices

How long will it last on a battery? We’ve no idea! The current consumption of the unit is very low (under 1 mAh per hour), but the batteries aren’t necessarily their stated capacity, and even if they are, they won’t necessarily respond particularly well to this style of use. The one feature that this board doesn’t have, that we’d like, is a way of checking the battery level. It’ll just suddenly stop working at some point. Hopefully, it’ll take several weeks (or ideally a few months) before I find out how long it lasts. The final part of the puzzle will be calibrating the moisture level. That will just be a case of seeing what readings it gets at different levels of moisture, and seeing what corresponds to unacceptably dry.  


From HackSpace magazine store