Building a soil humidity sensor for pot plant

Upload Code and Push Data over Internet

Deepsleep vs. interval sampling

To sample the humidity content with a fixed interval, in the main loop we can create a variable to keep track the last time it ran sampling

//pseudo code  **INTERVAL SAMPLING**
void setup(){
    // initialize libraries
    // run only one at starting up
int interval = 60 //seconds
int lastSample = 0 //seconds
void loop(){
    // run repeatedly
    int uptime = millis()/1000;
    if ((uptime-lastSample) >= interval){
        //only run this if more than 60 seconds has passed
        // read humidity content
        // push data to MQTT server
        lastSample = uptime; //update 

This is fairly straight forward implementation. It works well if the power supply is pluged into the wall. The power consumption during wireless communication can be unforgiving for a battery, upto 400mA. I saw 200mA for ESP8266 is typical.

The solution, as you might now, it to turn off ESP8266 partially or put it into deepsleep mode. According to espressif, in deepsleep mode, the current requires is ~20µA, a 10,000 times than a constant on mode.

power consumption

I'm not trained in electrial engineering, but here is my best effort for a rough calculation for 1000mAh at 3.7V = 740mAh at 5V = 1009mAh at 3.3V with 90% efficiency conversion from 5V to 3.3V. For a constant 200mA current, a 1000mAh lithium battery lasted for 5h not taken into account of self-discharge. For an interval of 60 seconds, I observed about 13-15 hours by one 1000mAh battery.

Now, if you convinced that we should try to run ESP8266 in the deepsleep mode, here the pseudo code

//pseudo code **DEEP SLEEP**
int interval = 60e6 // 60e6 microseconds = 60 seconds
void setup(){
    // initialize libraries
    // read humidity content
    // push data to MQTT server
    // ESP will put into the deepsleep mode and waked up by GPIO16 by triggering RST pin
    // the setup loop run every the ESP is waked up
void loop(){
    // this will not be run

Now, this is the excerpt of the code. The full code is hosted in Note that I selected 20 minutes for each cycle of waking up, sampling, then sleeping.

//excerpt code **DEEP SLEEP**
void setup() {
    Serial.println("Starting Node named " + String(SENSORNAME));
    pinMode(blueLED, OUTPUT);
    if (ds18b20.getDeviceCount() == 0) {
        Serial.printf("No DS18x20 found on pin %d.\n", ds18b20PIN);
    client.setServer(mqtt_server, mqtt_port);
    flashLED(100, 3);
    ds = ds18b20.getTempCByIndex(0);
    hum = getMoistureReading();
    while (hum >=1000){
        hum = getMoistureReading();
    int bat_ = analogRead(A0);
    bat = (bat_/900.0)*4.12;
    lastSample = round(millis()/1000);
    ESP.deepSleep(12e8); //12*100 seconds == 20mins; 10^6=1 second
void loop(){
    // this will not be run

Forcing the Chirp in I2C can be tricky. The screenshot below indcated I succeded operating the sensor by pressing the reset button when the blue blue was flashing (right before the an I2C was sent to the Chirp.)


If you are not familiar with MQTT, here is another tutorial to setup an MQTT server with a $35 Raspberry Pi. ThingSpeak is another platform you should consider if you don't have a dedicated computer to host the MQTT server or you want to see the data outside your home internet.

Following is some graphs for 3 modes: a 5-min interval sampling, a 20min deepsleep and a 20min deepsleep with a small solar panel.

solar charger

OK, so what is about the humidity content in the soil. Basically, a smaller number is drier. In my case 300 is when the sensor is in the air. That would be the condition that tree roots does not wanted.

humidity chart

And, finally, here is how the soil humidity sensors look like,

Was every thing that easy?

Yes, and No. Yes: You should have less hiccups than myself. No: there were bumps on the ways.

First, after two nights, I checked the humidity sensor and saw that the system CHIRP was not in I2C mode, which means the ESP8266 cannot read the humidity level over the I2C. Resetting by the RST pin did not help. Because I am so invested into the CHIRP, I was committed to figure it out. If not, I would reconsidered to use the capacitance sensor with the analog output, instead.

This blog post offered a nice solution to reset the Chirp sensor if I2C returned an invalid reading. However, I tried to adjust the delay time between 1 to a few thousands microseconds but the Chirp was not operated in the slave mode. Finally, I placed a flash led after the soft reset to manually reset by pushing the button on the top of the Chirp. It should follow by a bright LED flash and the Chirp now is in I2C mode. Subsequent readings, including in sleep mode, should work automatically.