#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 = 57; // 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
};
/* original zones initial values
t_zone zones[] = {
// leds position in strip count period button keep as is
{{1, 3, 4, 5, 10, 17, 19, 20, 22, 23, 24, 26, 27, 28, 31, 32, 33, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 49, 50, 51, 52, 53, 54, 55} , 34 , 3333, 4, false, 0}, // (S) Floodplains, Swamp Forests
{{2, 6, 10, 11, 12, 15, 18, 19, 21, 25, 30, 36, 38, 46, 53, 54, 56} , 17 , 3333, 5, false, 0}, // (F) Upland Forests
{{7, 8, 9, 13, 14, 16, 20, 29, 34, 35, 43, 48, 51} , 13 , 3333, 6, false, 0}, // (B) Marshes, Fens, Bogs
{{0, 3, 4, 12, 42, 52} , 6 , 3333, 7, false, 0}, // (M) Meadows
{{0} , 1 , 3333, 8, false, 0}, // (A) Alvars
};
*/
t_zone zones[] = {
// leds position in strip count period button keep as is
{{1, 3, 4, 5, 10, }, 5 , 7000, 4, false, 0}, // (S) Floodplains, Swamp Forests
{{2, 6, 10,}, 17 , 7000, 5, false, 0}, // (F) Upland Forests
{{7, 8, 9, 10,}, 13 , 7000, 6, false, 0}, // (B) Marshes, Fens, Bogs
{{0, 3, 4, 9, 10}, 6 , 7000, 7, false, 0}, // (M) Meadows
{{0}, 1 , 7000, 8, false, 0}, // (A) Alvars
};
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) {
Serial.print("LEDs turn ON zone "); Serial.println(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) {
Serial.print("LEDs turn OFF zone "); Serial.println(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)) {
Serial.print("button turn on zone "); Serial.println(z);
zoneOn(z);
}
}
void checkTimeout() {
for (uint8_t z = 0; z < zoneCount; z++)
if (zones[z].ledsAreOn && (millis() - zones[z].startTime > zones[z].lightingDuration)) {
Serial.print("timeout turn off zone "); Serial.println(z);
zoneOff(z);
}
}
void setup() {
Serial.begin(115200);
Serial.println("Hello Museum Thing World!\n");
// 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<WS2811, dataPin, GRB>(leds, ledCount);
for (uint8_t pixel = 0; pixel < ledCount; pixel++)
leds[pixel] = CRGB::DarkBlue;
FastLED.show();
}
void loop() {
checkButtons();
checkTimeout();
}