LED/Pixel home theater project decesions

Grumpy_Mike:
There is no need for neopixel strips here. Generally, lighting requires all the lights in any one area to be the same colour.

There is no requirement, but neopixels are way easier to deal with that MOSFETs for an RGB controller for a newbi.

I am doing this project on a much larger scale right now.

video of my strips on youtube

I can control 6 sections of the strip, and some of the sections overloop each other. It is controlled from a single ESP8266. I would recommend using a strip with Data and Clock, because the signal will be a bit more reliable over long distances.

Here is basically what i have:

Arduino Due to control a coldTears touchscreen, which communicates with an on-board ESP8266 via i2c to send data wirelessly to the controller for the LED lights which is in the attic.

The two wireless controllers communicate via MQTT which is using an old android tablet as the server.

On the controller, i have the esp8266, a switching voltage regulator to drop the 12vin to 5v, and a level shifter to boost the 3.3v signals from the esp to 5v.

becase code snippets are fun:

Here is the where my zone processing takes place (determin which zones should be on, which zones should be off, and which segments to turn on or off)

void refreshLEDS() {
  switch (zoneJustSetup) {
    case 1: //all segments on
      {
        TelnetClient.println("zone 1");
        zonesOn[1] = 1; zonesOn[2] = 0; zonesOn[3] = 0; zonesOn[4] = 0; zonesOn[5] = 0; zonesOn[6] = 0; zonesOn[7] = 0;
        break;
      }
    case 2: // back row on
      {
        TelnetClient.println("zone 2");
        zonesOn[1] = 0; zonesOn[2] = 1; zonesOn[3] = 0; zonesOn[4] = 3; zonesOn[5] = 0; zonesOn[6] = 3; zonesOn[7] = 0;
        break;
      }
    case 3: // center box on
      {
        zonesOn[1] = 0; zonesOn[2] = 0; zonesOn[3] = 1; zonesOn[4] = 3; zonesOn[5] = 3; zonesOn[6] = 3; zonesOn[7] = 3;
        SegmentsOn[0] = 3; SegmentsOn[1] = 3; SegmentsOn[2] = 3; SegmentsOn[3] = 3; SegmentsOn[4] = 1; SegmentsOn[5] = 1; SegmentsOn[6] = 1; SegmentsOn[7] = 1; SegmentsOn[8] = 3;
        break;
      }
    case 4: // front box on
      {
        zonesOn[1] = 0; zonesOn[2] = 3; zonesOn[3] = 3; zonesOn[4] = 1; zonesOn[5] = 0; zonesOn[6] = 0; zonesOn[7] = 0;
        break;
      }
    case 5: //all sides on
      {
        zonesOn[1] = 0; zonesOn[2] = 0; zonesOn[3] = 3; zonesOn[4] = 0; zonesOn[5] = 1; zonesOn[6] = 0; zonesOn[7] = 0;
        SegmentsOn[0] = 1; SegmentsOn[1] = 1; SegmentsOn[2] = 1; SegmentsOn[3] = 1; SegmentsOn[4] = 3; SegmentsOn[5] = 3; SegmentsOn[6] = 3; SegmentsOn[7] = 3; SegmentsOn[8] = 1;
        break;
      }
    case 6: //the peak on
      {
        zonesOn[1] = 0; zonesOn[2] = 3; zonesOn[3] = 3; zonesOn[4] = 0; zonesOn[5] = 0; zonesOn[6] = 1; zonesOn[7] = 3;
        break;
      }
    case 7: //just thesides on
      {
        zonesOn[1] = 0; zonesOn[2] = 0; zonesOn[3] = 3; zonesOn[4] = 0; zonesOn[5] = 0; zonesOn[6] = 3; zonesOn[7] = 1;
        break;
      }
    default:
      {
        TelnetClient.print("RefreshLEDS ERROR");
        break;
      }
  }
  for (int i = 0; i < 9; i++) {
    SegmentsOn[i] = 0; 
  }

  if (zonesOn[1] == 1) {
    SegmentsOn[0] = 1; SegmentsOn[1] = 1; SegmentsOn[2] = 1; SegmentsOn[3] = 1; SegmentsOn[4] = 1; SegmentsOn[5] = 1; SegmentsOn[6] = 1; SegmentsOn[7] = 1; SegmentsOn[8] = 1;
  }

  if (zonesOn[2] == 1) {
    SegmentsOn[0] = 1; SegmentsOn[7] = 1; SegmentsOn[8] = 1;
  }

  if (zonesOn[3] == 1) {
    SegmentsOn[4] = 1; SegmentsOn[5] = 1; SegmentsOn[6] = 1; SegmentsOn[7] = 1;
  }
  if (zonesOn[4] == 1) {
    SegmentsOn[1] = 1; SegmentsOn[2] = 1; SegmentsOn[3] = 1;
  }
  if (zonesOn[5] == 1) {
    SegmentsOn[0] = 1; SegmentsOn[1] = 1; SegmentsOn[2] = 1; SegmentsOn[3] = 1; SegmentsOn[8] = 1;
  }
  if (zonesOn[6] == 1) {
    SegmentsOn[2] = 1;
  }
  if (zonesOn[7] == 1) {
    SegmentsOn[0] = 1; SegmentsOn[1] = 1; SegmentsOn[3] = 1; SegmentsOn[8] = 1;
  }

  for(int i=0; i < 9; i++){
    if(SegmentsOn[i] == 1){
      }
    if(SegmentsOn[i] == 0){
      for(int j = 0; j < segmentSizeAry[i]; j++){
        leds[segments[i][j]] = 0;
         }
    }
  }


  turnLEDSon();
}

void turnLEDSon() {
  if (zonesOn[1] == 1 && zone1Array[zisON] == 1) {
    isOn[1] = 1;
  }
  else if (zonesOn[1] == 0 || zone1Array[zisON] == 0) {
    isOn[1] = 0;
  }

  if (zonesOn[2] == 1 && zone2Array[zisON] == 1) {
    isOn[2] = 1;
  }
  else if (zonesOn[2] == 0  || zone2Array[zisON] == 0) {
    isOn[2] = 0;
  }

  if (zonesOn[3] == 1 && zone3Array[zisON] == 1) {
    isOn[3] = 1;
  }
  else if (zonesOn[3] == 0  || zone3Array[zisON] == 0) {
    isOn[3] = 0;
  }

  if (zonesOn[4] == 1 && zone4Array[zisON] == 1) {
    isOn[4] = 1;
  }
  else if (zonesOn[4] == 0 || zone4Array[zisON] == 0) {
    isOn[4] = 0;
  }

  if (zonesOn[5] == 1 && zone5Array[zisON] == 1) {
    isOn[5] = 1;
  }
  else if (zonesOn[5] == 0  || zone5Array[zisON] == 0) {
    isOn[5] = 0;
  }

  if (zonesOn[6] == 1 && zone6Array[zisON] == 1) {
    isOn[6] = 1;
  }
  else if (zonesOn[6] == 0  || zone6Array[zisON] == 0) {
    isOn[6] = 0;
  }

  if (zonesOn[7] == 1 && zone7Array[zisON] == 1) {
    isOn[7] = 1;
  }
  else if (zonesOn[7] == 0  || zone7Array[zisON] == 0) {
    isOn[7] = 0;
  }
for(int i = 0; i < 7; i++){
  if (isOn[i] == 1) {
    zonefill(i);
  }
}
}

void zonefill(byte SelectedZone) {
  byte FillProgram;
  byte RGBr;
  byte RGBg;
  byte RGBb;
  byte Speed;
  byte DimmingV;
  //TelnetClient.print("Filling Zone: ");
  // TelnetClient.println(SelectedZone);

  switch (SelectedZone) {
    case 1:
      {
        FillProgram = zone1Array[0];
        RGBr = zone1Array[1];
        RGBg = zone1Array[2];
        RGBb = zone1Array[3];
        DimmingV = zone1Array[4];
        Speed = zone1Array[5];
        programsArray[FillProgram](RGBr, RGBg, RGBb, DimmingV, Speed, SelectedZone);
        break;
      }
    case 2:
      {
        FillProgram = zone2Array[0];
        RGBr = zone2Array[1];
        RGBg = zone2Array[2];
        RGBb = zone2Array[3];
        DimmingV = zone2Array[4];
        Speed = zone2Array[5];
        programsArray[FillProgram](RGBr, RGBg, RGBb, DimmingV, Speed, SelectedZone);
        break;
      }
    case 3:
      {
        FillProgram = zone3Array[0];
        RGBr = zone3Array[1];
        RGBg = zone3Array[2];
        RGBb = zone3Array[3];
        DimmingV = zone3Array[4];
        Speed = zone3Array[5];
        programsArray[FillProgram](RGBr, RGBg, RGBb, DimmingV, Speed, SelectedZone);
        break;
      }
    case 4:
      {
        FillProgram = zone4Array[0];
        RGBr = zone4Array[1];
        RGBg = zone4Array[2];
        RGBb = zone4Array[3];
        DimmingV = zone4Array[4];
        Speed = zone4Array[5];
        programsArray[FillProgram](RGBr, RGBg, RGBb, DimmingV, Speed, SelectedZone);
        break;
      }
    case 5:
      {
        FillProgram = zone5Array[0];
        RGBr = zone5Array[1];
        RGBg = zone5Array[2];
        RGBb = zone5Array[3];
        DimmingV = zone5Array[4];
        Speed = zone5Array[5];
        programsArray[FillProgram](RGBr, RGBg, RGBb, DimmingV, Speed, SelectedZone);
        break;
      }
    case 6:
      {
        FillProgram = zone6Array[0];
        RGBr = zone6Array[1];
        RGBg = zone6Array[2];
        RGBb = zone6Array[3];
        DimmingV = zone6Array[4];
        Speed = zone6Array[5];
        programsArray[FillProgram](RGBr, RGBg, RGBb, DimmingV, Speed, SelectedZone);
        break;
      }
    case 7:
      {
        FillProgram = zone7Array[0];
        RGBr = zone7Array[1];
        RGBg = zone7Array[2];
        RGBb = zone7Array[3];
        DimmingV = zone7Array[4];
        Speed = zone7Array[5];
        programsArray[FillProgram](RGBr, RGBg, RGBb, DimmingV, Speed, SelectedZone);
        break;
      }

  }
}

void ledOverrides() {
  if (turnLEDSoff == 1) {
    for (int i = 0; i < 512; i++) {
      leds[i].setHSV(0, 0, 0);
    }
  }
}

But, it won't work on an arduino, because it requires a massive amount of SRAM..

Reburg99:
yeah, I didn't choose my words wisely on amps,watts and power....

i wasn't 100% sure if it was groups of 3 when I purchased them, but was pretty sure it was. I"m not sure what else to call them, pixel seems to be the accepted terminology.

Its still a pixel, you just have lower resolution, I used 3 pixels each on my project as well... I would have recommended WS2801's or APA102's over Neopixels, because they both have a dedicated clock line and i found that to be more reliable over longer distances of pixels.

12v strips will require fewer "injections" of power than 5v strips. I found that i needed to inject power every 8ft of strip to get a nice even brightness over the whole strip... my leds were 48leds/meter... so if you have less leds you might get away with spreading them further appart, if you have more, move them closer together. I used 18awg wire to inject the power along the strips.

@Qdeathstar I've not purchased all the strips yet. I purchased one strip to test and experiment with, if I find I have issues I can always move to the 102's. I pulled 4 conductor wire everywhere.

I have a friend that's running 2811's in his Christmas lights and has runs over 100' long and has no signal issues. I also tested with a 25' length of wire that I coiled up and threw on top of my power strips for my computers, I didn't notice any signal issues. I figured if I can do that, I shouldn't expect too many issues.

Thanks for the code snippet, I'm going to take a look at it today and see if I can use any of it or at lest give me a guide of how to write up my code.

well, I have a 'proof of concept' put together buy using 6 buttons for 3 zone outputs and 3 colors to select. Now to find a smallish touch screen and more coding!

Here's the code if you care to comment.

// define output zones, groups of LEDs
#include<FastLED.h>
#define NUM_LEDS 3
#define NUM_STRIPS 3

//Define other variables
int buttonState = 0;
int zone = 0;

//Creates LED arrays
CRGB leds[NUM_LEDS];

//Sets global brightness level(i think :))
uint8_t gBrightness = 128;

void setup() {
//initialize the pushbuttons pin as an input
  pinMode(2, INPUT);
  pinMode(3, INPUT);
  pinMode(4, INPUT);
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  pinMode(7, INPUT);

//setup outputs for multiple zones
  FastLED.addLeds<WS2811,9,  BRG>(leds, NUM_LEDS);
  FastLED.addLeds<WS2811,10, BRG>(leds, NUM_LEDS);
  FastLED.addLeds<WS2811,11, BRG>(leds, NUM_LEDS);
}

void loop() {
  int R=0; int G=0; int B=0;
  FastLED.clear();
  //Read the state of the pushbuttons 2-4 to select zone
  buttonState = digitalRead(2);
  if (buttonState == LOW) {
    zone = 0;
  }
  buttonState = digitalRead(3);
  if (buttonState == LOW) {
    zone = 1;
  }
     
  buttonState = digitalRead(4);
  if (buttonState == LOW) {
    zone = 2;
  }
  //Read the state of the pushbuttons 5-7 to apply color to the selected zone         
 buttonState = digitalRead(5);
  if (buttonState == LOW) {
   fill_solid(leds, NUM_LEDS,CRGB::Red);
   FastLED[zone].showLeds(gBrightness);
  }

  buttonState = digitalRead(6);
  if (buttonState == LOW) {
    fill_solid(leds, NUM_LEDS,CRGB::Green);
    FastLED[zone].showLeds(gBrightness);
  }
  buttonState = digitalRead(7);
    if (buttonState == LOW) {
     fill_solid(leds, NUM_LEDS,CRGB::Blue);
     FastLED[zone].showLeds(gBrightness);
  }
}

Reburg99:
Just so I understand, what the deal with the timing anyways? I get the issues with noise and glitches', but can you help me understand the timing component?

The timing on those strips is pretty critical and pretty fast. Problem with longer wires is you get all kinds of trouble. Noise coupling, reflections, dispersion. Al this can make NeoPixels ignore commands or see commands wrong. The strips with separate Clock and Data are indeed a bit better for longer runs because they are less time critical. But still, can't recommend longer runs of it. Distributing everything is much simpler and more reliable in the long run then. Only making multiple nodes talk to each other is an extra step in the designing process which I would not call really newbie proof.

Also you need massive amounts of ram and you're doing quite a bit of calculation then if you want to use proper HSV.

Qdeathstar:
There is no requirement, but neopixels are way easier to deal with that MOSFETs for an RGB controller for a newbi.

Don't agree. All you need is a single mosfet. Yes, that's more complicated then connecting a 12V Pixel. 5V pixels are already more complicated because the current gets huge pretty quick.) But on the software side using PWM is sooooooooo much simpler then pixels (although FastLed makes it already a bit simpler). So hardware and software combined I would say a normal RGB strip with a mosfet is still simpler.
And psssst, F() macro and NOTHING follows a ; :wink:

Reburg99:
I have a friend that's running 2811's in his Christmas lights and has runs over 100' long and has no signal issues.

That's because there is no big gap between leds and each LED makes a new and clean signal for the next.

Reburg99:
I also tested with a 25' length of wire that I coiled up and threw on top of my power strips for my computer.

That's the difference between "Hé, it works fine!" and "It's a good design/idea". Although it might work fine now, if you stretch the limits you might get problems in the future. So just saying, be warned. Because fixing it then is always going to give you way more headaches and trouble then it is when you design it from the ground up.

Reburg99:
Here's the code if you care to comment.

  • Give every pin a name. And for the buttons, use arrays. Would have saved you halve the code.

  • Don't use plane RGB, use HSV. Looks wayyyyyyyyyyyy better.

  • Use button debounce

  • buttonState has NO right to be a global. And using a int for it is madness :wink:

  • You never use the variables R, G and B (which have terrible names anyway)

All you need is a single mosfet. Yes, that's more complicated then connecting a 12V Pixel.

This is only the case in single color correct? For a strip of RGB, isn't it going to be 3 mosfets?

  • You never use the variables R, G and B (which have terrible names anyway)

I had attempted to use various RGB color codes, which ended up not working as anticipated... I thought I had deleted all the references to them :(.

  • buttonState has NO right to be a global. And using a int for it is madness :wink:

That was stolen borrowed from some example code.... don't remember which one at this point, but I get what you're saying about it.

Thanks for your input on the rest and will make some notes for next time!

Reburg99:
This is only the case in single color correct? For a strip of RGB, isn't it going to be 3 mosfets?

Yes, in fact 3 MOSFETs for each section of strip that you want to independently control the colour of. And a PWM output for each MOSFET. If you only need 2 sections, then that's not too bad. But if you have 8 sections, you need 24 MOSFETs, 24 PWM outputs and 24 wires to carry the current to each section. This means you have to use a Mega, or a separate PWM chip(s) or an Uno/Nano for each section or pair of sections. That's why I still think the neopixel/ws2811/ws2812b strips will be simpler, despite their drawbacks.

The current does not rise more dramatically for 5V strips vs 12V strips. It is always 12/5=2.4 times higher. However, what is a problem is that the power dissipated in the cables is proportional to the current squared, so 2.4*2.4 = 5.76 times more than at 12V.

Hey PaulRB

Thanks for clarifying, However I'm not sure I'm following your last statement

However, what is a problem is that the power dissipated in the cables is proportional to the current squared, so 2.4*2.4 = 5.76 times more than at 12V.

Are you refereeing to the voltage drop at 5v, there by increasing the amperage?

Reburg99:
Are you refereeing to the voltage drop at 5v, there by increasing the amperage?

No, was referring to the power dissipated in the cable as heat. The voltage drop is 2.4 x what it would be for 12V.

PaulRB:

That's true, have to give you that. But making a single board with 24 mosfets and a PWM driver isn't that hard. But yeah, does makes it harder.

So pixels is indeed not that harder (but it is way more expensive though ;). But I still would not have a single controller for them. For the signals to start with but also because 10m of strip will now take 60led/m x 10m x 3bytes / 3per group = 600bytes. Which starts to get a lot for a Uno/Nano. And calculating the color for all 200 "pixels" when using proper HSV also gets intensive. No, not impossible. But I do think a distributed system is easier in the long run :slight_smile:

And yeah, the use of 12V pixels is a good thing. The 5V pixels take more then 2,4 times the current, they take 3 times the current. That's because in the 5V version every pixel takes 3 x (for RGB) 20mA where as the 12V version that's 3 x (for RGB) 20mA per 3 leds. So the 5V version wastes more power in the control part of the leds. So that makes 9 times the losses in cables. Also, a drop of 0,5V is a lot more noticeable on the 5V version (where it's 10%) then it is on the 12V version (where it's just 4%).