In Part 1 of this series, Brian discussed the benefits of the ESP-NOW protocol, and shared how it improved battery life in his ESP-based leak detector modules. In Part 2, Brian describes the circuitry and programming of the various modules making up his ESP-NOW home control system.
In Part 1 of this article (Circuit Cellar 368, March 2021 ), I discussed the advantages of using the ESP-NOW protocol with Espressif’s ESP32 and ESP8266 MCUs when low power consumption was important. I described the ESP-NOW API, and how it is used for either ESP8266 or ESP32 MCUs, in both controller and a remote (combo) roles.
I also contrasted the power consumption data for ESP8266 MCUs in either the conventional Wi-Fi mode (connected to your home wireless access point) or the peer-to-peer NOW protocol. For my leak detector modules, this improved the battery life from about 100 days up to about 900 days (ignoring any LiPo cell self-discharge current). Here, in Part 2, I will describe the circuitry and programming of the various modules making up my ESP-NOW home control system.
Please refer to Figure 1 for the schematic of the leak detectors. Since I was going to design a PCB for the leak detectors, I decided to use an Espressif ESP-WROOM-02 module, which contains the ESP8266 on a small board with castellations. In the past, I generally used the Adafruit ESP8266 Huzzah breakout board. It works great but contains some circuitry that increases the overall power consumption. I added the RESET and PROG pushbutton switches, and R6, R7 and R10, which are needed to pull three GPIO pins to the level needed to boot up the ESP8266.
The leak detector’s PC board has a footprint for the Aosong Electronics AM2320 temperature/humidity sensor (from Adafruit). This is optional, and I didn’t mount it on all three boards (fabricated by Oshpark). However, the I2C pull-up resistors, R1 an R2 must be fitted, because the Microchip Technology MCP79401 real-time clock (RTC) chip connects to the ESP8266 via I2C.
Leak detection is done using GPIO16. This is pulled up to VCC by R4, a 1MΩ resistor. One of the two detection leads is connected to GPIO16 through a 10kΩ current-limiting resistor. The other detection lead goes to ground through another 10kΩ resistor. When the leads are bridged with water, GPIO16 will go to a logic-low state.
When the ESP8266 is powered up, which happens every 10 minutes, it will sense this, and send a message to the central controller. It will make several attempts at getting the message through, but if for some reason the controller isn’t acknowledging receipt of this message, it will actuate the piezo buzzer (controlled by GPIO12) until the battery dies. To add a bit of versatility to the board, I added a footprint for a Sparkfun Qwiic connector. This is a standard connector/pinout for many I2C sensors sold by Sparkfun, Adafruit and others.
As I discussed in Part 1, the ESP8266 and associated circuitry were powered via a power manager made up of a MCP79401 RTC, which drives the enable pin of a Microchip MIC5323-3.3Y LDO regulator. The MIC5323-3.3Y has an extremely low quiescent current of 1µA when not enabled, and the 2.2MΩ resistor that pulls the enable line high draws less than 2µA while the RTC is keeping the LDO in a disabled mode.
SELECTING AN RTC CHIP
My choice of the MCP79401 RTC chip was not arbitrary. Many RTC chips are available, and I’ve used both Dallas and NXP (formerly Philips) RTCs in the past. However, the MCP79401 has a combination of features that are not present in those other devices, and which are necessary for this circuit.
- The MCP79401 will operate at a VCC up to 5.5V. In my circuit this is necessary, since I am powering it directly from a LiPo cell, which has a value of about 4.1V when fully-charged.
- The MCP79401 has a versatile alarm function. The most important feature is that it can be programmed for either an active-high or active-low alarm output. This circuit needs an active-high alarm. (Most RTCs have only an open-collector output, which drops the alarm pin low when the alarm has been triggered.)
- It contains 64 bytes of SRAM. This non-volatile storage is used by the firmware to keep track of the number of reboot cycles that have occurred (this is explained later).
The LiPo cell’s power directly feeds both the MCP79401 and R3, a 2.2MΩ resistor to the MIC5323 regulator’s enable line. Until the MCP79401 has had its alarm circuit configured, the multi-function pin (MFP pin), which is open-drain, will present as an open circuit to ground. Therefore, the MIC5323’s enable line will be high, making the regulator operational and providing 3.3V for the ESP8266 and for the rest of the circuitry.
The ESP8266 will boot up and do what is required for that particular power-up iteration. Having done that, it will set the current time to some fixed value, and then set the alarm for a fixed time greater than this preset current time. In my firmware, this is 10 minutes. Once the alarm has been enabled, the MFP pin will drop low for 10 minutes, which powers off the ESP8266. Subsequently, the alarm triggers and sets the MFP pin high, starting the cycle all over again. In my firmware, I maintain a variable called rebootCount, which is stored in the MCP79401’s SRAM. At each reboot, rebootCount is incremented, and every 12 iterations I perform the following two functions, in addition to the leak detection that occurs at every boot-up:
- Check the battery voltage using the ESP8266’s ADC (configured to measure the ESP8266’s VCC).
- Wake up the AM2320 temperature/humidity sensor and take its readings. I must allow 2 seconds for the AM2320 to wake up, so if you don’t want to bother with temperature/humidity readings, you can reduce the total ESP8266 powered-up time by 2 seconds.
Figure 2 shows the leak detector PCB and battery before mounting in the enclosure. The two wires protruding from the left-side of the PCB are the water-sensing leads. The piezo buzzer is controlled by GPIO12 and contains a 2N3904 NPN transistor as a driver. The piezo buzzer I chose contains its own driver, so it can be supplied by a DC voltage, rather than an audio frequency square wave signal.
To program the ESP8266, you need a USB-Serial bridge cable that works at 3.3V logic levels. A note about programming the ESP8266. When the firmware is loaded for the first time, it’s done in the normal way that you would expect for an ESP8266. That is, you power it up, then hold the PROG button down while you tap the RESET button. You will then see a line of “garbage” characters on your PC’s screen if you are running a terminal emulator program. Then you can start the programming routine.
However, once this firmware is running, its normal operation is to perform a quick check for leaks, and then set the MCP79401 alarm, which removes power to the ESP8266. The only way to re-program the ESP8266 at this point, if necessary, is as follows:
- Hold down the PROG button and the RESET button.
- Connect the LiPo battery or other power source.
- Release the RESET button.
- Now it should be in the normal programming mode, as indicated by a line of “garbage” characters on the terminal emulator program.
CENTRAL CONTROLLER HUB
The central controller hub regulates the timing of various events handled by the remote units, and the monitoring of the various parameters/alarms processed by the remotes. Figure 3 shows the unit in operation. A touchscreen TFT display, a rotary encoder, and a few switches configure the timing events and display the remote parameters/alarms. I could have used the touchscreen for all user data entry, but the 4.3” display is not all that large, and having a rotary encoder and two switches allowed me to save the screen space needed to handle the functions that the encoder/switches look after.
In this project (and many past ones), I use a TFT touchscreen powered by FTDI’s FT800 graphics engine IC. The FT800 handles the TFT screen using a circular buffer, which is filled with various text and graphics commands. These commands range from simple text/graphics primitives to some high-level commands that produce various graphics “widgets.” These commands are transferred between the ESP32 MCU and the display using a high-speed SPI link, so graphics operations are very quick. The FT800 graphic engine eliminates the need for any SRAM screen buffer memory on the host MCU side. The image is rendered line by line by the graphics engine under control of the various commands loaded into the circular buffer. The FT800 also looks after all touch processing at a fairly high level, which greatly simplifies things for the programmer.
Although there is a steep learning curve involved in using FT800-based TFT displays, I’m familiar with it now, so it made sense to use such a display for this project. While the central controller module does not require a whole lot of GPIO pins to handle its peripheral devices, more pins are needed than are available on the ESP8266. Therefore, an ESP32 was used instead.
Please refer to Figure 4 for the schematic diagram of the central controller. The specific FT800 TFT display that I used is the MikroElektronika ConnectEVE 4.3” TFT display. This module requires both logic signals and power supply to be 3.3V, which is fine because that is the voltage at which the ESP32 operates. This display module draws about 125mA and could possibly be powered from the output of the 3.3V LDO regulator onboard the ESP32-DEVKIT-C module. However, when it is transmitting, the ESP32, itself, consumes about 350-450mA from this LDO, and I was hesitant to push any limits. Therefore, I used U1, a separate Texas Instruments (TI) LM1086CT-3.3V LDO regulator, to power the display and other devices external to the ESP32 module.
Since the ESP-NOW protocol is being used between the central controller and the remotes, a “normal” Wi-Fi connection is not available. These two RF modes cannot be used simultaneously. Therefore, I could not implement a real-time clock synchronized to an Internet-based NTP service provider. That is OK, because I was trying to make the whole system completely independent of a Wi-Fi connection to my home router/WAP. For the RTC, I instead used an PCF8563P from NXP Semiconductors, which interfaces to the ESP32 via an I2C link. I used a common CR2032 coin cell to provide battery backup for the PCF8563P.
To control the air exchanger, I needed to measure the inside temperature and humidity. I used an AM2320 sensor for that purpose; it is also an I2C device. Two switches and a rotary encoder are connected to four of the ESP32’s GPIO lines. To indicate that a water leak has been detected, I use SP1, a piezo buzzer driven by a 2N3904 transistor. In Figure 5, at the top right side of the panel you can see the ribbon cable to the AM2320 sensor, which has its sensing “window” lined up with a rectangular hole in the front panel, to allow it to sense the correct room temperature and humidity.
Both the ESP32 DEVKIT-C and the LM1086CT-3.2 are driven by a regulated 5V supply. While I often use wall adapters for this purpose, in this case there was enough space on the circuit board to mount a RECOM RAC03-05SK AC-DC power module. This provides 600mA, which is plenty, even when the ESP32 is transmitting and drawing ≥350mA.
I use Hammond’s 1455 series extruded aluminum cabinets for most of my projects, and this one is no different. I have the proper jigs made up to mount these cabinets to my homemade CNC mill. Hammond uses high-grade aluminum for these cabinets, so they mill out beautifully on my CNC mill.
Because the ESP32 is communicating via ESP-NOW to numerous remotes, there must be a way for the RF to get out of the metal cabinet. I used a Hammond extruded cabinet with plastic end plates, and oriented the ESP32-DEVKITC module on the board such that its PCB trace antenna is next to the plastic end panel.
While the Espressif WROOM-32 module (contained on the DEVKIT-C) comes with options for either a PCB trace antenna or a U.FL socket, I had not been able to find any DEVKIT-C modules that contain anything other than a WROOM-32 module with a PCB trace antenna. Recently, I’ve come across the ESP32-DEVKITC-32UE at Digi-Key. It contains a U.FL socket and it would have allowed me to use an external antenna mounted outside the metal cabinet. This would be a better choice.
CONTROLLER FIRMWARE DETAILS
There are a few details of the controller firmware that I’d like to emphasize. As mentioned before, the ESP-NOW protocol is used for all communication between the central controller and the various remotes. Using ESP-NOW means that the ESP32’s normal Wi-Fi capabilities are not available. If a water leak is detected, the controller’s piezo alarm beeper sounds loudly, which is hard to ignore if you are at home. The leak detectors have their own piezo beepers, too. However, I also wanted the controller to send me an SMS text message if a leak was detected. This would require an Internet connection or a cellular modem.
In an earlier two-part article of mine (“Easing into the IoT Cloud,” Circuit Cellar 340 and 342, November 2018  and January 2019 ), I did a project with the Particle Electron module containing a cellular modem, but I didn’t want to pay for a monthly cell data plan in this case. Very recently Particle announced that their small-volume cellular subscriptions are now free, but it was too late to influence this design. So, I had to figure out a way to get the central controller’s ESP32 to handle both the ESP-NOW protocol and standard Wi-Fi functionality. Possibly, in the future, Espressif will modify its library routines to allow simultaneous use of both ESP-NOW and standard Wi-Fi functionality. However, right now, the only way that I have found to accomplish this is as follows:
- In the setup() routine section of your program, provide for two different program execution paths—one for the normal operation of the unit (using the ESP-NOW protocol), and another to handle the alarm SMS notification by configuring the ESP32 for Wi-Fi functionality.
- The choice of which path to execute depends on the value of a variable, which I call bootFlag. This variable gets loaded from the ESP32’s non-volatile memory section using the “preferences” class.
- When an alarm situation exists, the alarm routine must set the bootFlag variable to 0xAA (using the preference class putInt function), and then perform an ESP32 reset using the ESP.restart() function.
- When the ESP32 reboots after this alarm condition, it will find the bootFlag variable =0xAA, and will jump to the internetMode() routine, which turns on the Wi-Fi capability, sends out the SMS message and returns the bootFlag variable to 1. It will then enter a loop for 30 minutes, where it sounds the piezo beeper. (This can be aborted using the Alarm Cancel button.) After that, it reboots. This reboot (with bootFlag = 1) results in the central controller going back to its normal operating mode.
Originally, I tried to locate the bootFlag variable in the ESP32’s low-power RAM that is associated with its built-in RTC. There is a compiler directive that prevents the ESP32 from initializing this memory at boot up, so the value of any variable here should survive a boot up. However, this memory does not survive when the power is removed, so it wasn’t feasible to use this method.
GOOGLE MAIL SERVICE
In the past, I had used the IFTTT cloud service, with a few of my own custom applets, to send the email/SMS messages whenever the leak detectors sensed a leak. (IFTTT stands for “If This Then That”). The email/SMS message was triggered when the leak detector sent a specific message to a URL that was assigned to me by IFTTT (this is called a “web-hook”). Although this worked fine for a while, IFTTT dropped its free SMS message service about a year ago. I believe it has since reinstated it, but its user interface has changed so much that I can no longer figure out how to do what I had previously accomplished quite easily. Also, it has made the IFTTT cloud service into a paid subscription model. I decided to abandon this method and use the Google mail service instead.
Most cell phone carriers provide what is known as an SMS “gateway,” which allows you to send an email to a specific email address. That message will then be forwarded to your cell phone as an SMS message. That specific address generally consists of your full cell phone number followed by @txt and the domain name of your carrier. The easiest way to find out the exact format is to search for “SMS gateway” plus your carrier name, and look around at the various results to find the proper address format. With this function available, all my controller must do is send an email to this address. I decided to use the Google mail server for this purpose. I found an Arduino library for this, which works well with the ESP32 (and I believe also the ESP8266).
To connect to Google and send an email message, you must supply the sender’s email address and password. In addition, by default, Google implements an authentication process to make sure that the person sending the email is actually the person with that email address/password. This authentication process is too complex to be handled by the Arduino Google mail library. Therefore, it makes sense to set up a separate Google mail account for this purpose and then turn off this (default) authentication process while you are setting up the account. Google mail accounts are free, so there is no monthly cost to having this additional account. I don’t recommend using your main Google mail account for this purpose. Turning off this authentication, will reduce the security of your main email account and that is too important to fool around with.
If you don’t turn off this authentication while setting up the new account, you can do it later. Just bring up the Gmail webpage and login to this new account. Then access your account profile and you’ll see a list of actions on the left. Choose “Security,” and scroll down until you see the section that looks like Figure 6. Turn on the “less secure app access” and you’re done.
In the InternetMode() routine contained in the controller firmware, I had to specify three personal parameters:
- The email address of the SMS gateway for my personal cell phone
- The username for the new Gmail account that I set up for the controller
- The password for this new Gmail account
All three are specified in this routine and are easy to find. (My personal Gmail account details, and SSID/password of my WAP are crossed out in the program listing on the Circuit Cellar’s article code and files webpage). Readers would have to fill in these details for their own accounts.
The only other detail of this SMS notification process has to do with turning it on and off. During testing, I didn’t necessarily want this feature turned on. I have a “cheapskate” prepaid cell phone plan, and each SMS message costs me 25 cents. Also, if a leak were detected, the whole detection/reboot/SMS message sending could get into a loop where it repeatedly sends SMS messages. Therefore, in my program, I only allow the SMS message to be sent out once per leak detection. The SMS message function is enabled or re-enabled by pressing the “Cancel Alarm/Enable SMS” push button.
DETAILS OF OTHER MODULES
Besides the central controller and leak detector modules already described, there are three other modules:
- The Air Exchanger Controller Module (Figure 7). This unit is mounted on the air exchanger, itself, and consists of an ESP8266 configured to use the ESP-NOW protocol. When a “fan motor on” (or “off”) command is received, I set the level of GPIO5 accordingly. This pin drives a relay (via a 2N3904 NPN transistor) whose contacts are connected to the air exchanger’s on/off control input (which uses 24VAC control voltage level). Every few seconds, the program sends out a short “heartbeat” sound to the piezo buzzer, to indicate that the ESP8266 is working properly. The frequency of this heartbeat changes with each beep, to make it more noticeable. Unlike the piezo beeper in the leak detector modules, this one doesn’t contain an internal signal driver, so the program uses the “tone” command to send it a PWM signal at various frequencies.
- The Irrigation Pump Controller Module (Figure 8). This works virtually the same way as the air exchanger module. The main difference is that it contains a switch on GPIO4 which, when pressed, will manually turn on the water for 1 hour. This unit contains an Omron G2RL-14 heavy-duty relay, which directly switches the 120VAC power feed to the 0.5hp irrigation pump. The pump is located at the lakeshore and draws its water from the lake. Like the air exchanger controller, this module also contains a piezo beeper that sounds a short beep periodically as a “heartbeat,” and a different beep pattern when the pump is powered on.
- The Irrigation Remote Control (Figure 9). This is a hand-held, battery-operated unit, also containing an ESP8266 configured to use the ESP-NOW protocol. It senses the status of the Pump-On and Pump-Off push buttons, and sends the applicable pump-on or pump-off message to the central controller. We use this remote when we are manually watering flower beds, and want the water on only when we are actually watering. Since the ESP-NOW protocol provides an acknowledgment signal (when the central controller has received the command), I use the presence of that acknowledgment to sound a piezo beeper for 1s. This is activated by GPIO14, and allows us to know if we are within RF range of the central controller. You’ll know soon enough, though, if your command has not worked by the absence of water flow. Figure 10 shows a photo of the remote control.
I’ve done a lot of projects with both the Espressif ESP8266 and ESP32, and am very satisfied with how they operate. Specifically, I have found that these modules have a very good RF range. That is, when I use them in the normal Wi-Fi mode, they will connect successfully to my WAP at greater distances than I have been able to achieve with Wi-Fi modules from Atmel, Particle, Cypress and others. I have found that in the ESP-NOW mode, my pump controller remote unit will communicate up to 150′ away from the central controller.
Although the ESP-NOW protocol is said to be connectionless, whenever a NOW packet is sent, it is automatically acknowledged by the target device. I like this, because it is particularly useful in the leak detectors. You can set a retry count and send NOW packets out until an acknowledgment is received from the target, simply by looking at the status variable returned by the esp_now_on_send callback routine. If you exhaust the retries, you can turn on the piezo beeper.
I also like that both the ESP8266 and ESP32 are available in packages that are not difficult to solder to a PCB by hand. Even when I am not inclined to design a PCB, there are numerous breakout boards available for both devices, from Adafruit, Sparkfun and countless Asian sources.
I have built a few projects that utilize Bluetooth Low Energy (BLE). In general, I find that writing the firmware for the MCU and writing (or obtaining) a cellular phone app to communicate with the device are difficult and/or time-consuming. If your application requires BLE, and you can settle for the basic BLE UART profile, in my experience, the ESP32 Arduino library contains simple BLE examples that are easy to adapt to such applications.
The only thing missing from the ESP32 is the presence of a native Host USB port (that is, not simply a USB-Serial bridge chip added to the breakout board). The new ESP32S2 MCU contains this function, and I am sure I’ll start using it once someone writes a driver that works under the Arduino IDE.}
 “Using ESP-NOW Protocol Part 1” Circuit Cellar 368, March 2021
 “Easing into the IoT Cloud – Part 1“ in Circuit Cellar 340, November 2018)
 “Easing into the IoT Cloud – Part 2“ in Circuit Cellar 342, January 2019)
Esp8266 and ESP32 Documentation:
ESP-NOW API Documentation:
ESP8266 Arduino Core Library:
ESP32 Arduino Core Library:
Online IOT Battery Life Calculator:
Microchip MCP79401 Real Time Clock Chip:
Microchip (Micrel) MIC5323 LDO with Enable Line:
MikroElektronika ConnectEVE TFT display:
AM2320 Humidity/Temperature Sensor:
ESP8266 ESP-NOW Power Consumption- YouTube Video:
Adafruit | www.adafruit.com
Aosong Electronics | www.aosong.com
Espressif Systems | www.espressif.com
FTDI Chip | www.ftdichip.com
Hammond Manufacturing | www.hammondmfg.com
Microchip Technology | www.microchip.com
MikroElektronika | www.mikroe.com
NXP Semiconductors | www.nxp.com
Omron Electronic Components | www.components.omron.com
RECOM | www.recom-power.com
Texas Instruments | www.ti.com
PUBLISHED IN CIRCUIT CELLAR MAGAZINE • MAY 2021 #370 – Get a PDF of the issue