Over-engineered LED strip controller

Way too much stuff to light my garage MY way.

Similar projects worth following
I've put up the usual 12V LED strips to give more light in my garage. Like everybody else, I'm going to make a custom controller for those lights. This is part practical, part aesthetics, and part learning exercise.

My garage is 20 ft x 30 ft. (That's about 0.01 US [Imperial] football fields and an indeterminate number of metric [FIFA] football pitches.) The original lighting in there is 3 connected ceiling-mounted sockets. That's enough light to walk through there without risking your life, but it's very poor lighting for actually doing anything in that garage.

It's easy to find many descriptions of people putting up inexpensive 12V LED strips in garages or other places. So, hey, me too! I'm not bothering with describing much of that part of the project because there is nothing special about my take on it. This project is about the controller I am making for it.

Here's a high-level view of the features:

  • Two remote passive infra-red (PIR) motion detectors to keep the lights from timing out while someone is present.
  • Two remote control knobs consisting of rotary encoders with built-in momentary switches. These are both on/off switches and also dimmer controls.
  • The PIRs have LEDs for debugging/feedback.
  • The control knobs have LEDs for easy location in the dark.
  • Sensors for temperature, air pressure, and relative humidity.
  • A built-in touchscreen display.
  • SD card slot for possible data recording.

Creative Commons License
Over-engineered LED strip controller by WJCarpenter is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

  • 1 × SparkFun ESP32 Thing
  • 1 × DC-DC 3A Buck Converter Adjustable Step-Down Power Supply Module LM2596S adjust for 3.3v output
  • 4 × shallow single-gang plastic electrical box for the PIR sensors and the rotary encoder switches
  • 4 × single-gang blank faceplate
  • 1 × double-gang electrical box holds the main board

View all 15 components

  • Wire colors for remote boxes

    WJCarpenter4 days ago 0 comments

    Remote from the main controller board are 2 rotary encoders with switches and 2 PIR motion sensors. Each remote box also has a separate LED for feedback/indications. With shared ground connections and shared 3v3 connections (where possible), that implies 6 wires for the rotary encoder remote boxes and 4 wires for the PIR remote boxes.

    I'm using Cat3 cabling for the runs from the controller board to those remote boxes (including for the PIR remote boxes, where I only need 4 wires*). Cat3 cables is also known as 6P6C (6 pins, 6 conductors) and consists of 3 distinct pairs of wires. I'm using this kind of cable because (a) it's cheap and widely available, and (b) the standardized color coding of the wires is very helpful: blue, blue/white, green, green/white, orange, orange/white. The abbreviations for those colors is on the silkscreen for the PCB and simplifies hooking things up. To facilitate easy removal of the controller board, I used keystone jacks to wire up short lengths of Cat3 to the screw terminals. There will be matching RJ12 plugs on the cable ends nearest the controller board.

    (*OK, a little white lie. When it came time to run the cable, I ran short of Cat3 by several feet. So, one of the PIR remotes uses standard 2-pair telephone wire, which uses a different color scheme: black (orange/white), red (blue), green (blue/white), yellow (orange). Luckily, I arbitrarily [I think] didn't use green or green/white on my PCB markings, so I can be slightly less confused when wiring this up.)

    Here is a diagram of the pins of the components in the remote boxes with labels for the wire color coding. The color names in the [square brackets] are for the 2-pair telephone cable as an alternative to the Cat3 colors.

  • A hatful of mistakes

    WJCarpenter5 days ago 0 comments

    Along the way, I've come across some design errors and other mistakes I've made. Some of them are more like lessons learned than actual mistakes. This is a consolidated list. Some have been or will be mentioned in more detailed project log entries. These would be inconsequential if this were an iterative design. I'd just fix them up and keep going. However, I expect that I will build exactly one of these garage door lighting controllers, so I'm working around them.

    • In the PCB layout, I didn't allow enough space between the holes for the display screen mounts and the nearby screw terminal mounts. I worked around that by flattening the pins for the display screen mounts, and I turned one set of screw terminals around by 180 degrees. (Detailed in build instructions step 4.)
    • Some GPIOs of an ESP32 do not have internal pull-up/pull-down resistors. I used two of those GPIOs where I needed pull-downs. I worked around that by adding the pull-downs across some existing pins. (Described in project log Pull up! Pull up! Pull up!)
    • When testing those pull-down resistors after I soldered them, I was expecting to see about 10k ohms. Instead, it's pretty close to (but not quite) zero. There is no short between those holes in an unpopulated PCB. I'm still working on finding the cause of that problem. [I figured this out. Those resistors were just bad. There were from a batch I had on hand with a "10k" label, but they weren't anything near that. I swapped them for some 15k resistors that I measured before placing them.]
    • OK, I'm an idiot on this one. Even though I called the project log item "Pull up! Pull up! Pull up!", I somehow ended up believing I needed pull-down resistors for the switches on the rotary encoders. I even had that on the breadboard after I figured out the ESP32 GPIO situation. My switches seemed to be always either stuck "on" or "off", depending on my software configuration. When the light dawned on me, I rewired the resistors to pull up, and things worked as expected.
    • I probably should have added I2C to the design in the first place, even if I didn't have a specific use for it, but I wasn't sure if I could use the RX/TX pins for I2C. When I tack-soldered wires for an I2C bus (described in project log Adding i2c), I arbitrarily planned to use GPIO22 for SCL. When the time came, I discovered that my "no connect" pin was somehow tied to ground. It's not grounded on an unpopulated board. Maybe I'll find it's related to the problem with the pull-down resistors (I hope, I hope [edit: nope, nope]). I changed my plan and instead used GPIO3 (right next to it) for SCL instead.
    • It's a good thing that I am using a framework ( that allows for OTA updates. It's easy to pop the display off the mounting headers to get at the Sparkfun ESP32 Thing, but there is not enough room for me to insert a cable into the micro-USB port. It's at least 1/8 inch too cramped. (I found this pretty funny when I first found it.) If I were not using OTA, I guess I would do a more thorough search of my vast collection of micro-USB cables to see if I had one that fit. Or, maybe I would buy some kind of right-angle micro-USB thingy. Or, worst case, wire up some kind of custom USB monstrosity myself.
    • I'm pretty happy with the manufactured PCB and most of my own work. One thing that I would do differently would be to increase the size of some of the text on the silkscreen layers. I would also increase the size of the lands around some of the holes. Both of these looked plenty big when looking at the layout on a screen, but I faked myself out due to my own inexperience in realizing how small they would be on the actual PCB. One might say I didn't have the right perspective (nyuk, nyuk!)
    • I probably would use something other than the screw terminals for connecting the off-board wiring. They're OK, though the "play" in the plastic housings gives a less tidy look than I wanted. And, all that wiring does add a certain bulk overall. Perhaps in future...
    Read more »

  • Gestures

    WJCarpenter07/28/2020 at 02:13 0 comments

    Well, OK, the problem of making the display visible is probably solved, but that brings with it another minor problem. My display has a touch interface, and I was vaguely planning to use that to trigger the display of some internal info or whatever for my own geeky needs. I was not planning to use that for reconfiguration or for actually controlling the lights, but I might be able to display some configuration info or logs or something.

    I'm pretty sure the display I have uses resistive technology, in which case it definitely will not work through a plastic cover. Even if it turned out to be capacitive, the cover would probably have to be pretty thin for it to be usable. Oh, well.

    I happen to have on hand a few APDS-9960 gesture sensor boards. They operate over I2C, and I already planned to have I2C for the BME280 environment sensor. I should probably be able to use one of those gesture sensors through the plastic cover for simple things like displaying extra "pages" of information.

    I'll have to save additional details about that for when I get bogged down in software design.

  • A clear case

    WJCarpenter07/28/2020 at 02:05 0 comments

    Now that the board is assembled, it's time to get serious about the case I am going to put this in for mounting on the wall. I've dithered about this before in earlier project logs. Yesterday, I made a trip to the local big box hardware store to see what I could find off-the-shelf.

    Ever since I decided to add the display to the project, I've been thinking about how to make the display visible. Something I know from many past projects is that precisely cutting out a rectangular shape in anything, including soft plastic, will look a lot better in my mind's eye than it will when I actually try it in practice. In fact, I've been dreading that. 

    So, I've reverted back to the idea of a clear cover. Finding a clear cover for a 2-gang electrical box is not that easy, especially if you want it to be completely blank (ie, no cut-outs for switches or sockets). But it dawned on me that there are outlet covers that are more or less clear. For example, this item from Hubbell TayMac.

    That's a little bulky (and pricey), but maybe it would do. I decided to just think about it. When I got home and looked at more information on the manufacturer's web site, it seemed like it wouldn't have the depth I need except by expanding the cover. If you do that, it becomes a lot less rigid. That's not a problem for its intended use, but it's less ideal for my use.

    I also spent a bunch of time looking at different 2-gang electrical boxes and their friends. Some seemed like they might be suitable if I could just solve the problem of the cover. But another thing I've learned through hard experience is that I always need a lot more room than my mental picture of how the wiring will go. I started to worry about how cramped it would be. This PVC box from Legand Wiremold is 2-gang, but it has more elbow room than a typical in-wall electrical box. It's shallower, but it's deep enough for my use.

    When I got home from my mega-hardware-shopping trip, I decided to have another go at finding a clear blank cover plate. With some luck in the Google-fu, I found some ABS plastic boxes with clear covers. The brand is Lemotech. I found lots of places selling them online, but I didn't find a web site for the manufacturer. I ordered this one from a well-known e-commerce merchant.

    They come in lots of different sizes. The one in the picture is about US$10. I could have used a smaller one, but I rethought the physical arrangement of this project in my garage. I was originally going to have a central control unit that would house the board and the display, and then there would be two remotely mounted rotary encoder switches for turning the lights on and off and controlling the dimmers. I'm now thinking that. One of those rotary encoder switches will be mounted on the end of this box with the controller. There's plenty of room for the zillion wires I will have to connect to the board, and I don't really need very much interior room for the rotary encoder.

    I don't have this box in my hands yet, but I have high hopes for it. Finally, the problem of making the display visible is solved.

  • Put the metal to the metal

    WJCarpenter07/26/2020 at 00:31 0 comments

    Today was finally the day. I assembled the main board. After all of that, I hooked up a 12vdc power supply to the "a" power input, and the screen came alive with my test outputs. I found a couple of glitches during assembly, and I've done enough projects to know there could be more waiting for me as I start wiring up peripherals, but it felt pretty good seeing features instead of smoke.

    Here's a picture of the assembled board (except for the display, which slides into those blue sockets on the ends; some barbarian let the soldering iron touch the shorter one). 
    More details in the build instructions.

  • Adding i2c

    WJCarpenter07/25/2020 at 01:19 0 comments

    I've pretty much decided to add an i2c bus using a couple of unused pins on the processor. I have a few bme280 temperature/pressure/humidity sensors laying around from another project, and it will be interesting enough to get that environmental info from my garage.

    On the PCB, I isolated the lands for those no-connect pins. I should be able to easily tack-solder onto the pins of the processor board for the signals. For Vcc and Ground, I have plenty of places to tack-solder. For one of the pins, I have to use a pin that is set aside for UART Rx or Tx. I wasn't sure whether those would work for i2c, but since I am doing OTA updates, I think they are available without any problems. I did a test on the breadboard, and it works fine.

    This won't be as tidy as bringing it out to a screw-terminal connector, as I did with all of the other off-board connections, but I can live with that. To keep the sensor away from being influenced by the main board heat, I'll have the sensor dangling with a few inches of ribbon cable anyhow.

    Hey, still 2 GPIO pins left on the microprocessor board (one of which is the on-board LED). Come on, think! There must be something I can cobble together with that.

  • The current breadboard

    WJCarpenter07/24/2020 at 20:18 0 comments

    {Editor's note: I re-read all of the project logs to refresh my memory of some things. I was surprised to find out I had started the project log almost exactly 3 years ago. That's slow, even for me, and I was already thinking about it for a while before I got around to making this project. Sheesh.]

    I've got most of the logic of the circuitry laid out on a breadboard now. Since this is just proof-of-concept for the stuff, I only bothered with a single PIR sensor and a single rotary encoder. For the dimmer feature, I am driving an LED through one of the N-channel MOSFETs that I plan to use. The display is just showing some simple status information as I test things out. I haven't yet designed what the display will look like when the system is operational.

    • The "S" changes from red to green while the rotary encoder switch is pressed.
    • The "P" changes from red to green while the PIR data line is high.
    • The "Count" value is keeping track of rotary encoder ticks.
    • The clock value is kept in sync OTA by a component. (Who doesn't need another clock?)
    • The smaller text is just dummy stuff so I could get an idea of the font rendering.

  • Looking at

    WJCarpenter07/22/2020 at 03:48 0 comments

    While I haven't been actively working on this for a while, I have been thinking about the software design from time to time. 

    I've always imagined a paradigm of having a thread react to inputs from the PIRs, the rotary encoders, and the switches on the rotary encoders but putting things onto some kind of queue. Another thread would manage state and process items on the queue. That seems grand, indeed, though it might mean getting pretty far along in the Espressif SDK native features.

    It so happens that for another little project I decided to finally take a look at That project makes it pretty easy to do simple sensor readings and have them feed into MQTT and/or I wondered if it were worth the trouble, and I was overwhelmingly pleasantly surprised. It's well-documented, easy to work with, has good tooling, and it already supports zillions of things you might hook to your esp8266 or esp32 board. For things it doesn't directly support, it's often simple to add them as custom components, and for a lot of natively-supported things you can escape into Arduino-esque C++ to get exactly what you want. There's a vibrant community of people doing things with it, so it's not just "some guy" that you're depending on to have all of the ideas. The bonus is that your can do over-the-air (OTA) updates to the firmware after the first USB-connected upload. Pretty cool.

    OK, that's great for scattering bme280s around your house, but can it be used for something as *cough* sophisticated as this project? I believe it can. It still has that simple-minded Arduino loop() inside, but it packs a lot into it while still iterating that loop pretty fast. I was afraid the busy loop could miss input events, but so far it seems to be fast enough.

    My plan is to let esphome handle the low-level dealings with the inputs and outputs. I'll use the equivalent of a state table to react to the processed inputs and tell esphome what to do with the outputs. I'm back to breadboarding things to prove in individual components one at a time to make sure they actually behave in the way I expect. So far, so good.

  • Pull up! Pull up! Pull up!

    WJCarpenter07/22/2020 at 03:30 0 comments

    I've had this project on the back-burner for a while, but I've recently started dusting it off.

    First, I have to say that I'm pleased with the amount of effort I put into labelling pins on the schematic. It's a fact of life in microprocessor board land that every pin tends to have 3 designations. There is the name the chip maker gives the pin on the chip. There's the name the breakout board maker prints on the silkscreen. And then there's the constant defined in some board definition that fits into a programming framework. Those multiple names bedevil us all. However, I put just about everything that I could identify onto the schematic, so it minimizes the amount of remembering that I have to do now after all this time. Yay, me!

    Second, I'm slightly annoyed at something, and I can't find anyone to blame but me. When I got to laying a few things out on the breadboard again, this time with connections matching the schematic design, I discovered something about the ESP32 that I guess a lot of people know. GPIOs 34-39 are input-only pins. I knew that and took it into account in my schematic and board layout. The part that I didn't notice is that those pins also don't have any internal pull-up/pull-down resistors. In my design, I'm using pins 35 and 38 as the inputs pins for the switches built into the rotary encoders. Not only do they float, they wander aimlessly up and down on the breadboard. Grrr. Looking at the board layout, it looks like I won't have too much trouble soldering on external pull-down resistors. It's just annoying. 

    It would be less annoying if I hadn't already had the boards made long ago. If I end up having to re-do the boards for some other reason, I can fix the design to change a couple of pins. With the current design, I've still got a few no-connects, and I was thinking of adding a bit-banged I2C bus (I might as well have a temperature sensor in my garage). 

  • FreeRTOS calls

    WJCarpenter11/05/2017 at 22:03 0 comments

    I guess I'm going to seem pretty fickle about the software environment, but it's really born of ignorance rather than wishy-washy-ness.

    Earlier, I commented that I would probably use Lua so that I could take advantage of multi-threading to simplify the logic of the control software. I knew that the ESP32 has FreeRTOS inside. After all, that's what at least one of the Lua implementations is built on. What I didn't realize until today was that the ESP32 plugins for the Arduino ecosystem exposes most of the FreeRTOS calls. (It was brought to my attention by this youtube video #168 ESP32 Dual Core on Arduino IDE including Data Passing and Task Synchronization  from Andreas Spiess. 

    Once the idea got into my thick skull, I found there was plenty of tutorial and reference material for making FreeRTOS calls from within an Arduino sketch. The main advantage, of course, is the availability of plenty of Arduino-targeted libraries for devices and sensors. Perhaps the same is true for Espressif's SDK for the ESP32. I'm going to start with the Arduino ecosystem in the interest of getting this project done in less than 12 parsecs.

    (Notice above I said Arduino ecosystem instead of Arduino IDE. Since I have been a software developer for a long time, the Arduino IDE drives me a little crazy, though I understand why it is the way it is. Anyhow, I hope to some day spend the time to iron out a smooth path to doing in some other tool what is convenient in Arduino IDE.)

View all 28 project logs

  • 1
    Important up-front notes.


    1. Many project assembly instructions are written for a generic audience and include step-by-step component ordering. If you've done enough projects, you probably have your own routine for placing things, and you probably don't pay much attention to that part of the assembly instructions. This board has sizeable components on both sides of the board, and the positions overlap. If you do some of the things in the wrong order, you may find that you can't get at the lands to solder later components. If you are experienced, you can visualize it yourself and do whatever you want. If you are less experienced, I recommend using the order that I enumerate.
    2. The overall power supplies for the project are the type of 12vdc wall warts you can find many places, and they power the LED strips themselves. In addition, the "a" input feeds into an adjustable power supply component mounted on the main board. It powers the microprocessor and everything else other than the LED strips. Once you apply power to the assembled board, that adjustable power supply will be immediately feeding power to the microprocessor board. It is therefore important that you adjust the power supply to have an output 3.3vdc before placing it on the main board. If you try to adjust it after it's on the board, you may be unlucky and damage the microprocessor.
  • 2
    Sparkfun ESP32 thing

    The first component to be placed is the microprocessor board, a Sparkfun ESP32 thing. This is a bit fiddly to place simply because it has a lot of pins, and the tolerance for the PCB holes is tight. If you have not already soldered the pin strips to the microprocessor board, I suggest you first insert them into the main PCB and then place the microprocessor board on top of them. That should give you enough wiggle room to get the pins inserted in both boards, and there will be enough friction to hold things in place while you do your soldering. (I had already soldered my pins to the microprocessor board, but I had to desolder them to be able to do this step. Don't be like me.)

    • Insert the pins (2 strips of 20 pins each) by pushing them from the side with the silkscreen outline of the ESP32 thing. The long ends of the pins should go through the PCB with the little plastic nubbin and the short end of the pins remaining on the silkscreen side.
    • Place the Sparkfun ESP32 thing onto the short ends of the pin strips. Be careful of the orientation. The printed name of the board should match up with the printed name on the silkscreen. See the photo. It's easy to get it mixed up because the USB and battery connectors make it seem like that's the main end of the board.
    • Solder the long ends of the pins to the bottom of the PCB. Solder the short ends of the pins to the Sparkfun ESP32 thing.
  • 3
    Adjustable power supply board

    Stop. Don't insert this on the PCB yet.

    Because of the physical layout, we had to solder the microprocessor board onto the PCB first. When we apply power to the adjustable power supply, it will be immediately sending power to that microprocessor board. If the output voltage is not right, it can damage the board. Before adding the adjustable power supply to the main PCB, carefully adjust it so that the output is close to 3.3vdc. 

    The adjustable power supply board has clear markings and handy pins for the inputs and outputs. Using whatever combination of alligator clips, bobby pins, paper clips, and baling wire that you can find, attach a 12vdc supply to the input pins. Positive should go to the IN+ pin, and ground should go to the IN- pin. Measure the output voltage on the OUT+ and OUT- pins. Use a small screwdriver to adjust the potentiometer on the board to get the output voltage to 3.3vdc. This voltage will be applied directly to the 3.3vdc input voltage of the microprocessor board.

    When you have the voltage adjusted, you are ready to place the power supply on the board. It goes on the bottom side of the board, where you see its silkscreen outline.

    • Notice that the pins from the microprocessor board are sticking through from the other side. (They are not shown in the photo just above.) As is, they interfere with the placement of the power supply board. Clip off the ends of the pins from the microprocessor board. You can either clip them all off (preferred), or you can clip just the central pins that overlap with the power supply position.
    • Insert the pins of the power supply board into the marked holes on the PCB. Double check that you got the orientation correct. Also check that no pins from the microprocessor board touch or come close to touching the power supply board.
    • Solder the 4 corner pins of the power supply board in place.

View all 8 instructions

Enjoy this project?



Graham Toal wrote 07/16/2017 at 02:12 point

This (use a pi zero w for lower cost, or stick with the ESP8266 if you prefer working at a low level) should do most of the analog side for you:

  Are you sure? yes | no

WJCarpenter wrote 07/16/2017 at 02:30 point

Interesting idea. Thanks.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates