04.11.2024 20:03

Stairway to Heaven: Customizing WLED

From the idea and attempts to use the standard firmware to building my own with an increased number of control pins, an expanded web interface, a debugging API, custom lighting control logic, and even a demo on jsfiddle.

Task

We have a partially outdoor staircase (a glazed veranda). We want to create a "stairway to heaven" effect – sequential lighting of the steps from the side where a person is walking. Operating conditions are challenging – winter frost, summer heat, daytime lighting is useless due to natural illumination.

Exists solution

In fact, there is already lighting on the indoor staircase in the house with simple animation, but it was implemented with a controller from China on regular LED strips – each step had to be wired separately.

This time, I wanted more, so my requirements were:

  • multi-color lighting,
  • a bunch of ready-made effects,
  • turn off the lighting when there’s enough natural light,
  • steps should light up from bottom to top and top to bottom, and the animation should run from both ends if movement is detected simultaneously from both sides.

We will calculate and compare the costs of the first and second solutions closer to the end.

Basic WLED firmware

WLED is ready-made firmware for working with addressable LEDs, which, in addition to its main function, also includes an HTTP API, web interface, support for integration with external systems (e.g., MQTT), and even synchronization between different WLED devices.

WLED also have an entire ecosystem with integrations and plugins for all common smart home systems, and they’re quite decent. For example, Home Assistant automatically recognizes WLED devices on the network and can update their firmware over the air.

Let's get closer to our task: WLED seems to support everything we need right out of the box:

  • LED groups for each step,
  • configuration of on/off animations for groups with timing,
  • support for 2 input pins (for Wemos D1 Mini / ESP8266) to connect buttons/switches/motion sensors,
  • triggers for changing pin values to start animations.

from left to right: palettes, animations, segments, presets

This is how it works (I’m connected to the WLED WiFi access point from my laptop and manually start the animation from the web interface):

animation-default-note

Looks great, but in practice, not everything is so smooth:

  • each time the sensor is triggered, the animation restarts,
  • two animations cannot run in parallel,
  • the firmware for ESP8266 only has 2 available input pins; there’s nowhere to connect a light sensor,
  • even with more pins, there’s no way to tie the light sensor in, or write complex conditions, or even a simple if statement to check a couple of values (and set it up in the interface, respectively).

The light sensor issue can be solved by installing a relay on the power supply (in my opinion, it’s a workaround, but it works overall), but even so, the animation doesn’t satisfy me — with any sensor and timing settings, proper operation is only possible in ideal conditions – a single activation of one sensor.

Let's gradually solve these problems.

Expanding the number of inputs (buttons)

By default, WLED firmware for Wemos D1 Mini allows only 2 input ports, although the controller and board have more free pins.

Fortunately, this problem is easily fixable – you only need to set the WLED_MAX_BUTTONS flag with the required number of pins and compile the firmware.

Compiling WLED firmware

Here’s where it gets complicated, especially if you’ve never encountered this build setup. Arduino flashing experience won’t help here. However, everything is described in the official instructions. You’ll just need some software – git, VS Code, PlatformIO extension, Docker, Node.js, WSL for Windows. Also, a few reboots and possibly a non-working build button that, according to some issues, might work randomly and compile the binary not on the first try.

If you don’t want to build the firmware for all supported platforms – you’ll also need to uncomment the line in the config for d1_mini and comment the line above listing all supported platforms.

Then add the key -D WLED_MAX_BUTTONS=10 in build_flags to expand the number of available "buttons."

I eventually managed to compile everything through test, the first stage of which includes build and produces the necessary firmware binary.

The desired 10 available pins obtained, but ultimately not used

Customizing WLED

Since we’ve determined that standard functions won’t cut it – let’s see what WLED offers for customization: here is a guide to implementing custom scripts (usermods), which can expand the GUI, create APIs, and interact with the microcontroller pins in C++.

Initially, I started writing code according to the instructions until I accidentally found a set of ready-made usermods deep within the repository that the official documentation doesn’t mention.

Meanwhile, there’s a lot here:

My usermod and its description can be found in the repository; all necessary explanations are in the README and code. The coding style (or lack thereof) is a consequence of implementing it based on another solution, and I didn’t get around to refactoring after getting a working version.

Even though the flashing process is convenient and fast by microcontroller standards, debugging bugs on physical hardware and circuit proved labor-intensive. I honestly tried to do this, but after a couple of dozen iterations, I asked chatGPT (then version 4) to convert all the current code into a demo on HTML/CSS/JS and debugged the logic there.

You can try the demo here - jsfiddle.

The final logic is as follows:

  • each sensor independently starts turning on steps on its side.
  • on_time_ms after the last sensor trigger, the steps begin to turn off (always in one direction).
  • repeated sensor triggers only affect the turn-off time; the animation does not restart.
  • the pins and delays are set in the interface, and sensor states are available in the API.
  • a light sensor (logic module giving high or low output) is connected to a separate pin, turning off the lights during daylight.

To enable usermod in the firmware, just include it in /wled00/usermods_list.cpp:

#include "../usermods/usermod_stairs.h":

The usermod settings in WLED interface

Connection scheme

A small digression on the connection scheme.

All LED strip sections are connected sequentially, but the power, especially in the 5V strip version, is catastrophically insufficient, and the strip at best will lose brightness from start to end. For this reason, power should also be connected to intermediate points on the strip (in my case, every 2 steps – I ran a power cable along one side of the staircase).

The WLED developers also ensured safety, and the firmware has software calculation of the strip's maximum power consumption at selected modes, with a default limit based on direct connection to the controller pins. When exceeding this value, the controller will proportionally reduce the LEDs’ brightness depending on the effect used.

img

If your strip is properly powered rather than directly from the controller, set this value to the maximum (nominal?) current your power supply can output, or remove the limit.

The general connection scheme can be depicted roughly like this:

Sorry, not to standards

Even though the ESP works at 3.3V and the strip is powered/driven at 5V, direct connection works correctly, partly due to the short distance between the controller and the first section of the strip. If in your case this distance is large and failures occur, or if the strip is powered by a different voltage and cannot be directly connected (12V), add a level shifter to the circuit following the official recommendations.

As you can see, far fewer wires are needed here than with a ready-made controller.

Result

The final result looks like this:

animation-up

I settled on one animation, which only slightly varies the brightness of individual LEDs, making it look dynamic but not distracting during use.

However, you can choose any effect up to using different animations for each step. For example, here’s a more dynamic mode:

animation-example

The usermod can also be disabled, allowing standard lighting control – in case your staircase is at the center of the house, and you want to throw a party with light music.

Required components and budget

Below are links to AliExpress searches for components, without referral links.

Component Cost
Wemos D1 Mini 1.4 $
Addressable LED strip 60LED/m 5V IP65 ~20 $
200W 5V power supply ~1.3 $
2 motion sensors HC-SR 501 ~1.3 $
1 light sensor ~0.8 $
Power and signal wires ~10 $
Cable ties and wire sleeve for aesthetics 5 $
Enclosures for sensors and microcontroller Optional, I printed

Total expenses are roughly 51.5 $.

Ready-made solution

I also promised a comparison of the ready-made solution and the described implementation.

A 2nd version of the controller with light sensor support has since appeared; I have the first version without it.

Component Cost
Controller with sensors 20-40 $
Single-color LED strip ~20 $
Power supply, can be lower wattage but up to 24V (matching the strip) ~10 $
Wires – requires more length but smaller gauge, assuming cost is similar 10 $
Cable ties, sleeve for aesthetics 5 $

Total minimum 65 $ (without light sensor support).

As you can see, slight savings come only from the power supply and sensors. The controller is significantly more expensive than the one we used.

Conclusion

With the wider capabilities of the described solution, the ready-made option still falls short in price and installation convenience.

Yes, the development cost isn’t considered here, but this device is more of a hobby project – I was simply interested in the process, regardless of the final expense.

If you have any questions or comments/suggestions – feel free to leave a comment.

Useful links

Latest articles