ESP32 Low Power Device Design – Part 1

The ESP32 is a remarkable chip. It has many peripherals, lots of processing power. With built-in WiFi und BLE support it offers two widely adopted communication protocols. And with the right circuitry and programming it can ran from batteries for a very long time. In this post I’d like to share some lessons learned from designing a simple IoT application.

In this post we will be designing a typical but simple IoT application: a mailbox sensor. Building a mailbox sensor might not be the most exciting project you will ever build. But it is a good example to show a couple of concepts. In this first part we will build a mailbox sensor which wakes up when the state of the mailbox door sensor changes. It then connects to WiFi and to an MQTT broker, sends the state of the door and goes back to sleep.

In the second part we will further improve battery lifetime by using the ESPNow protocol. This proprietary protocol allows the ESP32 to be awake only for a short time. This safes energy and also sends the door state notification much faster.

Hardware Requirements

This project is built around the ThingPulse ePulse dev board. This board is designed with battery driven projects in mind and consumes only 25uA in deep sleep. I was involved in designing this board. In this post I describe why this is the dev board I always wanted.

Further you will need a reed switch to sense the state of the mailbox door. Reed switches are mechanical contacts which change their state in the presence of a magnet. You can buy them either in their bare form as little glass tube or built into a plastic enclosure to be used as door sensor.

As power supply we will use a battery pack with 3xAAA batteries. You can also use a LiPo/Li-Ion battery pack or the smaller AA batteries.

ThingPulse ePulse ESP32 Dev Board, consuming only 25uA in deep sleep.
USD $16.90 at ThingPulse

3xAAA Battery Pack
USD $1.50 at Banggood
(Affiliate Link)

Door sensor
USD $1.80 at Banggood
(Affiliate Link)

Connecting Components

Connecting the components is easy. Either you use a bread board to set everything up or you solder the battery pack and the door sensor directly to the ePulse dev board. When you get the ePulse dev board the male header pins are not soldered yet, so it is very easy to connect other components to it.

Connect the door sensor to GPIO15 and GND and the battery pack to VIN and GND. Make sure you get the polarity right!

Software

The software project I prepared here for this post assumes that you have a MQTT broker setup and available in the same network that the ESP32 will be connected to. In my setup the ePulse publishes the message to a MQTT broker running on a Raspberry Pi. The excellent Node-Red software also running on the Raspberry Pi is subscribed to the MQTT topic and forwards the message to the Pushbullet API. I then get a notification on my smartphone that the door has been opened.

MQTT is a good solution for this project because messages can be quickly pushed into a queue and the ESP32 can go back to sleep fast. In average one message push takes between 1.5s- 2s before the ESP32 enters deep sleep mode.

If you have git installed then do a

git clone https://github.com/squix78/esp32-door-sensor

Alternatively you can also just download a zip file from github containing the project. I’m using for most of my advanced project the platformio development platform with the Visual Studio Code editor. If you haven’t done so already head over to https://platformio.org/platformio-ide and download the Platformio IDE (which is VSCode + Platformio plugins).

Platformio offers many advantages over the Arduino IDE. The later was designed for beginners but as a professional software developer I am missing many features, such as dependency management. In this project I have already defined which libraries we need in the platformio.ini file. If we were to use the Arduino IDE you’d have to download the libraries manually.

Before we connect the ePulse to your computer and upload the firmware we have to make a few adjustments to your local setup. Open the settings.h file and change your WiFi and MQTT settings.

#define REED_PIN 15

#define WIFI_SSID "yourssid"
#define WIFI_PASSWORD "yourpassw0rd"

#define MQTT_HOST IPAddress(192, 168, 0, 100)
#define MQTT_PORT 1883

#define MQTT_TOPIC "ESPNOW/1"

Attention!: Programming the ePulse

Every time you connect the ePulse to your computer make sure that the battery pack is empty. If you don’t you might either destroy your USB port, the ePulse or overheat the batteries. So: just make sure the battery pack is empty!

Understanding the Code

The code uses some interesting concepts which you might not be familiar with. This program is entirely event driven. This means that methods get called when certain events occur. Let’s have a look at the WiFi connection:

void setup() {
   ...
   WiFi.onEvent(WiFiEvent);
   ...
}

This sets a callback method called WiFiEvent. This method get’s called whenever something happens to the WiFi connection:

void WiFiEvent(WiFiEvent_t event) {
    Serial.printf("[WiFi-event] event: %d\n", event);
    switch(event) {
    case SYSTEM_EVENT_STA_GOT_IP:
        Serial.println("WiFi connected");
        Serial.println("IP address: ");
        Serial.println(WiFi.localIP());
        connectToMqtt();
        break;
    }
}

Here we are only handling the SYSTEM_EVENT_STA_GOT_IP. As soon as we have an IP we can connect to the MQTT broker. In many existing WiFi examples you have a loop which checks if the state of the WiFi is connected.

In software development we call this a “polling loop” which might cost more time (and energy) than necessary. By using a call back we get informed when the system is ready to proceed.

This pattern continues throughout the code: when the device is connected to the MQTT broker we publish the door state. When the message has been successfully sent we tell the device to sleep.

Once you get the hang of it this pattern is very convenient.

Lessons Learned – Energy Consumption

After I had the code running I wanted to make sure, that the door sensor really is as efficient as I expected it to be. I attached the excellent CurrentRanger device to measure the sleep consumption of the device. It turned out that it wasn’t efficient at all!

Current Ranger | LowPowerLab
The CurrentRanger by LowPowerLab is an excellent device to measure deep sleep current of IoT devices. While your average multimeter will cause issues when measuring deep sleep current the CurrentRanger can handle it.

It consumed sometimes up to 1.5mA in deep sleep! This is about 60 worse than the 25uA I hoped for. So what caused this consumption? I tried many combinations: using the ext1 wakeup component rather than the ext0. Without setting the wakeup at all. Without WiFi. Many combinations used exactly the same high 1.5mA!

After many experiments I finally found this issue on github which suggested to use

adc_power_off();

to power off the adc block before deep sleep. This finally fixed the issue.

Thanks to the CurrentRanger I discovered another problem. The internal pull up resistor consumes about 75uA in deep sleep when the door is closed. When the door is open the device only consumes 25uA in deep sleep.

Because of this I will probably install the sensor in the mailbox so that it triggers when the lid is moved. For this particular application I’m more interested, that there was movement rather than the actual state of the door/lid.

3D Printed Enclosure

Dangling wires above your door frame are not really family friendly. So I designed a simple box which fits all components neatly. The lid and the box have snap-fit design and close without screws. You can download the STL files from thingiverse.

Outlook Part 2

In part one we connected the ESP32 over WiFi to a MQTT broker. Establishing a secure WiFi connection takes a lot of time and costs energy. If we’d like to further improve energy consumption we need to get rid off this costly WiFi handshake. The solution to this is called ESPNow. It is a proprietary protocol using the same hardware and frequencies that the WiFi protocol uses. A device can send a message over ESPNow in the fraction of the time it would take to send the message over regular WiFi.

This is great for battery runtime, but also comes at a cost. In order to use ESPNow your door sensor needs another ESP8266 or ESP32 acting as an access point or gateway for the sensor. This gateway listens for ESPNow messages and forwards them over regular WiFi to your MQTT broker.

Interested? So stay tuned for part 2!

Summary

In this post we built a simple door sensor which can run in theory for a year or more from 3 AAA batteries. This is possible because unlike many other ESP32 development boards the ePulse board consumes very little energy when sleeping. Door sensors are the perfect use case for such a board: in a regular home door states change only a couple of times per day. The rest of the time the device is sleeping.

blank
Posted by Daniel Eichhorn

Daniel Eichhorn is a software engineer and an enthusiastic maker. He loves working on projects related to the Internet of Things, electronics, and embedded software. He owns two 3D printers: a Creality Ender 3 V2 and an Elegoo Mars 3. In 2018, he co-founded ThingPulse along with Marcel Stör. Together, they develop IoT hardware and distribute it to various locations around the world.

3 comments

  1. Thanks for the post, Daniel. Between you and Andreas Spiess, today is the Low Power Day!
    One idea for your 75 uA when closed, 25 uA when open problem. You might consider using a Normally Open reed switch? The type in your post is Normally Closed. Perhaps this also requires a logic change in your code – I haven’t looked. A resistor inline with the switch may also help. I’m working on a similar device for my garage door using an ESP-12 and am using a mercury switch. The mercury switch can be mounted to be N/O, or N/C.

    I noticed the link to Thingiverse leads to a 404 error. Thought you would want to know.

    • Thank you Craig for the comment and your input. You could even call it the *Swiss* Low Power Day:-)! I didn’t synchronize with Andreas, pure coincidence!

      Good point about the default state of the reed switch. I will look if I can find something about it. I was briefly considering to use a pull-down circuit but I guess that wouldn’t solve my problem?

      Also many thanks for the hint with the 404, I fixed it. Looks like my thing on thingiverse just vanished.

      • Good of you to reply and thanks again for the post. The Thingiverse box looks great. I’ll probably download and order one (Treatstock is my printer!) I especially like the lid clip.

        Pin-change-interrupt is what I would like to achieve for low power. At one point I thought I had if figured out but never mastered it on PIC’s or ESP’s. The idea was to sleep until a pin change interrupt. Someday I’ll get to it. It sounds like that is what you were after. I’ll follow-up if I do!

Leave a Reply