Skip to Content

Control Halloween Lights using ESP32 on Battery

Control Halloween Lights using ESP32 on Battery

In this tutorial you will learn how to run an ESP32 lite on batteries with deep-sleep mode to control Halloween lights. And to make it really cool, we will use this to give a Halloween skull a pair of glowing red, scary eyes 😉

As part of this project you will learn about the Lolin32 lite development board, deep-sleep to preserve battery power, and how to create some simple lighting effects with LEDs.

Let’s have some fun.

Required Parts

Makerguides.com is a participant in the Amazon Services LLC Associates Program, an affiliate advertising program designed to provide a means for sites to earn advertising fees by advertising and linking to products on Amazon.com. As an Amazon Associate we earn from qualifying purchases.

Below you will find the components required to build the project. For this project I am using an older ESP32 board, which has been deprecated but you can still get it for a very low price. That’s the one listed below. There is a successor model with improved specs, which you can find here. I haven’t tried this one myself but it should work just the same.

Also the skull I used is different from the one I listed below. I think the one below actually looks better but it is a bit smaller. However, I tried and the board and the battery fit in very nicely.

Finally, all the 903052 LiPo batteries I could find have the wrong connector. So the ones suggested below! You will need to cut off the connector and replace it by an 2.0mm JST PH 2-pin connector. But I like the form factor of these batteries since they have almost the same dimensions as the ESP32 board.

ESP32 lite Lolin32

ESP32 lite

Dupont wire set

Dupont Wire Set

Half_breadboard56a

Breadboard

USB data cable

USB Data Cable

Resistor & LED kit

1200mAh Battery

Connecting the Parts

We want to build a Halloween skull with a pair of red glowing eyes. For the eyes we use two red LEDs. Furthermore, we want those eyes to blink or show some other effect. Which means we will need a microcontroller.

The picture below shows you how to connect those parts.

Breadboard wiring of the ESP32 and the LEDs

As you can see, it is very simple. We connect the GND pin of the ESP32 board with a blue wire to the Cathodes of the two LEDS (those are the shorter pins.) The Anodes (the longer pins) of the LEDs are connected to pin 16 and 17 via a 68Ω resistor (purple and green wire).

It doesn’t matter much, which LED you connect to witch pin on the board. Just make sure that you know, which LED will be the right eye and which the left eye.

For the time, we use the USB port for programming and power supply. So no battery needs to be connected.

Writing the Software

In this section, I will show you how to implement the control software for the LEDs. We are aiming for the following effect:

  • a 5 second phase where the eyes/LEDs slowly grow darker with some random flicker at the end
  • followed by another 5 second phase, where the LEDs are completely switched off.

We want to give the impression that the skull suddenly wakes up, stares at you with red, glowing eyes and then slowly dozes off until it sleeps for a while.

If you are completely new to the Arduino world, maybe have a look at our tutorial How To Blink An LED Using Arduino first. Otherwise, just have a quick glance at the code below. I will explain the details in the following sections.

const int ledPin1 = 16;
const int ledPin2 = 17;

const int ts_ms = 10;               
const int dozingoff_ms = 5000;      
const uint64_t sleeping_ms = 5000;  

void set_brightness(int brightness) {
  analogWrite(ledPin1, brightness);
  analogWrite(ledPin2, brightness);
}

int effect(int t) {
  long flutter = random(0, 30);
  int brightness = 255 * (dozingoff_ms - t) / dozingoff_ms;
  return brightness < 150 ? brightness + flutter : brightness;
}

void dozingoff() {
  for (int t = 0; t < dozingoff_ms / ts_ms; t++) {
    delay(ts_ms);
    int brightness = effect(t * ts_ms);
    set_brightness(brightness);
  }
}

void sleeping() {
  esp_sleep_enable_timer_wakeup(sleeping_ms * 1000);
  esp_deep_sleep_start();
}

void setup() {
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
}

void loop() {
  dozingoff();
  sleeping();
}

Constants

We start by defining some constants. ledPin1 and ledPin2 are obviously the pins where the LEDs are connected.

const int ledPin1 = 16;
const int ledPin2 = 17;

const int ts_ms = 10;               
const int dozingoff_ms = 5000;      
const uint64_t sleeping_ms = 5000;  

After that, we have some timing constants. We use those to regulate how long the dozing-off and the sleeping phases are. Those times are in milliseconds (ms), so 5000ms is 5 seconds.

You can change these constants pretty much anyway you like to make the two phases shorter or longer. Make dozingoff_ms larger if you want a slower dozing off. And make sleeping_ms larger if you want a longer sleeping phase.

We will talk about the time step ts_ms later.

Helper functions

Next we implement some useful helper functions to keep the code nicely structured and readable. We use the set_brightness() function to sets the brightness of the two LEDs. Where analogWrite() is doing the actual work.

void set_brightness(int brightness) {
  analogWrite(ledPin1, brightness);
  analogWrite(ledPin2, brightness);
}

Note that we will need a pin that supports Pulse Wide Modulation (PWM) for analogWrite() to work. For the ESP32 board we are using here that is not a problem. Pins 16 and 17 are PWM pins and so are almost all pins on that board. Have a look at the pinout diagram under Pinout of the ESP32 board.

The parameter brightness will be a value between 0 and 255, where 255 means maximal brightness.

To create the dozing-off effect, we implement a function named effect(). Surprise, surprise. It takes a time step t as parameter and over time decreases the LED brightness from 255 to 0. To make it more interesting, we add a random flickering about halfway in the dozing off. This will give the impression of the skull fighting against the sleep with fluttering eye lids. I know, skulls have no eye lids, nevertheless …

int effect(int t) {
  long flutter = random(0, 30);
  int brightness = 255 * (dozingoff_ms - t) / dozingoff_ms;
  return brightness < 150 ? brightness + flutter : brightness;
}

I hope the following diagram will make it clear how this works in detail.

Diagram of the dozing-off and sleeping phases that regulate the LED brightness

Dozing-off function

We are going to use the effect() function in the dozingoff() function shown below. This function simply iterates over the time steps of length ts_ms, calculates the brightness via the effect() function and then sets the brightness of the LED accordingly.

void dozingoff() {
  for (int t = 0; t < dozingoff_ms / ts_ms; t++) {
    delay(ts_ms);
    int brightness = effect(t * ts_ms);
    set_brightness(brightness);
  }
}

You can change the length of the time steps which will result in a smoother or coarser effect. I picked 10ms, which works nicely. You can save battery power by making it longer but the animation will not be as smooth.

Sleeping function

To make the head sleep, we could simply set the brightness of the LEDs to zero and then wait for the duration of the sleeping phase. The code below does exactly that.

void sleeping() {
  set_brightness(0);
  delay(sleeping_ms);
}

However, we would waste valuable battery power, since the microprocessor is still running without actually doing anything during the sleeping phase. Instead, we put the microprocessor in actual deep-sleep mode, where it consumes much less power. The code below shows you how that is done.

void sleeping() {
  esp_sleep_enable_timer_wakeup(sleeping_ms * 1000);
  esp_deep_sleep_start();
}

First, we specify how we want to wake up. There are different ways to do that but here we set a timer via esp_sleep_enable_timer_wakeup(). It takes the sleeping time in micro-seconds. That’s why we need to multiply sleeping_ms by 1000.

And in the second line we simply start the deep sleep mode by calling esp_deep_sleep_start(). Note that this means the setup and the loop function will run, then the board falls asleep, wakes up and the repeats the cycle, starting by calling the setup function.

Setup function

Our setup is very simple. We just switch the pins that control the LEDs into output mode. Done.

void setup() {
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
}

Loop function

And thanks to our helper functions, the loop function is also beautifully simple. We doze-off, then sleep and that’s it.

void loop() {
  dozingoff();
  sleeping();
}

However, note the loop function will run only once, since we enter deep-sleep mode when sleeping and then restarting the board when waking up.

Power savings

We want to run our scary skull on batteries. And the obvious question to ask is, for how long will it run and how much does the deep-sleep mode help.

I am using a 1200mAh LiPO battery. And I measured the current during the dozing-off phase (LEDs on) as 50mA. In deep-sleep the board consumes only 0.054mA and if I use delay() instead, the consumption goes up to 39mA. Now, let’s do the math.

First, we convert the battery capacity to Coulomb:

1200mA x 3600s = 4320000mC

For the dozing-off phase, when the board is awake for 5 seconds, we consume

50mA x 5s = 250mC

During the 5 seconds in deep sleep mode, however, we consume only

0.054mA x 5s = 0.27mC

In total, we consume 250mC + 0.27mC = 250.27mC every 10 seconds.

Therefore, we get a continuous running time of about

10s * 4320000mC / 250.27mC ≈ 17263s ≈ 48 hours = 2 days

If we don’t use the deep-sleep mode that time is cut in half. If you want to increase the running time make the sleeping phase longer (or the dozing-off phase shorter). Or use a bigger battery , of course.

Pinout of the ESP32 board

In this section, I want to highlight some specific aspects of the Lolin32 lite board we are using for this project. You will find the pinout below.

This board is especially suited for battery power project, since it has a battery connector and a charging circuit with 500mA maximum charging current. This means you can connect a LiPo battery to the board, run the board on battery power and charge via the USB port. Very nice!

Furthermore, the deep sleep currents are pretty low. The spec says 125mA with WiFi on and 45mA with WiFi off, which is what I roughly measured as well.

Without a battery connected, and the board powered over USB, you will see a continuous flickering of the charging LED. This is normal! If you connect a battery the flickering will stop. If the battery is charging the LED will be solid blue and will switch off when fully charged.

Note that the board operates with a 3.3V logic level. So not all modules that you get for an Arduino will necessarily work with this board, since the Arduino runs on 5V.

Finally a word of warning. The battery connector is a 2.0mm JST PH 2-pin connector. But most batteries with this connector will have a reverse polarity! Look carefully at the markings of the board. In the picture above the plus pin is on the left side. Make sure the red wire from the battery will connect to the plus pin. I had to cut off and reverse the connector on my battery.

Wiring of the Halloween Skull

While the breadboard is great for testing out the circuit, it will not fit into the skull. Once you confirmed everything is working you will need to solder the wires to the board and the LEDs. Here is how my wiring looks like

Wiring of the ESP32 board
Inside of the Halloween skull and its LED eyes

The skull I bought had no removable top. So I had to cut out the bottom and drill two holes for the eyes. I also repainted it and added some weathering. But I am very happy with the end product

Halloween skull with exposed circuitry

Especially after everything is nicely tucked away:

Another Halloween skull with red glowing eyes

Conclusion

In this article, we have explored how to control Halloween lights using an Lolin32 lite on battery power. We started by listing the required parts, including the LoLin32 Lite board, which is a great choice for battery powered project. We then discussed the process of connecting the parts and wiring the LEDs for the Halloween skull.

Next, we wrote the software for the ESP32, which involved programming it to control the lights and enter deep sleep mode to conserve battery power. This allows the lights to be operational for an extended period without the need for constant power supply.

Overall, this project provides a fun and creative way to add a spooky touch to your Halloween decorations. By using the ESP32 and a few simple components, you can easily control your Halloween lights and create a memorable experience for trick-or-treaters.

Of course, we could do a lot more. Adding a PIR motion sensor or radar sensor to switch on the lights only when a person is detected. Or adding a sound module and more lighting effects, or controlling the head via Wi-Fi. There are endless possibilities.

If you have any questions or encounter any issues while working on this project, please refer to the Frequently Asked Questions section below for further guidance.


Frequently Asked Questions

Here are some commonly asked questions about controlling LEDs using ESP32 on battery:

Q: Can I use any ESP32 board for this project?

A: Yes, you can use any ESP32 board for this project. However, in this blog post, we specifically use the LoLin32 Lite board, since it is easy to run on battery.

Q: How long will the battery last?

A: The battery life will depend on various factors, such as the capacity of the battery, the power consumption of the lights, and the sleep duration of the ESP32. It is recommended to use a high-capacity battery and optimize the code to minimize power consumption for longer battery life. See the calculations above.

For more advance ways to save power have a look at this excellent post: ESP32: Tips to increase battery life.

Q: Can I use different lights instead of the Halloween skull?

A: Absolutely! You can use any type of lights you prefer. The wiring and code may vary depending on the lights you choose, but the overall concept remains the same. A nice idea would be to use RGB LEDs to have some color effects.

Q: Is it possible to control multiple sets of lights with one ESP32?

A: Yes, it is possible to control more lights with one ESP32. You can connect multiple lights in parallel or use a multiplexer to control them individually. However, keep in mind that the power consumption will increase accordingly, affecting the battery life.

Q: Can I modify the code to add more features?

A: Definitely! The code provided in this blog post is a basic example to get you started. You can modify and expand it to add more features, such as different lighting patterns, remote control, or integrating with other smart home devices.

Q: Can I power the ESP32 using a USB cable instead of a battery?

A: Yes, you can power the ESP32 using a USB cable instead of a battery. However, the purpose of this project is to make it portable and wireless by using a battery. If you prefer a wired setup, you can connect the ESP32 to a power source via USB.

Links

Some useful links with additional information are listed below.