How to multiply this code so that each neopixel reacts to assisned LDR

Hello everyone!

I am new to physical computing and I am creating a project for my university assessment. I have basic understanding of code so please bare with me. I am working on interactive16-bit Neopixel rings with an LDR as input. Any tips on how I could implement up to Neopixel rings each individually triggered by assisgned LDR? I understand this might have to be done with an array, just not sure were to go from there in the body of the code.

#include <Adafruit_NeoPixel.h>

#define LDR_PIN A0
#define PIN 2   // input pin Neopixel is attached to

#define NUMPIXELS      16 // number of neopixels in Ring

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

int delayval = 0; // timing delay

int redColor = 0;
int greenColor = 0;
int blueColor = 0;

int lightLevel = 0;
int preLightLevel = 0;

void setup() {
  pixels.begin(); // Initializes the NeoPixel library.
  Serial.begin(9600);
}

void loop() {
  setColor();

  for(int i=0;i<NUMPIXELS;i++){
    // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
    pixels.setPixelColor(i, pixels.Color(redColor, greenColor, blueColor)); // Moderately bright green color.

    pixels.show(); // This sends the updated pixel color to the hardware.

    delay(delayval); // Delay for a period of time (in milliseconds).

  }

}

// setColor()
// picks random values to set for RGB
void setColor(){
  lightLevel = map(analogRead(LDR_PIN), 110, 1023, 0, 15);
  Serial.println(lightLevel);

  if( preLightLevel != lightLevel ) {
    redColor = random(0, 15) + lightLevel;
    greenColor = random(0, 15) + lightLevel;
    blueColor = random(0, 15) + lightLevel;
  }
  
  preLightLevel = lightLevel;
}

Hi @miniklaudia

Explain your project better.

Which microcontroller will you use?

How are you going to connect 16 LDRs to your microcontroller?

RV mineirin

If I understand you correctly... you want each led on the neopixel ring to light up (with some color) depending on the state of a photoresistor? Then you've pretty much done everything you need to do, except to map a photoresistor to each led.

Sure. To map each resistor to each neopixel, you can use an array of pinouts for each photoresistor. Then iterate through that array, read the photoresistor given by the value of the array at that index, determine a color to set the led to, and set the led with the same index (although in your array of neopixels) to that color. Something like this:

// Globally:
// Array of pinouts... change the order of the pins according to the led number
int LDRpins[NUMPIXELS] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16};
int preLightLevels[NUMPIXELS] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

// (I’m omitting void setup)

void loop(){
  for (int x = 0; x < NUMPIXELS; x++) {
    setColor(x);
    pixels.setPixelColor(x, pixels.Color(redColor, greenColor, blueColor));
  }
}

Then make void setColor() take an argument for a pin to set the color for:

void setColor(int index) {
  lightLevel = map(analogRead(LDRpins[index]), 110, 1023, 0, 15);
   if (preLightLevels[index] != lightLevel ) {
    redColor = random(0, 15) + lightLevel;
    greenColor = random(0, 15) + lightLevel;
    blueColor = random(0, 15) + lightLevel;
  }
  
  preLightLevels[index] = lightLevel;
}

Hopefully that makes sense? You’re just repeating everything you’ve done using an array.

Thank you for the feedback! Sorry I am using an Arduino Leonardo and I am using 5 neo pixel rings that have 16 individual leds each (5x16) , all will be connected through in and out. The LDRs I will wire and solder to all analog pins i have available. I will be thinking about making 15 neopixel rings with 15 LDRs in the future using a multiplexer but that is too advanced for me at this moment.

This makes perfect sense thank you so much for taking your time to respond! I will give this a go.

I read your current code like you want to fill each 16 pixels of a strip with the same color.
You can use .fill() for that instead of the for loop.

if you want to assign one LDR to each strip of 16 pixels, consider to put your data into a structure. This data (the ldr and the strip) will be handled as a group of data.
Also the "preLightLevel" belongs to one member of the strip-ldr group member, therefore add a variable for this also to your data structure.

When you have defined your data structure - just declare an array and initialize it with the values.

// https://forum.arduino.cc/t/how-to-multiply-this-code-so-that-each-neopixel-reacts-to-assisned-ldr/934145

#include <Adafruit_NeoPixel.h>
constexpr byte numpixels = 16; // number of neopixels of each ring

struct Group {
  Adafruit_NeoPixel pixels;
  byte ldrPin;
  byte preLightLevel;
};

Group group[] = {
  //                           strip pin                 ldrPin
  {Adafruit_NeoPixel(numpixels, 2, NEO_GRB + NEO_KHZ800), A0, 0},
  {Adafruit_NeoPixel(numpixels, 11, NEO_GRB + NEO_KHZ800), A1, 0},
  {Adafruit_NeoPixel(numpixels, 12, NEO_GRB + NEO_KHZ800), A2, 0}
};

constexpr size_t noOfGroup = sizeof(group) / sizeof(group[0]); // count elements of group

const uint16_t delayval = 0; // timing delay

void setup() {
  Serial.begin(115200);  // use faster Serial
  for (auto & i : group) i.pixels.begin();          // call begin for each strip
}

void loop() {
  for (size_t i = 0; i < noOfGroup; i++) {
    setColor(i);

  }
  delay(delayval); // Delay for a period of time (in milliseconds).
}

// setColor()
// picks random values to set for RGB
void setColor(byte index) {
  byte lightLevel = map(analogRead(group[index].ldrPin), 110, 1023, 0, 15);
  Serial.print(F("i=")); Serial.print(index); Serial.println(F(" lightLevel=")); Serial.println(lightLevel);
  if (group[index].preLightLevel != lightLevel )
  {
    byte redColor = random(0, 15) + lightLevel;
    byte greenColor = random(0, 15) + lightLevel;
    byte blueColor = random(0, 15) + lightLevel;
    uint32_t newColor = (uint32_t)redColor << 16 | (uint32_t)greenColor << 8 | (uint32_t)blueColor; // make one uint32_t color out of 3 single colors
    group[index].pixels.fill(newColor); // for usage of fill see https://learn.adafruit.com/adafruit-neopixel-uberguide/arduino-library-use
    group[index].pixels.show(); // This sends the updated pixel color to the hardware.
    group[index].preLightLevel = lightLevel;
  }
}

Amazing thank you ! In this would I just need to change the size of group to however many I create ? Following the group pattern you assigned to each strip? Sorry again i am not too familiar with this approach.

read the sketch again.
try it.
basically you only need to add more rows of data:

{Adafruit_NeoPixel(numpixels, 8, NEO_GRB + NEO_KHZ800), A3, 0},
{Adafruit_NeoPixel(numpixels, 7, NEO_GRB + NEO_KHZ800), A4, 0},

the number of elements (noOfGroup) will be calculated "automatically". You don't have to change it.

That makes so much sense thank you so much again :smiley:

1 Like

oh sorry, I missed that.

does that mean you will daisy chain your 5 stripes and you are using only one output pin for all your 80 pixels?

I am using not a strip but a neopixel ring , I’m trying to create a more basic and smaller version of this neopixel table example , but using LDRs : NeoPixel Reactive Table : 27 Steps (with Pictures) - Instructables

Yep, in retrospect, using a struct is definitely the way to go.


This is my initial plan to explore if I can get it going.

Then I will be making a more complex one with 15 inputs and neopixels but I know this requires multiplexers which are difficult for me to grasp at the moment , therefore I’m sticking in with my 5 analog pins for now.

Thank you for everyone’s help. This forum is amazing

ok, so if you just daisy chain all your rings (or strips), you might want something like

// https://forum.arduino.cc/t/how-to-multiply-this-code-so-that-each-neopixel-reacts-to-assisned-ldr/934145
// ONE physical strip with 5 virtual groups of 16 pixels each on one output pin

#include <Adafruit_NeoPixel.h>

struct Group {
  const byte ldrPin;
  byte preLightLevel;
};

Group group[] = {
  {A0, 0},
  {A1, 0},
  {A2, 0},
  {A3, 0},
  {A4, 0},
};

constexpr size_t noOfGroup = sizeof(group) / sizeof(group[0]); // count elements of group
constexpr byte numpixels = 16;                                 // number of neopixels of each ring
constexpr uint16_t noOfPixels = numpixels * noOfGroup;         // total number of pixels
constexpr byte pixelPin = 2;                                   // one pin used daisy chain all groups

Adafruit_NeoPixel pixels=Adafruit_NeoPixel (noOfPixels, pixelPin, NEO_GRB + NEO_KHZ800);


const uint16_t delayval = 0; // timing delay

void setup() {
  Serial.begin(115200);  // use faster Serial
  pixels.begin();          // call begin for each strip
}

void loop() {
  for (size_t i = 0; i < noOfGroup; i++) {
    setColor(i);
  }
  delay(delayval); // Delay for a period of time (in milliseconds).
}

// setColor()
// picks random values to set for RGB
void setColor(byte index) {
  byte lightLevel = map(analogRead(group[index].ldrPin), 110, 1023, 0, 15);
  Serial.print(F("i=")); Serial.print(index); Serial.println(F(" lightLevel=")); Serial.println(lightLevel);
  if (group[index].preLightLevel != lightLevel )
  {
    byte redColor = random(0, 15) + lightLevel;
    byte greenColor = random(0, 15) + lightLevel;
    byte blueColor = random(0, 15) + lightLevel;
    uint32_t newColor = (uint32_t)redColor << 16 | (uint32_t)greenColor << 8 | (uint32_t)blueColor; // make one uint32_t color out of 3 single colors
    uint16_t first = index * numpixels;
    pixels.fill(newColor, first, numpixels); // for usage of fill see https://learn.adafruit.com/adafruit-neopixel-uberguide/arduino-library-use
    pixels.show(); // This sends the updated pixel color to the hardware.
    group[index].preLightLevel = lightLevel;
  }
}

but now I think you should do your research about arrays and structures on your own.

Thank you! And yes I’m in the process of learning arrays :smiley: