Museum Interactive: LED Help

Who said? It’s the 21st century, for controlling LEDs there are better choices.

I didn’t catch on to the relays being part of your plan right away. As you see in this and your previous thread, we all have other ideas.

a7

1 Like

Thank you for the helpful example, I'll look into this.

It seems it will be worth looking into Led strip/Neopixels option, and it would be less wire tangling too :sweat_smile:

@J-M-L @groundFungus @alto777

Ok - so lets say I start exploring something like Neopixels as an option for this project.
This LED below would probably be the shape we are looking for, for the map.
NeoPixel Diffused 8mm Through-Hole LED - 5 Pack PRODUCT ID: 1734

Forgive my dumb question, but these are capable of showing white light correct?
We are only looking to have the lights shine in white.

Yes. RGB LEDs can show "white" by illuminating all three colors.

I put white in quote marks because white isn't always white… in fact there are smart LEDs that are not RGB but RGBW which have a fourth LED in them for just white.

Then there's the color temperature specification, warm white, cool white.

So again, there's nothing like trying a sample and making sure it delivers the whiteness and brightness you are aiming for tested in your deployment scenario or a mockup thereof.

a7

I've never used those, so would be worth checking their brightness (I use APA102)

However for the white LEDs you have, a MAX7219 will individually control 64 LEDs, wired in a matrix, at good brightness. That requires three pins. The other two or three LEDs can of course be driven by pins of a Nano.

The matrix means that there are only sixteen connections overall, so the wiring is manageable. NeoPixels may not make the wiring all that easy as all the wiring has to go from one LED to the next and will be zig-zagging all over the place.

I imagine that as purely indicators, not a room light, the exact colour temperature would not be at all critical. the only problem is whether they are sufficiently diffused that the individual colours are not apparent at close quarters.

Yeah but there are people who care, and more that would, especially if they were told they could!

a7

Asked without details
Information not offered
Speculation abounds

1 Like

I've ordered a sample of the Through-hole Neopixel LED to see how the color and brightness is.
Its true that for our purposes the color temperature won't be as important, but it'd be good to have them all close in their particular white color.

... apart from the series resistor on the data line.

(RE: Comment #12) I have finally gotten time to sit down and try to implement/test this code with some of the neopixels I got.

I generally understand what you described in the areas to replace info in the code, and was wondering if you could elaborate on a couple of parts for me.

  1. One, what is <FastLED.h> ?
  2. And the other, when you say connect power from both ends what would that look like (simple drawing?).
  3. How would I program the color for the LEDs, or does that default to "white"?

Error message:

Arduino: 1.8.13 (Windows 10), Board: "Arduino Mega or Mega 2560, ATmega2560 (Mega 2560)"
20210604_NatAreaMap_Arduino:9:10: fatal error: FastLED.h: No such file or directory
#include <FastLED.h>

      ^~~~~~~~~~~

compilation terminated.
exit status 1
FastLED.h: No such file or directory
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.

Code you sent (I only adjusted a couple of the numbers so far)

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:
  
#include <FastLED.h>
// For led chips like WS2812, which have a data line, ground, and power, you just need to define dataPin.
const uint8_t dataPin = 3;

// For led chipsets that are SPI based (four wires - data, clock, ground, and power),
// like the APA102, define both dataPin and clockPin
const uint8_t clockPin = 52;              // 13 is SPI SCK on UNO, use 52 on a MEGA

// Define the array of leds
const uint8_t ledCount = 66;              // How many you have
CRGB leds[ledCount];

// Define the zones on the map
const uint8_t maxLedPerZone = 34;         // this is to make our life easy with fixed size arrays even if it wastes a bit of RAM

struct t_zone {
  const uint8_t   ledIDs[maxLedPerZone];  // where they are in the strip, starting at position 0
  const uint8_t   ledCount;               // how many LEDs are in this area
  const uint32_t  lightingDuration;       // How long the area stays lit in ms
  const uint8_t   buttonPin;              // the pin of the button triggering this zone
  bool            ledsAreOn;              // true if leds are on
  uint32_t        startTime;              // utility for timeout
};

t_zone zones[] = {
  /* leds position in strip            count    period  button    keep as is */
  {{0, 1, 2, 3, 4, 5, 6}              , 7     , 20000,    7,      false, 0},
  {{2, 3, 4, 7, 8, 9, 10}             , 7     , 20000,    6,      false, 0},
  {{4, 5, 6, 10, 11, 12, 13, 60, 61}  , 9     , 20000,    5,      false, 0},
};
const uint8_t zoneCount = sizeof zones / sizeof zones[0];

bool ledIsOnInAnotherZone(uint8_t ledId, uint8_t currentZone)
{
  bool ledIsOn = false;
  for (uint8_t z = 0; z < zoneCount; z++) {
    if ((z != currentZone) && zones[z].ledsAreOn) {
      for (uint8_t i = 0; i < zones[z].ledCount; i++) {
        if (ledId == zones[z].ledIDs[i]) {
          ledIsOn = true;
          break;
        }
      }
    }
  }
  return ledIsOn;
}

void zoneOn(uint8_t zoneID) {
  for (uint8_t i = 0; i < zones[zoneID].ledCount; i++)
    leds[zones[zoneID].ledIDs[i]] = CRGB::White;
  FastLED.show();
  zones[zoneID].startTime = millis();
  zones[zoneID].ledsAreOn = true;
}

void zoneOff(uint8_t zoneID) {
  for (uint8_t i = 0; i < zones[zoneID].ledCount; i++)
    if (!ledIsOnInAnotherZone(zones[zoneID].ledIDs[i], zoneID))   // only turn it off if it does not belong to another zone that is ON
      leds[zones[zoneID].ledIDs[i]] = CRGB::Black;
  FastLED.show();
  zones[zoneID].ledsAreOn = false;
}

void checkButtons() {
  for (uint8_t z = 0; z < zoneCount; z++)
    if ((!zones[z].ledsAreOn) && (digitalRead(zones[z].buttonPin) == LOW))
      zoneOn(z);
}

void checkTimeout() {
  for (uint8_t z = 0; z < zoneCount; z++)
    if (zones[z].ledsAreOn && (millis() - zones[z].startTime > zones[z].lightingDuration))
      zoneOff(z);
}

void setup() {
  // sanity check delay - allows reprogramming if accidently blowing power w/leds
  delay(2000);

  // declare button pins
  for (uint8_t z = 0; z < zoneCount; z++) pinMode(zones[z].buttonPin, INPUT_PULLUP);

  // Define led arrangement, see FastLED examples for strip definition
  // https://github.com/FastLED/FastLED/blob/cfffa1351497425931fb9ef5bad0eeb7b0cf8645/examples/Blink/Blink.ino#L17-L57
  FastLED.addLeds<APA102, dataPin, clockPin, RGB>(leds, ledCount);  // BGR ordering is typical
}

void loop() {
  checkButtons();
  checkTimeout();
}
}

Thanks for your help

FastLED is a library that facilitates control of the LED strips. There is extensive documentation in the linked pages.

At least one 1000uF cap is recommended to smooth power. Extras are optional.

Refer to the linked documentation.

1 Like

Agree you can learn much more, but going on a “least you need to know” basis, there’s really not much to smart LEDs after all.

This, from your code

leds[zones[zoneID].ledIDs[i]] = CRGB::White;

is setting a particular LED to a certain color.

So

leds[ LED_number ] = some_color;

is the pattern. Above, LED_number is an index, it should be between 0 zero and N - 1, where N is the number of pixels on the strip.

And some_color is a variable that sets the R, G, B and possibly W intensities to make wide range of colors.

Colors in smart LED use have an internal format. You’ll have to,learn bit about that, or stick with “pre-mixed” colors, which is what the constant CRGB::White is. Presumably you might find CRGB::Red has been also provided, &c. Here’s where the documents can help.

But wait, there’s one last thing… you can do all the changing to the strip like the line I grabbed from your code, but nothing will appear to have changed until you

FastLED.show();

also grabbed from your code. This line refreshes the strip by sending the entire strip’s LED settings for every pixel all at once, boom, new strip display.

So you can take your time making all the pixels whatever color they shou,d be next, then do the show() to reveal the new contents.

TBH I don’t know much more about it than that. Other libraries for smart LEDs have slight variations but amount to the same pattern: set the colors, refresh the strip.

And it happens fast, um, so if you do those steps fast, you can get motion or animation or whatever you want to call time changing LEDs.

Sry if this is obvious, or you already figured it out.

a7

1 Like

File: 20210604_NatAreaMap_Arduino.ino (3.5 KB)

@groundFungus Thanks, I realized I had to download the FastLED library, which I tried to, but may not have done correctly due to the errors? In Arduino I went to Tools>Manage Libraries>and installed FastLED library.
@alto777 Thank you as well for the coloring info.

I in the code I had entered everything that needed change as far as I am aware but am still getting some error messages when i go to verify it. Can anyone see what may be causing the errors?

Some of the messages:

20210604_NatAreaMap_Arduino:97:13: error: a function-definition is not allowed here before '{' token
void loop() {

C:\Users\ryurkovich\Documents\Arduino\libraries\FastLED/FastLED.h:362:2: error: invalid declaration of member template in local class
template<template class CHIPSET>

C:\Users\ryurkovich\Documents\Arduino\libraries\FastLED/FastLED.h:312:2: error: invalid declaration of member template in local class
template<template<uint8_t DATA_PIN> class CHIPSET, uint8_t DATA_PIN>

C:\Users\ryurkovich\Documents\Arduino\libraries\FastLED/FastLED.h:237:2: error: invalid declaration of member template in local class
template<ESPIChipsets CHIPSET, uint8_t DATA_PIN, uint8_t CLOCK_PIN > static CLEDController &addLeds(struct CRGB *data, int nLedsOrOffset, int nLedsIfOffset = 0) {

and it goes on...

Thank you for your help and patience with my inexpertise.

this should be at the top of the sketch, not in the loop() function

#include <FastLED.h>

EDIT:
actually you probably pasted into a template sketch as there are bits and pieces of setup and loop...

the whole code should look like this

#include <FastLED.h>
// For led chips like WS2812, which have a data line, ground, and power, you just need to define dataPin.
const uint8_t dataPin = 3;

// For led chipsets that are SPI based (four wires - data, clock, ground, and power),
// like the APA102, define both dataPin and clockPin
const uint8_t clockPin = 52;              // 13 is SPI SCK on UNO, use 52 on a MEGA

// Define the array of leds
const uint8_t ledCount = 66;              // How many you have
CRGB leds[ledCount];

// Define the zones on the map
const uint8_t maxLedPerZone = 34;         // this is to make our life easy with fixed size arrays even if it wastes a bit of RAM

struct t_zone {
  const uint8_t   ledIDs[maxLedPerZone];  // where they are in the strip, starting at position 0
  const uint8_t   ledCount;               // how many LEDs are in this area
  const uint32_t  lightingDuration;       // How long the area stays lit in ms
  const uint8_t   buttonPin;              // the pin of the button triggering this zone
  bool            ledsAreOn;              // true if leds are on
  uint32_t        startTime;              // utility for timeout
};

t_zone zones[] = {
  /* leds position in strip            count    period  button    keep as is */
  {{0, 1, 2, 3, 4, 5, 6}              , 7     , 20000,    7,      false, 0},
  {{2, 3, 4, 7, 8, 9, 10}             , 7     , 20000,    6,      false, 0},
  {{4, 5, 6, 10, 11, 12, 13, 60, 61}  , 9     , 20000,    5,      false, 0},
};
const uint8_t zoneCount = sizeof zones / sizeof zones[0];

bool ledIsOnInAnotherZone(uint8_t ledId, uint8_t currentZone)
{
  bool ledIsOn = false;
  for (uint8_t z = 0; z < zoneCount; z++) {
    if ((z != currentZone) && zones[z].ledsAreOn) {
      for (uint8_t i = 0; i < zones[z].ledCount; i++) {
        if (ledId == zones[z].ledIDs[i]) {
          ledIsOn = true;
          break;
        }
      }
    }
  }
  return ledIsOn;
}

void zoneOn(uint8_t zoneID) {
  for (uint8_t i = 0; i < zones[zoneID].ledCount; i++)
    leds[zones[zoneID].ledIDs[i]] = CRGB::White;
  FastLED.show();
  zones[zoneID].startTime = millis();
  zones[zoneID].ledsAreOn = true;
}

void zoneOff(uint8_t zoneID) {
  for (uint8_t i = 0; i < zones[zoneID].ledCount; i++)
    if (!ledIsOnInAnotherZone(zones[zoneID].ledIDs[i], zoneID))   // only turn it off if it does not belong to another zone that is ON
      leds[zones[zoneID].ledIDs[i]] = CRGB::Black;
  FastLED.show();
  zones[zoneID].ledsAreOn = false;
}

void checkButtons() {
  for (uint8_t z = 0; z < zoneCount; z++)
    if ((!zones[z].ledsAreOn) && (digitalRead(zones[z].buttonPin) == LOW))
      zoneOn(z);
}

void checkTimeout() {
  for (uint8_t z = 0; z < zoneCount; z++)
    if (zones[z].ledsAreOn && (millis() - zones[z].startTime > zones[z].lightingDuration))
      zoneOff(z);
}

void setup() {
  // sanity check delay - allows reprogramming if accidently blowing power w/leds
  delay(2000);

  // declare button pins
  for (uint8_t z = 0; z < zoneCount; z++) pinMode(zones[z].buttonPin, INPUT_PULLUP);

  // Define led arrangement, see FastLED examples for strip definition
  // https://github.com/FastLED/FastLED/blob/cfffa1351497425931fb9ef5bad0eeb7b0cf8645/examples/Blink/Blink.ino#L17-L57
  FastLED.addLeds<APA102, dataPin, clockPin, RGB>(leds, ledCount);  // BGR ordering is typical
}

void loop() {
  checkButtons();
  checkTimeout();
}

1 Like

Ahh yes I probably did paste it in a template sketch thank you.

Hello -
I have reached the stage of physically testing this hookup and code.
I'm using an Arduino Uno, with the NeoPixel Diffused 8mm Through-Hole LED
With arduino code 20210629_NatAreaMap_ArduinoUno.ino (3.4 KB)

#include <FastLED.h>
// For led chips like WS2812, which have a data line, ground, and power, you just need to define dataPin.
const uint8_t dataPin = 3;

// For led chipsets that are SPI based (four wires - data, clock, ground, and power),
// like the APA102, define both dataPin and clockPin
const uint8_t clockPin = 13;              // 13 is SPI SCK on UNO, use 52 on a MEGA

// Define the array of leds
const uint8_t ledCount = 66;              // How many you have
CRGB leds[ledCount];

// Define the zones on the map
const uint8_t maxLedPerZone = 34;         // this is to make our life easy with fixed size arrays even if it wastes a bit of RAM

struct t_zone {
  const uint8_t   ledIDs[maxLedPerZone];  // where they are in the strip, starting at position 0
  const uint8_t   ledCount;               // how many LEDs are in this area
  const uint32_t  lightingDuration;       // How long the area stays lit in ms
  const uint8_t   buttonPin;              // the pin of the button triggering this zone
  bool            ledsAreOn;              // true if leds are on
  uint32_t        startTime;              // utility for timeout
};

t_zone zones[] = {
  /* leds position in strip            count    period  button    keep as is */
  {{0, 1, 2, 3, 4, 5, 6}              , 7     , 20000,    7,      false, 0},
  {{2, 3, 4, 7, 8, 9, 10}             , 7     , 20000,    6,      false, 0},
  {{4, 5, 6, 10, 11, 12, 13, 60, 61}  , 9     , 20000,    5,      false, 0},
};
const uint8_t zoneCount = sizeof zones / sizeof zones[0];

bool ledIsOnInAnotherZone(uint8_t ledId, uint8_t currentZone)
{
  bool ledIsOn = false;
  for (uint8_t z = 0; z < zoneCount; z++) {
    if ((z != currentZone) && zones[z].ledsAreOn) {
      for (uint8_t i = 0; i < zones[z].ledCount; i++) {
        if (ledId == zones[z].ledIDs[i]) {
          ledIsOn = true;
          break;
        }
      }
    }
  }
  return ledIsOn;
}

void zoneOn(uint8_t zoneID) {
  for (uint8_t i = 0; i < zones[zoneID].ledCount; i++)
    leds[zones[zoneID].ledIDs[i]] = CRGB::White;
  FastLED.show();
  zones[zoneID].startTime = millis();
  zones[zoneID].ledsAreOn = true;
}

void zoneOff(uint8_t zoneID) {
  for (uint8_t i = 0; i < zones[zoneID].ledCount; i++)
    if (!ledIsOnInAnotherZone(zones[zoneID].ledIDs[i], zoneID))   // only turn it off if it does not belong to another zone that is ON
      leds[zones[zoneID].ledIDs[i]] = CRGB::Black;
  FastLED.show();
  zones[zoneID].ledsAreOn = false;
}

void checkButtons() {
  for (uint8_t z = 0; z < zoneCount; z++)
    if ((!zones[z].ledsAreOn) && (digitalRead(zones[z].buttonPin) == LOW))
      zoneOn(z);
}

void checkTimeout() {
  for (uint8_t z = 0; z < zoneCount; z++)
    if (zones[z].ledsAreOn && (millis() - zones[z].startTime > zones[z].lightingDuration))
      zoneOff(z);
}

void setup() {
  // sanity check delay - allows reprogramming if accidently blowing power w/leds
  delay(2000);

  // declare button pins
  for (uint8_t z = 0; z < zoneCount; z++) pinMode(zones[z].buttonPin, INPUT_PULLUP);

  // Define led arrangement, see FastLED examples for strip definition
  // https://github.com/FastLED/FastLED/blob/cfffa1351497425931fb9ef5bad0eeb7b0cf8645/examples/Blink/Blink.ino#L17-L57
  FastLED.addLeds<NEOPIXEL, dataPin, RGB>(leds, ledCount);  // BGR ordering is typical
}

void loop() {
  checkButtons();
  checkTimeout();
}

Power: 5V power source, spit and routed to Aruino and LED. Added the recommended capacitor (1000uF) and resistor (470Ω). Have two buttons hooked up at Pin 5 and 7. LED Data in Pin 3, and only one LED hooked up for now.

After hooking everything, I pushed one of the test buttons hooked up to pin 7 (as listed as the one that triggers LED 0). The light turned on, and stayed on. Same thing happened when hooking up the button to a pin that wouldn't trigger that led # in the sequence (if it was the only button hooked up)..

Question 1: Can you think of anything that I connected wrong here? Or could it be something in the code that isn't causing the light to turn off after 20 seconds?

Question 2: What's the best way to daisy-chain the LED's? Just soldering wires? Are there any quick connect solutions?

Some reference images, sorry if hard to see.



in the code you have this

  FastLED.addLeds<APA102, dataPin, clockPin, RGB>(leds, ledCount);  // BGR ordering is typical

I don't think APA102 is the right type for your WS2812B or SK6812-based LEDs. try
FastLED.addLeds<NEOPIXEL, dataPin, RGB>(leds, ledCount);

the color order might need to be GRB instead of RGB

please post code inline with code tags as it's painful to go download the code and load it in the IDE etc (and does not work on smartphone easily)

1 Like

Get this working, keep it handy and fix it up for each time you have a new hardware to test.

Divide and conquer. If you can't blink one LED, it is pointless to look into why anything more complicated isn't working.

I did not test this. I do hope it is 100 percent within your understanding and we can get this to work.

# include <FastLED.h>

const uint8_t dataPin = 3;
const uint8_t ledCount = 1;

CRGB leds[ledCount];

void setup() {
	Serial.begin(115200);
	Serial.println("Blink!");

//	FastLED.addLeds<APA102, dataPin, clockPin, RGB>(leds, ledCount);  // BGR ordering is typical

    FastLED.addLeds<WS2811, dataPin, GRB>(leds, ledCount);
}

void loop() {

	Serial.println("turn it OFF");
	leds[0] = CRGB::Black;
	FastLED.show();
	
	delay(500);
	
	
	Serial.println("                 then back ON again");
	leds[0] = CRGB::White;
	FastLED.show();
	
	delay(500);
}

You don't need to use th serial monitor, it's just to show the flow. If you do, set the baud thingy to 115200.

EDIT: Scared up a neopixel LED, code blinks it fine.

You could use

 leds[0] =  0;    // CRGB::Black;

and

leds[0] =  0xffffff;    // CRGB::White

in the appropriate places above to eliminate another source of trouble. Both work here.

HTH

a7

this is the key piece @ryurkovich needs to find out.

I've no experience with those LEDs so unsure what type to pick