I picked up a really nice and low priced E-Paper display, called the TTGO E-Paper Series. Mine is the T5 V2.3, which uses a 2.19″ E-Paper display, has an SD card slot, a bit of flash memory, one I/O button and some clever power management ICs. It uses the ESP-32 WiFi System on a Chip (SoC). It cost me about £20 delivered.
They have been around for a while and I think were developed to be update-able point of sale for shops. The E-Paper display needs no power once it has been set to show something, so can be a very low power display solution.
The main links that were useful to me were these:
- The open-source github repository for the code by lewisxhe.
- A post by Roger Clark for getting started
- A “getting started” post from Tedizen
It’s worth reading through these to give you a bit of info and overview about the devices. I got stuck in, but had a few issues with getting started. Following the final link in that list was the best one for me. The end result was that I could get the unit to show a bit of data, but mainly errors, as I did not have an SD card present.
My challenge I set for myself was to build a battery powered unit that will wake up every hour or so, connect to WiFi, read a MQTT message and then update the display depending on the MQTT message. I wanted to display the local radiation level from my environment monitoring system in my workshop.
In order to follow these examples, you will need to have the following libraries installed:
- ESP_WiFimanager by Khoi Hoang (via library manager)
- The GxEPD library from the open-source github repository for the code by lewisxhe. (This has the correct SRC for the E Paper)
- Adafruit MQTT library (via Library Manager)
To start with I just wanted to just display some text, which is actually pretty easy. You need to follow the above tutorials to get the ESP 32 programming installed for the Arduino IDE. You also need to include all the libraries listed. I stripped back the code from the example given there to just show how to write text to the screen. I used the “DOIT ESP32 DEVKIT V1” as the board for the upload. This has worked well for me so far, although the TTGO has some options in the board list.
Connect to WiFi
The next step was to add a form of wifimanager to this code, so we can connect to WiFi and the read data from the MQTT broker. There are a few available via library manager in the Arduino IDE. Some examples I had seen used ESP_WiFiManager by Khoi Hoang (version 1.0.8 in my case). This seemed to work very well and also handles using either the ESP8266 or the ESP32 with just one library.
I wrote some basic code to set up as an Access Point (if the unit does not have stored WiFi info) or to connect to WiFi if it does have stored credentials. This code then subscribes to an Adafruit IO MQTT channel (with my local radiation sensor data on it). It then displays the most recent value on the screen.
I could not get wificlientsecure working (which I could get working on the ESP8266) so I have just used the insecure client and port. I will work on sorting this soon!
Sleep modes & low power
My next idea was to reduce the power consumption so that I can have a battery powered display which wakes up every hour or so, check the MQTT subscription and display a new value, if it has changed. I can then put the display anywhere for long term monitoring!
The first thing to review are the different sleep mods available to the ESP32. They will have different interfaces and peripherals available with different levels of power saving. These are covered in the documentation by Espressif (who produce the ESP32 processor) here. There seem to be two different types of sleep: ‘light sleep’ and ‘deep sleep’. Light sleep reduces clock frequency and lowers voltage, but all internal states are preserved. Deep sleep powers off a lot of the peripherals and including the CPU. Both light and deep sleep modes switch off the WiFi circuitry.
Some other good articles on sleep modes for the ESP32 are here:
- Last Minute Engineers – Great review of ESP32 sleep modes.
- Randon Nerd Tutorials – Sleep modes, ESP32 and Arduino IDE
There are five main power modes (covered in detail in the links above):
- Active Mode (160 – 260 mA): WiFi, Bluetooth and Radio all active
- Modem Sleep Mode (3-20mA): WiFi, Bluetooth and Radio OFF
- Light Sleep Mode (0.8mA): WiFi, Bluetooth and Radio OFF and slower clock
- Deep Sleep Mode (10µA – 0.15mA): As above plus ESP32 main core is OFF
- Hibernation Mode (2.5µA): Everything off except real time clock.
Active mode consumes too much current for battery powered units. I think for my application I’m looking at either using deep sleep or light sleep modes. The second link above explains more about putting the ESP32 into deep sleep mode and using a GPIO attached to the RTC to wake the unit up.
The TTGO v2.3 E Paper unit I have has one button on GPIO39 (which is also the RTC_GPIO3).
For programming the ESP32 via the Arduino IDE, have a look at the Examples -> ESP32 -> DeepSleep. I tried the Timer Wake-up example. This shows how a full reset can be performed by waking up every set number of seconds. The most important thing about this code is that everything happens in the ‘setup’ function – we never reach the ‘loop’ section.
One of the main issues with my code is that I want it to start in access point mode if there is no stored WiFi SSID and password information. If the unit does not have this then it will just stay awake until the data has been added to the unit. This might not be a great way of doing this as it could consume a lot of battery if switched on and no WiFi SSID added. But for now it works OK!
I wanted the unit to wake up, connect to WiFi with save credentials, then subscribe to the MQTT feed from Adafruit.IO and find the most recent value from the feed and display it.
The main issue with this is that, when you subscribe to Adafruit.IO MQTT you will only get the data value when it is published/updated. So you do not automatically get the last value. This is called (in MQTT parlance) “retained” message. Adafruit.IO does not support retained messaging – you only get the data when it is published. A blog post from Adafruit gave me some more information about this. This makes things a bit more complex, but gives us a way of getting the most recent item of information on that feed.
What I found was that in order to get the most recent value on the MQTT feed via subscribe, you need to publish to the same feed but with “/get” added to the feed name. For example:
Adafruit_MQTT_Publish getRadiation = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME “/feeds/airradiation/get”);
You can then publish (anything!) to the /get feed and it will return the most recent value to anything subscribed to that feed.
The code for this is available within the GITHUB repository. This code also includes the deep sleep code to save energy.
I have tested the power consumption of this circuit, which should wake up every so often and display the new value. It then goes to deep sleep and has very low consumption until it wakes up again. As I switch off WiFi, then this needs to be reconfigured each time which slows things down a bit, but is good for the energy savings…
Here is the unit with 18650 lithium ion battery pack and a simple laser cut enclosure. (Photo coming soon!)
All in all this is an amazing bit of kit, especially for the price. The ESP32 is an amazing capable processor and the programming chain is really very good and quite easy. I came across some barriers, mainly related to library compatibility and the different versions of wifimanager for the ESP32, but within a day I had a unit running, which is pretty good for me!
I still have a few things to figure out: adding a secure WiFi client using the certificate, trying out bluetooth, trying out the co-processor…. and more!