My sketch is working, if not potentially sloppy and redundant, so I thought I'd throw it up here and see about recommendations to improve it.
The Project: To upgrade my holiday display by adding addressable LEDs to my christmas tree and village, and controlling it via Serial input (eventually by way of Bluetooth).
The Code:
#include <Adafruit_NeoPixel.h>
#include <SoftwareSerial.h>
SoftwareSerial BT(0, 1);
#define villagePIN 6
#define treePIN 5
#define villageStripLength 9
#define treeStripLength 88
String mode = "rainbowCycle";
Adafruit_NeoPixel treeStrip = Adafruit_NeoPixel(treeStripLength, treePIN, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel villageStrip = Adafruit_NeoPixel(villageStripLength, villagePIN, NEO_GRB + NEO_KHZ800);
void setup() {
randomSeed(analogRead(0));
Serial.begin(9600);
BT.begin(9600);
villageStrip.begin();
villageStrip.show(); // Initiallizes all pixels to 'off'
treeStrip.begin();
treeStrip.show(); // Initialize all pixels to 'off'
flicker(255, 50, 0);
rainbowCycle(20);
}
void loop() {
serialEvent();
}
void rainbowCycle(uint8_t wait) {
uint16_t i, j;
while (mode == "rainbowCycle") { //loops forever
for (j = 0; j < -1; j++) { // 5 cycles of all colors on wheel
for (i = 0; i < treeStrip.numPixels(); i++) {
treeStrip.setPixelColor(i, Wheel(((i * 256 / treeStrip.numPixels()) + j) & 255));
}
treeStrip.setBrightness(128);
treeStrip.show();
serialEvent();
delay(wait);
}
}
}
// Input a value 0 to 255 to get a color value.
// The colours are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if (WheelPos < 85) {
return treeStrip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
}
if (WheelPos < 170) {
WheelPos -= 85;
return treeStrip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
WheelPos -= 170;
return treeStrip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}
void flicker(uint8_t r, uint8_t g, uint8_t b) {
for (uint8_t i = 0; i < villageStripLength; i++) {
uint8_t brightness = (random(2, 4) * 2) * 25.5;
uint8_t rr = (r * brightness) / 255;
uint8_t gg = (g * brightness) / 255;
uint8_t bb = (b * brightness) / 255;
villageStrip.setPixelColor(i, rr, gg, bb);
delay(0);
}
villageStrip.show();
}
void colorStripes(uint32_t c1, uint32_t c2, uint8_t s, uint8_t w, uint8_t d) {
int L;
int numP = treeStrip.numPixels();
while (mode == "stripes") {
for (int j = 0; j < (w * treeStripLength); j++) {
for (int i = 0; i < treeStrip.numPixels(); i++) {
int mod = ((i + j) % (w * 2));
L = treeStrip.numPixels() - i - 1;
if ( mod < w) {
if (mod == 4 || mod == 0) {
treeStrip.setPixelColor(i, splitColor(c1, 'r')*.25, splitColor(c1, 'g')*.25, splitColor(c1, 'b')*.25);
} else {
treeStrip.setPixelColor(i, splitColor(c1, 'r')*.5, splitColor(c1, 'g')*.5, splitColor(c1, 'b')*.5);
}
} else {
if (mod == 5 || mod == 9) {
treeStrip.setPixelColor(i, splitColor(c1, 'r')*.25, splitColor(c1, 'g')*.25, splitColor(c1, 'b')*.25);
} else {
treeStrip.setPixelColor(i, splitColor(c2, 'r')*.5, splitColor(c2, 'g')*.5, splitColor(c2, 'b')*.5);
}
}
treeStrip.show();
delay(d);
serialEvent();
}
}
}
}
/*** splitColor() - Receive a uint32_t value, and spread into bits. */
uint8_t splitColor ( uint32_t c, char value )
{
switch ( value ) {
case 'r': return (uint8_t)(c >> 16);
case 'g': return (uint8_t)(c >> 8);
case 'b': return (uint8_t)(c >> 0);
default: return 0;
}
}
void solid(uint32_t c1) {
while (mode == "solid") {
for (int i = 0; i < treeStripLength; i++) {
treeStrip.setPixelColor(i, c1);
}
treeStrip.setBrightness(100);
treeStrip.show();
serialEvent();
}
}
void starSparkle(uint32_t c1, uint32_t c2) {
while (mode == "sparkles") {
treeStrip.setBrightness(0);
int rp = random((1, treeStripLength) - 1);
int rc = random(1, 3);
for (int i = 255; i > -10; i = i - 5) {
if (rc == 1) {
treeStrip.setPixelColor(rp, c1);
} else if (rc == 2) {
treeStrip.setPixelColor(rp, c2);
}
treeStrip.setBrightness(i);
treeStrip.show();
serialEvent();
}
}
}
void serialEvent() {
if (Serial.available() > 0) {
treeStrip.begin();
String newMode = Serial.readString();
newMode.trim();
if (newMode == "default") {
} else if (newMode == "candyCane") {
mode = "stripes";
colorStripes(treeStrip.Color(255, 0, 0), treeStrip.Color(255, 255, 255), 2, 5, 0);
} else if (newMode == "hanukkah") {
mode = "stripes";
colorStripes(treeStrip.Color(0, 0, 255), treeStrip.Color(255, 255, 255), 2, 5, 0);
} else if (newMode == "redAndGreen") {
mode = "stripes";
colorStripes(treeStrip.Color(255, 0, 0), treeStrip.Color(0, 255, 0), 2, 5, 0);
} else if (newMode == "silverAndGold") {
mode = "stripes";
colorStripes(treeStrip.Color(192, 192, 192), treeStrip.Color(255, 215, 0), 2, 5, 0);
} else if (newMode == "rainbowCycle") {
mode = "rainbowCycle";
rainbowCycle(20);
} else if (newMode == "sparkles") {
mode = "sparkles";
starSparkle(treeStrip.Color(255, 255, 255), treeStrip.Color(0, 191, 255));
} else if (newMode == "red") {
mode = "solid";
solid(treeStrip.Color(255, 0, 0));
} else if (newMode == "green") {
mode = "solid";
solid(treeStrip.Color(0, 255, 0));
} else if (newMode == "blue") {
mode = "solid";
solid(treeStrip.Color(0, 0, 255));
} else if (newMode == "orange") {
mode = "solid";
solid(treeStrip.Color(255, 50, 0));
} else if (newMode == "yellow") {
mode = "solid";
solid(treeStrip.Color(255, 100, 0));
} else if (newMode == "purple") {
mode = "solid";
solid(treeStrip.Color(201, 0, 158));
}
}
}
One little annoyance I see is that I need to put in loops where they don't seem necessary. For example, if I don't loop through the solid function instead of just setting all the pixels and leaving them, the program defaults back to the rainbowCycle function, as if it never stopped running. It's not a huge deal, but I'd like to keep things as svelte as possible.
Of course, I'm completely open to suggestions or ideas to make this better. I'm coupling it with an Android app that sends the serial commands, but until that's finished, testing is just being done via the Serial console.