LSC LED Strip Home Assistant Control With MQTT and Custom Neopixelbus Protocol

by headseth in Circuits > Electronics

47 Views, 0 Favorites, 0 Comments

LSC LED Strip Home Assistant Control With MQTT and Custom Neopixelbus Protocol

LSC Led strip hack.png
trim.58856445-A44A-4DC0-97DB-4F66D34DF987.GIF

In one of my previous posts I said I liked to hack my way into existing devices. One of the devices that I could not so easily hack or use ESPHome with, was the addressable LED-strip from LSC. This one had a much complexer protocol than the standard Neopixel library could handle. I needed to rewrite this protocol or, so to say, change the way this protocol is addressing the LED's. This because the LED-strip its RGB and CCT LED's are ordered differently.

I managed to get this working with an ESP32 D1 Mini with use of MQTT and programmed in the Arduino IDE! It was a fun project and it is still not done.

It can receive home assistant commands via MQTT and is capable of doing effects as well. I still need to program the effects though...

Supplies

  1. ESP32 (D1 Mini or something else)
  2. Home assistant
  3. PC / Mac with the Arduino IDE
  4. Soldering equipment
  5. A transistor and some resistors

How Does This Protocol Work?

LED strip diagram.drawio.png

With use of an oscilloscope, I managed to read the data signal send by the original controller. There was something quite similar yet different from most addressable LED's I have seen. This strip is 5 meters long and has "segments" of 20 centimeters. Each segment has 6 RGB and 6 CCT LED's. For who does not know what I mean with CCT LED's, these give warm and cold white lighting. These 12 LED's are controlled by 2 controlling IC's, 1 for the RGB and 1 for the CCT. The order of receiving the data is: RGB -> CCT -> RGB -> CCT etc. Each controller needs 3 bytes (red, blue and green). The CCT needs 3 bytes too but ignores one of those 3 bytes entirely!

So in order to put the first segment red, we send: [255,0,0]. But if we want to make the first segment cold white, we write; [0,0,0],[0,0,255]. The CCT's byte order is [WW,0,CW] (WW = warm white, CW = cold white, 0 = ignored byte). This byte order continues on until the end of the LED-strip. However, this happens only if you continue to send this order. These controllers "eat" these 3 bytes and let the rest of the data go to the next controller. This will do the same, and the same, and the same...

To make everything red, you write: [255,0,0],[0,0,0],[255,0,0],[0,0,0]... Notice that you need to send the CCT bytes as well!

Something else is needed before connecting the strip to the ESP32. The data signal is 5V that goes into the LED-strip. However, using 3V3 (directly from the ESP32) works too for a short length. This is not reliable so I used a transistor and some resistors to make this signal 5V towards the LED-strip.

Planning the Code Writing

The Neopixel library is used allot for addressable LED's. However, because of these byte order, we need to modify this. Not only that but some things more. I list everything below.

  1. The ESP32 needs to be able to connect with WiFi. The ESP8266WiFi library needs to be included.
  2. We are going to control the ESP32 with use of MQTT, we need the PubSubClient library as well.
  3. We are using the NeoPixelBus library because this one can be included on the D1 Mini and is capable of using the UART protocol to send the data to the LED's.
  4. The MQTT data is send and received in JSON format. We could hardcode this into the D1 Mini but that is allot of work. Instead we use the ArduinoJson library.
  5. We want the LED-strip to fade towards the colour that has been chosen by the user. Smooth transitions in the lighting.
  6. We want to change the brightness of the strip. Because the controllers on the strip do not use a brightness byte, we need to do some "math" ourselves.
  7. We need to remember the previous LED-state, -colour, -brightness and more.
  8. We need to send the status of the LED-strip to home assistant via MQTT in JSON format.
  9. Home assistant needs to be able to detect our device with use of a discovery message.
  10. Home assistant does not separate the WW and CW values. Instead, it will send an 500 max value to our device. Thats why we need to do some "math" here too.

Understanding the JSON Format

Screenshot 2025-10-29 at 22.16.19.png
Screenshot 2025-10-29 at 22.18.13.png
Screenshot 2025-10-29 at 22.18.28.png
Screenshot 2025-10-29 at 22.22.12.png
Screenshot 2025-10-29 at 22.24.07.png

The JSON format is very important. This needs to be structured exactly like the picture shows. We need to make a nested JSON doc in the Arduino code for the colour setting (I will come back to this later). The messages above are the status data send by the ESP32 MQTT device. You can easily read it via the MQTT integration in home assistant.

The message with the most data in it, is not a status message. This is the discovery payload send by the ESP32 to make it discoverable by home assistant. This has to be done in order for home assistant to add this device as an entity. The code that makes the ESP32 do this, is shown in a picture as well.

Start Writing Actual Code! Setup, WiFi, Neopixelbus, MQTT and MQTTcallback

Screenshot 2025-10-29 at 22.33.09.png
Screenshot 2025-10-29 at 22.33.25.png
Screenshot 2025-10-29 at 22.33.42.png
Screenshot 2025-10-29 at 22.34.46.png
Screenshot 2025-10-30 at 12.08.10.png

Let's start at the top of the code. We should include a bunch of things like I said in the list in step 2. After that, we want to add our wifi and MQTT account by changing the variables. My LED-strip has 50 LED-controllers so I made a variable for that. The ledPin is locked for me. I use the UART protocol for the Neopixelbus library. This is boud to pin 2. The topics are used for MQTT. These two can be modified and will be known to the home assistant client while sending the discovery payload later on. The minMireds and maxMireds are used for calculating the WW and CW values from the home assistant format to 2 bytes (1 WW and 1 CW). The "NeoPixelBus<NeoGrbFeature, NeoEsp8266Uart1800KbpsMethod> strip(numLeds);" is mandatory for initialising the Neopixelbus.

After that we can create a simple wifi connection function seen in the picture. It tells to the serial monitor that the device is connecting to wifi (it is in the dutch language in my example). After that, the code will connect to the wifi and keeps trying until it is connected successfully.

When the wifi function is done, we create the MQTT callback function. This can be left empty for now, we will fill this up later.

We want the device to reconnect to MQTT automatically. That is why I created a reconnect function. This will connect to MQTT and sends its availability payload. This is crucial for the MQTT protocol. If the connection is not successful, it will try again every 5 seconds. In this function, the discovery payload is send to the home assistant instance. Every time the ESP32 disconnects from MQTT, you have to send it again.

Finally we create the setup and loop. This is classic Arduino. We start with the serial init, the LED-strip init, we make sure everything is off on the LED-strip, we connect to wifi, we set the MQTT server, MQTT callback and activating the MQTT connection. The updateStrip and sendStateStrip functions are used to set all the LED's and to send the status of the LED-strip to home assistant. The loop function is pretty simple. It keeps track of the MQTT connection and reconnects if necessary.

Also, the LED effects can be programmed here. As shown in the picture, I still need to do this!


LED-strip Parameters

Screenshot 2025-10-30 at 12.14.41.png
Screenshot 2025-10-30 at 12.14.49.png

To make my life easier, I created a structure type with all the LED-strip parameters that are needed. I then made two types of these for the current color and previous color. I made them both empty.

The LED-strip could have effects. To show what effect is on, I used an enum table shown in the picture.

Discovery Payload

Screenshot 2025-10-30 at 12.20.08.png

The next step is to make a discovery function to make the ESP32 visible to home assistant. The code in the picture is everything that is needed. This function creates a JSON format file named "doc". Each value is then added in the correct order. Note that a nested array is added for the color modes and for the effects.

After creating the doc, it is time to send it. First checking if wifi and MQTT are still connected. Then it can be send with the topic shown in the picture. This topic cannot be changed! This is where home assistant wants to receive the data on.

MQTT Callback

Screenshot 2025-10-30 at 18.50.04.png
Screenshot 2025-10-30 at 18.50.25.png
Screenshot 2025-10-30 at 12.35.22.png

The MQTT callback function is the main part of this code! It is used as a parser in my code, translating the incoming message to an JSON doc file and working its way through all the possibilities. This is all pretty complex. I am not going to describe everything with text, try to understand it yourself! The order of the parser is crucial;

  1. On/off needs to come first. Off -> turn it off directly, no need for checking everything else. By the way, home assistant does not send color or brightness values if you just turn it off! If the strip is off and you turn it back on without changing color or brightness in home assistant, home assistant will only send state = on via MQTT. Use the previous data to make the strip the same color and brightness as before. Same goes for the CCT value.
  2. The CCT and RGB values cannot be operated together at the same time via home assistant. I limited this by checking if the CCT value or the RGB value is present in the data and toggle a boolean respectfully.
  3. If home assistant wants color, only color is send and not the CCT values.
  4. If home assistant does not send brightness, use the previous brightness. That is why we saved the previous settings.
  5. Brightness needs to be calculated over the RGB and CCT values send to the LED-strip. This is done in a different function.
  6. The CCT value needs to be converted to 2 bytes for the controller. This is done in rows 234-238.
  7. To fade the color, I created the fadeToColor() function with the transition time in the brackets (500ms for me here at row 304).
  8. Always send the state of the strip to home assistant with the sendStateStrip() function. This function sends all the states of the LED-strip to home assistant. Home assistant can represent the color, brightness etc with use of this.

FadeToColor Function

Screenshot 2025-10-30 at 18.50.44.png
Screenshot 2025-10-30 at 18.50.59.png

The same for the MQTT callback, I am not going to describe all the code. The fadeToColor function calculates all the values that the users want the strip to be. It makes little steps determined by the 500ms transition time. I wanted the strip to transition from color to CCT and back too. That is why the code is looking at the rgbValCheck boolean a couple of times. The for loops inside here are calculating every step that needs to be taken and updates the strip with the updateStrip function.

UpdateStrip Function

Screenshot 2025-10-30 at 12.40.53.png

The updateStrip function is responsible for the correct byte order send to the strip. This order is described in step 1. This is done by looking at the rgbValCheck boolean. This function also scales the color and CCT values to match the brightness wanted.

Creating the Hardware

Screenshot 2025-10-30 at 17.51.42.png
IMG_0521.jpeg
IMG_0522.jpeg
IMG_0523.jpeg
IMG_0524.jpeg

The hardware is pretty simple for this LED-strip. We want to make sure the LED-strip gets his recommended power with the original power supply. The ESP32 is powered by USB. I want to power the ESP32 from the LED-strip power supply in the future. The datapin needs to be attached to a transistor which is toggled by the ESP32. I made a diagram to show how the wiring is needed. Make sure to tie all the GND's to each other! I made a small circuit on a piece of perfboard. I attached a barrel connector where the connector from the power supply perfectly fitted in. I also desoldered the LED-strip connector from the original PCB to attach it to my own PCB. This worked out perfectly. I then soldered all the components like the circuit diagram.

Future Additions

That is it! It is still not perfect though. The following list is something I want to do in the future:

  1. Making a nice PCB with KiCad and a ESP32 supply that gets his power from the LED-strip supply
  2. Maybe a nice enclosure
  3. Fun effects!