Traffic Light (2.0)

Felix Kohlhas • GitHub: [TrafficLight]
Tags: Microcontrollers IoT Embedded Systems
I recently built a WiFi controlled traffic light and want to share the design, code and the build process.

Collage of three images, showing the wireframe, 3d render and the real life version of the traffic light


I designed this traffic light to replace an improvised device that I had build for my parents office in 2020. At the time the COVID social distancing restrictions were very strict and they had to extend the waiting room onto the stairwell to accomodate their waiting patients. For this they needed a way to call in patients one by one, and so I build a small WiFi-controlled device that would light up green to signal the next patient to come in. This worked great, but during is lifetime over the last 3 years, more and more LEDs on the device were starting to fail and each had to be manually replaced or removed by me. When it became clear that this waiting room system was working very well and that it was here to stay, I decided to build a new and improved version.

A LED panel lit up half blue half red, with two LEDs missing
The old “traffic light”, after another LED of the WS2812 panel failed


The main goals were simple. The device should look more like a real traffic light (so that patients could easily recognize at first sight what the red signal means) and its LEDs should be user-replaceable (so that I would not have to drive over to desolder broken LEDs). Of course, the setup should also be as simple and cheap as possible while remaining visually pleasing and reliable.

I put great emphasis on the ability to replace LEDs after reading a very interesting paragraph on the lifespan of WS2812 LEDs in the Adafruit Neopixel Uberguide. While they have a rated lifespan of 50.000 hours (about 5 years), this is just an average and some LEDs will statistically fail much earlier. When using many LEDs together (such as 64 in the initial version of the device), the chances of at least one LED failing can increase to the point where the lifespan will be much less than 5 years. In many cases, it makes more sense to accept that some LEDs will fail after a year or two and to design the product with replaceability in mind, instead of trying to extend their lifespan through means such as undervolting or active cooling.

With these goals, fancy ideas such as soldering individual cob LEDs to a 3D structure of brass wire and encasing it in clear epoxy resin were off the table (even though I had already envisioned something like that and I am sure it would’ve looked great). Instead, I decided to go with a much simpler setup, using very similar components to the device I had designed before. The LEDs would still be WS2812s, but this time as two ring-shaped modules, and the NodeMCU would be replaced by a bare ESP-01. The main difference would be the design of the case.

Digital sketch of a stylised traffic light and its individual parts
A rough sketch of the device

Parts used:

I chose the WS2812 rings, because they already have connectors attached and can be replaced without any soldering.


For the case, I took inspiration from real traffic lights and tried to include the essential design elements. Even though the device will not be used in direct sunlight, I added a small sun shade and tried to keep all other proportions somewhat realistic. I am quite happy with how the design turned out.

Screenshot of Fusion360 showing the wireframe of the 3d design
The 3D-model of the traffic light


While the case was printing on my 3D printer (15 hours for the largest part), I started testing the components and the indended wiring. For projects involving ESP-01s, I like to first test everything using a NodeMCU or similar dev-board so that debugging is easier and flashing can be done in place. Then, after writing some minimal code to test the LEDs and ensuring that the OTA update function worked, I flashed the firmware onto an ESP-01 and soldered everything together.

Photos of components with lines showing the rough connections
An overview of the wiring

Digital sketch showing the wiring with pins labelled
Specific pins used

Collage of three images, showing the spray-painted case, the wiring on the inside and a test with the lights lighting up blue


After soldering everything together and applying power, the LEDs lit up and I was able to update the device over WiFi successfully. I wrote some more code to allow switching the lights to green for a few seconds by sending a GET request to the device and added smooth transitions to the color changes.

Screenshot of the code in VSCode


Finally, I spray painted and assembled the 3D-printed parts, added the electronics and got to enjoy the result.

Collage of three images, showing the traffic light lighting up blue, red and green
The finished traffic light

All the code and the 3d designs are in the “TrafficLight” GitHub Repository.
While I am very happy with how it turned out, there are some small things I would do differently if I build something similar again. For one, I realized that I could have saved screws and made it easier to replace parts by having inside parts slot into place and be fixed by screwing in the front panel. Something else I would add the next time is a piezo buzzer or some other audio output.

Update: I have added an active piezo buzzer on the last remaining pin (GPIO0) and updated the code on GitHub. In order to avoid the ESP8266 going into serial programming mode, I connected it between 5V and GPIO0. This way GPIO0 is pulled-up at boot and the buzzer can be activated by pulling GPIO0 LOW.


This blog does not currently have a comment function. You can send me an email to [email protected] instead and I will add it here.