Soil moisture sensor with WiFi

Posted by

In summer, I have a lot of potted plants out on the balcony, and I need to know when to water them. Indoors, most of my home automation gadgets are based on MySensors, but out on the balcony the signal is too weak, so I needed something WiFi-based, but without the high battery consumption typical of WiFi solutions.

This was an opportunity to learn about optimizing a WiFi based gadget for low power consumption, and I will share my insights with you here.

Building blocks

The solution consists of

  • an ESP32 module with custom software
  • a cheap plastic case protected by an upside-down Ziploc bag
  • a pair of AAA batteries
  • up to 4 cheap capacitive soil moisture sensors, of the kind you find on Aliexpress for less than a Euro
  • my home network, with a DHCP server assigning pseudo-static IP addresses to everybody (based on MAC address)
  • my home automation system, with an MQTT broker and OpenHAB for visualization and control

As always, full documentation including source code, hardware schematic and a requirements specification can be found on Github.

Design decisions

How to make it waterproof-ish

There will be rain out on the balcony, so the modules need to be waterproof-ish. Real waterproof sealed cases are expensive, so I opted for a cheap plastic case with a Ziploc bag over it, with the opening facing down … good enough for the intended use case.

Processor

The final design uses an ESP32-WROOM module.

I also tried a ESP32-C3 “Super Mini” module, the source code supports this. This is a single core RISC-V based processor, with the following pros and cons, compared to the ESP32:

  • Pro: lower current draw when WiFi is on, I observed about 50 mA vs 130 mA
  • Pro: easy to use the little development module in a production system, because it has no USB-serial chip that would consume power all the time, the ESP32-C3 has builtin USB capability
  • Con: higher current draw during sleep, I measured about 40µA
  • Con: unreliable WiFi connection. I think this is probably a property of the module rather than the ESP32-C3 chip, because of the tiny antenna — but that was a knockout criterion for me

Addendum 4-Oct-2024: the unreliable WiFi connection with the ESP32-C3 probably has nothing to do with the processor per se, but with the board layout: the module I bought from Aliexpress looks exactly like the “bad module” shown in this post.

Minimizing power consumption

  • a bare ESP32-WROOM module is better than a development module — no power-consuming voltage regulators and USB interfaces. Power consumption during deep sleep, with a bare ESP32-WROOM, powered from 2x AAA battery, is 14µA.
  • To avoid any power loss through a voltage regulator, I am running the ESP32 directly from a pair of AAA batteries. Newer processors will work down to 2.3V, I just had to make sure the soil moisture sensor also works below 3V (see below).
  • to minimize the time the processor is awake, and in particular the time that Wifi is active, I try to reconnect to Wifi using previously established SSID, IP and channel number, which are cached in RTC memory.

Hardware

I used a 7×9 cm prototype board for ESP32 and ESP8266 boards, cut to fit inside a 100x60x25 mm plastic case. The soil sensors are connected via cables with an RJ12 6P4C connector on the module end, for easy connection “in the field”.

The capacitive soil sensors I got from Aliexpress use an NE555 chip that only works down to 3.0V, whereas the ESP32 itself will still work when the battery voltage is as low as 2.5V, so I replaced the NMOS NE555 with the CMOS version ILC555D, which work down to 2.0V. I also bypassed the voltage regulator on the sensor board.

Battery life

These factors contribute to power consumption or battery drain, in decreasing order of importance:

1. the self-discharge of the AAA batteries, according to this post, about 35 µA or 0.84 mAh per day

2. deep sleep, at ~14 µA or 0.34 mAh per day

3. wake time with WiFi on, up to 130 mA x ~300ms per wakeup every hour or 0.26 mAh per day

4. wake time, with WiFi OFF, 50 mA x ~300ms per wakeup or 0.10 mAh per day

This results in a battery life in excess of 500 days, good enough for me. Note that I have brought the design to the point where overall power consumption is dominated by the self-dischange of the Alkaline batteries, so there is no point in attempting to further optimize the power consumption of the processor module.

Lessons learned

Some things are outside of my control

The performance of the device, in terms of power consumption or battery life, depends of course on the design of the device itself and the design decisions I made (processor, program flow, etc.), but also on external factors that I cannot control. For example, power consumption depends on wake time, which is the aggregate of

  • the time between turning on sensor power, and making measuring the sensor voltage — I chose 100ms, which appears to be enough for the sensor voltage to settle
  • the time to re-connect to the WiFi access point, using stored information about WiFi channel, SSID etc — this takes about 160ms most of the time, but sometimes can take as much as 2-3s
  • the time to look up the IP address for the MQTT broker, usually 20-40ms
  • the time to connect to the MQTT broker, mostly 30ms, but sometimes up to 500ms, which I can’t explain
  • the time to send MQTT messages — I can influence this, by deciding how much information to send
  • the time to disconnect from the WiFi access point — mostly about 20ms, but sometimes as high as 130ms, which I can’t explain

An almost easy project

I found it fairly easy to create a first version of the code that sort of worked most of the time. Then I began to notice the rough edges, and it took a lot of time to get those fixed:

  • easy: making measurements and reporting them via MQTT. Harder: get the measurements to be less jittery, and less affected by varying current consumption due to WiFi activity. I now get all the ADC measurements done before turning on WiFi.
  • allow configuration changes via MQTT, and acknowledge the command by deleting the topic. Easy: get it to work most of the time, with occasional loss of a message. Harder: make it work every time, by inserting delays here and there, without a massive increase in the overall wake time

2 comments

  1. This is an extremely interesting project. I’ve thought about doing something similar for years.
    I’m blown away that are able to get one year+ on 2x AAA batteries using WiFi backhaul!

    Things I had considered in my imagination-desgin phase:
    1. Using Z-Wave LR (or LoRA) for wide area coverage, expanding the covered area without needing to build out a supplemental WiFi network. The obvious con for ZW or LoRA, is the firmware development (which would be harder (for me at least)).
    2. Using a small solar panel to charge the battery pack, making the device closer to “maintainence free”. A one-year battery life is pretty incredible, but even 12 battery operated IOT devices in your universe, and your IOT starts to feel a bit like “monthly maintenance”. :-).
    3. Using “DS18B20” onewire sensors to simplify wiring in the field, possibly enabling use of unused pairs on pre-existing sprinkler wires.
    Again, very nice work, and thoughts welcome on points 1-3.

  2. Thanks for the flowers 🙂
    Please note that the 12 months on a pair or AAA is a _prediction_ based on _measured_ power consumption. So far, it looks realistic, the sensors deployed in early June are now (October) at 2.8V
    re 1: I have no experience with Z-wave or LoRA, and I needed something quick & dirty …
    re 2: yes, I thought about small solar panels, too, maybe next year …
    re 3: well, I needed soil moisture sensors, the DS18B20 is a temperature sensor, afaik. I had thought about continuing to use these cheap Aliexpress soil moisture sensors, and attaching a small ATtiny to the back end of the sensor PCB, to turn it into a onewire client

Leave a Reply