ESP32 – Getting Battery charging level

Some of the ESP32 development boards provide a 3.7 Ion-Li battery charger what is an advantage when we want to get a device with the minimum number of components.

One of these boards is Wemos Lolin 32 (with battery charger) which costs about 7$ in eBay.

Wemos Lolin 32 with battery charger
Wemos Lolin 32

When a battery is plugged in and the board is connected to a power source via the USB connector, the battery starts being charged.

As the ESP32 board counts with several ADC pins, we can use one of them to check the voltage in between the two battery terminals. The only issue with this is that ADC pins expect voltages between 0 and 3.3 volts and our Ion-Li battery voltage range may reach 4.2 volts.

18650 Ion-Li Battery
18650 Ion-Li Battery

The solution to that is connecting a voltage divider to the battery, so we can divide the volts by 2 and the maximum value will be about 2.1 volts.

Voltage Divider
Voltage Divider Schema
Voltage Divider
Voltage Divider

Our voltage divider is built of two 47KΩ resistors. The total impedance between positive and negative terminals will be 94KΩ and that means a current of less than 5μA (microamperes, not milliamperes).

Voltage Divider mounted on Lolin 32
Voltage Divider mounted on Lolin 32

With this, we can measure the voltage applied in GPIO34 (or any other ADC pins of our ESP32) and then, based on a conversion table, calculate the charge level of the battery.

First, we will get the value of ADC pin. This value may vary from 0 to 4096 depending on the voltage applied to it from 0V to 3.3V. So we can establish a constant to calculate the voltage applied to the pin based on its value. This constant, theoretically, will be 3300 / 4096 = 0.8056.

As we are applying a voltage divider and the voltage applied to the pin is half the voltage of the battery, our constant should be 0.8056 x 2 = 1.6113.

This means, for each unit in ADC pin we have 1.6113 mVolts applied to it.

For instance, if we read the value of the ADC pin and get 2,543, then the voltage applied to the pin should be 2,453 x 1.6113 = 3,952V = 3.95V

ADC pins are not that precise, so the value of our constant should be adjusted to a level we consider it is valid for our components. In my case, after doing some testings I have concluded that the best value for the conversion factor is 1.7.

As I mentioned before, calculating the charge level is a direct translation from the voltage we obtained to a charge level by using a table.

All the code to make these calculations is contained in a library I have created for that purpose. You can find it in Github at Pangodream_18650CL

All you have to do is downloading the .zip file and add it to Arduino IDE.

There is an example of using the library:


#include <Pangodream_18650_CL.h>

//#define ADC_PIN 34
//#define CONV_FACTOR 1.7
//#define READS 20

Pangodream_18650_CL BL;
 * If you need to change default values you can use it as
 * Pangodream_18650_CL BL(ADC_PIN, CONV_FACTOR, READS);

void setup() {

void loop() {
  Serial.print("Value from pin: ");
  Serial.print("Average value from pin: ");
  Serial.print("Volts: ");
  Serial.print("Charge level: ");

And if everything works, it should display something like this on your serial terminal:

Reading battery charge level
Reading battery charge level


ILI9341 + ESP32 (Parallel)

Today I’ve received two ILI9341 TFT screens that I ordered some weeks ago. These screens are in fact a shield designed for Arduino Uno but they work nicely when connected to other developer boards and the price is amazingly cheap: just US$4.

ILI9341 Front
ILI9341 Front
ILI9341 Back
ILI9341 Back

In this case, we will connect the screen to an ESP32 Dev Board.

The pins are configured in a slightly different way than other examples you could find in the web: I’ve tried to minimize mistakes because we will use 13 pins so I thought the best way would be to use as much as possible consecutive pins.

ILI9341 pin to pin ESP32
ILI9341 pin to pin ESP32


ILI9341 to ESP32
ILI9341 to ESP32

You can also connect the ILI9341 using only 4 IO pins (not this model), but the refresh/painting speed is not comparable.

The library we will use is TFT_eSPI library by Bodmer and our only purpose by the moment will be executing an example demo script successfully.

During testing, you can connect TFT 3V3 pin directly to ESP32 3V3 pin, but do it only during a short period of time because the current drawn by the screen LEDs is 134mA and you will notice how the LEDs and the Development Board voltage limiter will become hot.

A 22Ω resistor (not 220) between the two 3V3 pins it’s enough to reduce the current to 23mA and though the screen is not the brightest one in the world I think it is enough for testing purposes.

Once you have finished the connection of the pins as described in the diagram above, you can install the TFT_eSPI library if you don’t have it already installed.

Open Arduino IDE, go to Library Manager and in the search box type TFT_eSPI. In the results list, look for the next and install it.

TFT_eSPI Bodmer Library for Arduino
TFT_eSPI Bodmer Library for Arduino

Now you have the library installed you have to configure the IO pins where we have connected our screen. Other libraries use the definition of constants at the top of each sketch to do this, but TFT_eSPI uses a common file to define the configuration.

Find in your Arduino installation the file called User_Setup.h

It should be located in a path equivalent to this:

[Arduino Folder]/libraries/TFT_eSPI/User_Setup.h

Now, copy the file for backup purposes and edit the original to place inside it this following content (replacing all the previous content):

// See SetupX_Template.h for all options available

#define ESP32_PARALLEL

#define ILI9341_DRIVER

// ESP32 pins used for the parallel interface TFT
#define TFT_CS   27  // Chip select control pin
#define TFT_DC   14  // Data Command control pin - must use a pin in the range 0-31
#define TFT_RST  26  // Reset pin

#define TFT_WR   12  // Write strobe control pin - must use a pin in the range 0-31
#define TFT_RD   13

#define TFT_D0   16  // Must use pins in the range 0-31 for the data bus
#define TFT_D1   4  // so a single register write sets/clears all bits
#define TFT_D2   23
#define TFT_D3   22
#define TFT_D4   21
#define TFT_D5   19
#define TFT_D6   18
#define TFT_D7   17

#define LOAD_GLCD   // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
#define LOAD_FONT2  // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
#define LOAD_FONT4  // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
#define LOAD_FONT6  // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
#define LOAD_FONT7  // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:.
#define LOAD_FONT8  // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
#define LOAD_GFXFF  // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts


Save the file and go back to Arduino IDE.

Open the example sketch UTFT_demo (it is under File / Examples / TFT_eSPI /  320 x 240 / UTFT_demo)

At this point, you can compile and upload the sketch to your ESP32. If everything went ok you should see some graphics, backgrounds and texts appearing in your TFT screen. Otherwise please review carefully the IO pins configuration (hard and soft).

If it works, probably you’ll see the results like in a mirror. To solve this, go to the sketch and edit the line that sets the screen orientation. This is done in the setup function.

void setup()
// Setup the LCD
  //myGLCD.setRotation(1); //Comment out this one and insert the one below

The result now should look like this

Claudio, parts and some links

Claudio consists of just five (or six) components, the wiring between them and code. No resistors, capacitors, diodes… no discrete components apart from 3 five cents of € coins. 😉

List of components:

  1. ESP32 Development Board: I’ve tested two different boards, and though they are very similar the results were not the same. 
    ESP32 Development Boards Front
    ESP32 Development Boards Front

    ESP32 Development Boards Back
    ESP32 Development Boards Back

    Price: US $7
    The first one was the one on the right side. It is a board I bought a year ago and it was working fine (for small tests) since then. When I first tried to put all the components together I noticed that ILI9341 TFT Display and WiFi connection were not good friends working at the same time. After 3 or 4 display operations (text, area fill, …) the screen went always blank and only when WiFi library was loaded. I tried multiple pin configurations, alternate libraries loading order. I tested voltage on each significant pin (D/C, CLOCK, MOSI) and no result.
    Finally, I decided to give a try one of the last boards I bought: the model on the left side. The result was successful. No blank screen. But, these boards have a bug design: they don’t allow uploading schemas directly from Arduino IDE (Error: Timed out waiting for packet header) and you have to ‘play’ with EN and BOOT buttons every time.
    Workaround: once Arduino IDE tries to upload the schema, press BOOT and without releasing it press also EN button, wait for a half second, release EN and when IDE stops waiting and starts the uploading you can release BOOT button.

    Error Time_out_waiting_for_packet_header
    Error uploading schema from Arduino IDE search for ESP32 Dev Board
  2. ILI9341TFT Screen – SPI
    Again, the component I had at home was about one year old. The only difference is that the one you can find now implements a set of pins to control a touch panel (though they say at the product description “non-touch”). Anyway, I think the one is being sold now is perfectly compatible with the previous model.
    What we need for this design is a model with an SPI pin configuration. Sellers usually refer to these as “driven with at least four IO”
    Price: US $7
    ILI9341 SPI TFT Display
    ILI9341 SPI TFT Display
     Sample link to ILI9341

  3. DHT-11 Temperature and Humidity Sensor
    This is a low-cost sensor very easy to use. Though it has four pins, only three of them have a function (the other one is not connected).
    Simply connect ground pin to GND, VCC pin to 3V3 and Data Out pin to any ESP32 IO pin.
    Depending on the range of temperature/humidity you need to measure, you should take a look also to DHT-22 sensor (which implements a wider range and more accuracy), but in my case, 0-50ºC/20-80%R.H. is quite enough.
    Price: US $1
    DHT-110 Temperature and Relative Humidity sensor link to DHT11 search

  4. BH1750FVI Digital Light Intensity Sensor
    I think the best feature of this sensor is, apart from ease of use, the sensibility and stability.
    It measures ambient light and gives the result in Lux
    It has 5 pins, but once again we can ignore one of them (ADD) by connecting it to GND. So, we only need two ESP32 IO pins to connect  SDA and SCL sensor pins.
    GND and VCC pins go to GND and 3V3 ESP32 pins respectively.
    Price: US $1
    BH1750FVI Ambient Light Sensor
    BH1750FVI Ambient Light Sensor link to BH1750FVI search

  5. Passive Piezo Buzzer
    The most basic part of the system.
    Just two pins (the middle one can be ignored), one goes to GND and the other one to an ESP32 IO pin.
    Price: US $0.2
    Passive Piezo Buzzer
    Passive Piezo Buzzer link to Piezo Buzzer search

  6. Touch sensors (5 cents of € coins)
    Each one connected to an ESP32 Touch pin.
    Price: 0.15€
    5 cents euro coin
    5 cents euro coin
    Mounted coin touch sensors
    Mounted coin touch sensors

ESP32 and ILI9341 ISP mode

After trying several options that I found on the web, I chose this one as the better to connect an ESP32 to an ILI9341 TFT display.

ESP32 ILI9341
D15 CS
D4 D/C
Not connected MISO
3V3 (***or D19) LED

The code:

 * ILI9341 TFT libraries and resources
const int TFT_CS = 15;
const int TFT_DC = 4;
const int TFT_MOSI = 23;
const int TFT_SLK = 18;
const int TFT_RST = 2;
const int TFT_LED = 19;     

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_SLK, TFT_RST);

void setup() {
  tft.setRotation(3); //Landscape orientation

The reason for the two possibilities for the LED pin is the next:

If you connect LED pin directly to 3V3 you will get maximum brightness in your screen. LED pin controls the backlight of your TFT display.

In my case, I didn’t want to have max brightness but I wanted to control the intensity based on ambient light, so I decided to connect LED pin to any of the IO pins of the ESP32 (#19 in the showed example).

The code to control backlight intensity (once you have connected LED to pin D19) is as follows:

const int TFT_LED = 19; 
 * PWM Constants
const int freq = 5000;
const int tftledChannel = 0;
const int resolution = 8;
void setup() {
  //Background light PWM
  ledcSetup(tftledChannel, freq, resolution);
  ledcAttachPin(19, tftledChannel);

 * Sets TFT background luminosity (0-255)
void setBGLuminosity(int level){
  ledcWrite(tftledChannel, level);

Inserting the code above allows you to set the backlight intensity at any point just invoking setBGLuminosity() function passing a value between 0 and 255.


setBGLuminosity(0);   //Switch off screen backlight
setBGLuminosity(128); //Medium intensity (theoretically)
setBGLuminosity(255); //Full intensity

Claudio, available resources

Before going into detail of coding or wiring, I will publish here the links to the existing project resources (videos and code repositories).

Sorry about the video language, but I prefer writing in Spanish in places like youtube where automatic translation is good enough.

Youtube channel:

Github repositories:

Inside Hardware folder, you may find some hardware pictures and a wiring diagram (though this one will have its own post) and inside Box folder are the .obj files to 3d Print the box.


Claudio, a wake-up alarm not so simple

New blog and to tell you the truth, my first blog. No personal introduction, no sensitive content… 🙂

I made some basic tests with an ESP8266 a couple of years ago and I was very pleased with the board capabilities, the freshness of NODEMCU, the quick schema uploading… everything. But I didn’t like one aspect, in the same way, I didn’t like some years before about Arduino boards: connectivity.

The ESP32 arrived, WiFi and BLE connectivity, a bunch of IO pins, a lot of different pin working modes… and for someone with limited knowledge of electronic theory… a marvelous tiny thing.

Lately, I am having much more spare time that I used to have, so I decided to start doing things I always wanted to do but I never had the time to. I don’t like using my cellular for all purpose. I like WakeUp alarm clocks, but not the ones they sell. My last WakeUp alarm was a Sony, very nice, spectacular design but “who the hell designs an alarm clock supposed to be stopped while you are sleeping by pressing a tiny switch in the middle of a lot of more tiny switches? Yes, Sony” And what if I design my own Alarm Clock with that ESP32 Developer board I have? And that’s what I did.

The requirements:

  1. Time visible in the dark, but not like a red UFO. Light intensity has to accommodate to room light.
  2. No need for time adjustment. No need to change the hour every spring or autumn.
  3. Minimal use of buttons, tiny buttons, micro switches… :S
  4. If there’s enough room on the screen… some other indicators like temperature and relative humidity (these are enough important in the dry & hot Madrid nights)
  5. If possible, some communication capabilities: remote configuration, remote alarm stopping, …
  6. Easy to wire components between

The prototype:

I needed a box to fit all the components in. Perfect reason to buy my first 3D printer, and that’s what I did.

This is the screen design today… it’s evolving and probably will not be the same in a couple of days.

Claudio WakeUp Alarm Screen

The box is 11cm x 65mm x 65mm and though is a bit bigger than I expected it to be I think of it as a prototype and time will bring smaller designs.

Claudio Wake Up alarma box
Claudio Box

This has been only the introduction. Check out the rest of the posts to know more about the design, the code and the possibilities of ‘the creature’.