LED Candle in a Jar


I’ve been wanting to create a small light with realistic fire animation, so hot off the workbench in time for mid-winter: a flickering LED candle.

Its brain is a programmable microcontroller, running a smart RGB LED via a single data pin, housed in the lid of a jar. I used Adafruit’s Atmel-powered Trinket — a tiny, inexpensive board available in 3.3V or 5V flavors.

Here are three prototypes:

1) A self-contained 3.3V candle with a single Flora NeoPixel, powered by a tiny rechargeable 150mAh lipo battery inside the lid, with a pushbutton toggle power switch hot glued to the outside of the lid.


2) A 5V single-pixel candle, with Trinket on the outside for powering via USB, plus an extra 2.1mm socket for external wall or battery power. I used a nail to punch holes in the lid for the wires, and a diagonal cutter for the power socket. The Trinket is held down with hot glue.


3) A 5V 8-pixel candle using Adafruit’s 8 NeoPixel Stick, with all electronics inside the lid and a 2.1mm power socket on top. The Trinket can handle 150mA output, which is right around the stick’s draw when all pixels are set to candle flame yellow (R=255, G=100, B=10) — but the stick jumps over 200mA when fully lit, so it gets its power upstream from the Trinket.


The jars have a white paper disc at the bottom and a tracing paper tube running the jar’s height. I plan on replacing them with some theatrical lighting diffusion so nothing bursts into flame — probably not a risk, but you never know.

The Arduino code runs a basic fade on the green pixel, causing it to dip down and back every 120 milliseconds, roughly 8 times per second. When the green dips, the light gets dimmer and redder, as if it’s losing oxygen.

An RGB mix of 255, 100, 10 (on a scale of 0 – 255) looks like a pretty good candle flame yellow to me. The starting green pixel value is “grnHigh.” You then set how much below grnHigh the green pixel should dip for normal burning, and when it’s flickering more. “grnLow” is grnHigh minus the dip value.

The main function is a basic for-loop, called fire()

void fire(int grnLow) {
  for (int grnPx = grnHigh; grnPx > grnLow; grnPx--) {
    strip.setPixelColor(0, redPx, grnPx, bluePx);
  for (int grnPx = grnLow; grnPx < grnHigh; grnPx++) {
    strip.setPixelColor(0, redPx, grnPx, bluePx);

So green starts at grnHigh, the max green value, and decreases until it reaches grnLow, then goes back up again. fDelay is calculated by doing some math with the number of steps to keep the cycle time constant.

The next set of functions all call fire() with adjusted dip and delay time. Your options in increasing amount of animation are: on(), burn(), flicker(), and flutter().

The main loop just looks something like this, with the variable as the number of seconds you want each animation to run:

void loop() {

The Adafruit NeoPixels officially run on 5V, but according to the power page of the Adafruit NeoPixel Überguide, small numbers of NeoPixels can run off 3.7V. (I’m powering them from the 3.3V pin on the 3.3V Trinket, and it seems to work). The thing to consider is that green and blue pixels draw more power, so they’ll be dimmer and the whole RGB effect will be warmer. So grnHigh, bluePx, burnDepth, and flutterDepth all need to be tuned higher for the 3.3V version. I eyeballed 3.3V next to 5V, and include both values in the sketch’s comments.


For the 8-pixel strip (above), I created a color and flicker-depth gradient that was more exaggerated toward the top, and not at all at the bottom. It’s supposed to look like the flame height is dancing. It looks more convincing, but the portability of the battery-powered 3.3v model’s pretty nice — and the lid fits on any Ball jar (below).


Get the full code here: https://github.com/timpear/NeoCandle