#include <FastLED.h>
#include <AsyncTimer.h>
// #include <DmxSimple.h>
// #define DMXPIN 3
//const int numLights = 3;
#define LED_PIN3 3
#define NUM_LEDS 14
#define LEDS_LEFT 5
#define LEDS_RIGHT 9
CRGB leds[NUM_LEDS * 3 + 1];
#define HUE_PIN A0
#define SPEED_PIN A1
#define BRIGHTNESS_PIN A2
#define SCALE_PIN A3
#define BRIGHTNESS 100
uint8_t maxBrightness = BRIGHTNESS;
uint8_t currentBrightness = maxBrightness;
float brightnessMultiplier = currentBrightness * 0.01;
uint16_t xPosition;
uint8_t starIntensity[NUM_LEDS];
uint8_t starIncreasing[NUM_LEDS];
uint8_t tailLength = 6;
uint8_t currentPulseStep = 0;
bool pulseActive = false;
// Define a palette.
DEFINE_GRADIENT_PALETTE(NorthernLightsPalette) {
0, 0, 207, 82,
62, 3, 46, 62,
143, 25, 100, 106,
192, 0, 198, 144,
255, 0, 223, 150
};
DEFINE_GRADIENT_PALETTE(WarmNorthernLightsPalette) {
0, 207, 34, 44,
61, 233, 160, 58,
130, 219, 61, 49,
187, 233, 160, 58,
255, 26, 26, 26
};
CRGBPalette16 currentPalette = CRGBPalette16(NorthernLightsPalette);
CRGBPalette16 warmPalette = CRGBPalette16(WarmNorthernLightsPalette);
enum State { STARS,
PULSE,
NOISE
};
State currentState = NOISE;
State targetState = NOISE;
uint16_t caseEffectsDuration = 8000;
bool effectStarted = false;
bool transitionInProgress = false;
AsyncTimer t;
void setup() {
Serial.begin(9600);
//DmxSimple.usePin(DMXPIN);
//DmxSimple.maxChannel(NUM_LEDS * 3);
FastLED.addLeds<WS2811, LED_PIN3, GRB>(leds, NUM_LEDS * 3 +1);
/* --- INITIALIZE POTENTIOMETERS --- */
pinMode(HUE_PIN, OUTPUT);
pinMode(SPEED_PIN, OUTPUT);
pinMode(BRIGHTNESS_PIN, OUTPUT);
pinMode(SCALE_PIN, OUTPUT);
memset(starIntensity, 0, NUM_LEDS);
memset(starIncreasing, false, NUM_LEDS);
}
void loop() {
/* --- READ POTENTIOMETERS --- */
int potValueHue = map(analogRead(HUE_PIN), 0, 1023, 0, 255);
int potValueSpeed = map(analogRead(SPEED_PIN), 0, 1023, 10, 100);
int potValueScale = map(analogRead(SCALE_PIN), 0, 1023, 1, 50);
if (currentState == NOISE && transitionInProgress == false) {
maxBrightness = map(analogRead(BRIGHTNESS_PIN), 0, 1023, 0, BRIGHTNESS);
currentBrightness = maxBrightness;
brightnessMultiplier = currentBrightness * 0.01;
}
t.handle();
if (currentState != targetState && transitionInProgress) {
EVERY_N_MILLISECONDS(40) {
brightnessMultiplier = currentBrightness * 0.01;
currentBrightness--;
if (currentBrightness <= 0) {
currentState = targetState;
currentBrightness = 0;
}
}
}
if (currentState == targetState && transitionInProgress) {
EVERY_N_MILLISECONDS(40) {
brightnessMultiplier = currentBrightness * 0.01;
currentBrightness++;
if (currentBrightness >= maxBrightness) {
currentBrightness = maxBrightness;
transitionInProgress = false;
}
}
}
switch (currentState) {
case STARS:
// Stars effect
EVERY_N_MILLISECONDS(20) {
addRandomStars(potValueSpeed * 10);
}
if (transitionInProgress == false && effectStarted == true) {
effectStarted = false;
t.setTimeout(resetTransition, caseEffectsDuration);
}
break;
case PULSE:
EVERY_N_SECONDS(2) {
startPulse();
}
EVERY_N_MILLISECONDS(50) {
// Pulse effect
if (pulseActive) {
updatePulse();
} else {
for (int i = 0; i <= NUM_LEDS; i++) {
SetDMXLight(i, 0, 0, 0);
}
}
}
if (transitionInProgress == false && effectStarted == true) {
effectStarted = false;
t.setTimeout(resetTransition, caseEffectsDuration);
}
break;
case NOISE:
// Noise effect code
EVERY_N_SECONDS(10) {
if (!transitionInProgress) {
uint8_t rNumber = random8();
if (rNumber <= 50) {
Serial.println("STARS");
currentState = STARS;
effectStarted = true;
} else if (rNumber > 50 && rNumber < 100) {
Serial.println("PULSE");
targetState = PULSE;
transitionInProgress = true;
effectStarted = true;
}
}
}
EVERY_N_MILLISECONDS(10) {
addNoise(potValueHue, potValueScale);
xPosition += potValueSpeed * 0.1;
}
break;
}
FastLED.show();
}
void startPulse() {
currentPulseStep = 0;
pulseActive = true;
}
void updatePulse() {
for (int i = 0; i < NUM_LEDS; i++) {
SetDMXLight(i, 0, 0, 0);
}
int leftStart = 0;
int leftEnd = LEDS_LEFT - 1;
int rightStart = LEDS_LEFT;
int rightEnd = NUM_LEDS - 1;
int rightPulsePosition = rightEnd - currentPulseStep;
for (int i = 0; i < tailLength; i++) {
int pos = rightPulsePosition + i;
uint8_t pulseBrightness = 255 - (i * (255 / tailLength));
if (pos >= rightStart && pos <= rightEnd) {
SetDMXLight(pos, pulseBrightness, pulseBrightness, pulseBrightness);
}
int mirrorStartRight = rightStart;
int mirrorEndRight = rightStart + LEDS_LEFT - 1;
if (pos >= mirrorStartRight && pos <= mirrorEndRight) {
int leftPos = leftStart + (mirrorEndRight - pos);
if (leftPos >= leftStart && leftPos <= leftEnd) {
SetDMXLight(leftPos, pulseBrightness, pulseBrightness, pulseBrightness);
}
}
}
currentPulseStep++;
if (rightPulsePosition + tailLength - 1 < rightStart) {
pulseActive = false;
}
}
void addNoise(int hue, int scale) {
uint8_t blendFactor = hue;
//uint8_t blendFactor = inoise8(millis() / 10); // Smoothly changing blend factor
for (int i = 0; i <= NUM_LEDS; i++) {
if (i < LEDS_LEFT) {
uint8_t noise = inoise8(i * scale - xPosition, 0, i * scale - xPosition);
CRGB color1 = ColorFromPalette(currentPalette, noise);
CRGB color2 = ColorFromPalette(warmPalette, noise);
CRGB blendedColor = blend(color1, color2, blendFactor);
SetDMXLight(i, blendedColor.r, blendedColor.g, blendedColor.b);
} else {
uint8_t noise = inoise8(i * scale + xPosition, 0, i * scale + xPosition);
CRGB color1 = ColorFromPalette(currentPalette, noise);
CRGB color2 = ColorFromPalette(warmPalette, noise);
CRGB blendedColor = blend(color1, color2, blendFactor);
SetDMXLight(i, blendedColor.r, blendedColor.g, blendedColor.b);
}
}
}
void addRandomStars(int speed) {
for (int i = 0; i < NUM_LEDS; i++) {
if (random16() < speed && starIntensity[i] == 0) {
starIntensity[i] = 1;
starIncreasing[i] = true;
}
if (starIntensity[i] > 0) {
if (starIncreasing[i]) {
if (starIntensity[i] < 245) {
starIntensity[i] += 10;
} else {
starIntensity[i] = 255;
starIncreasing[i] = false;
}
} else {
if (starIntensity[i] > 10) {
starIntensity[i] -= 10;
} else {
starIntensity[i] = 0;
SetDMXLight(i, 0, 0, 0);
}
// Update the LED color
if (starIntensity[i] > 0) {
SetDMXLight(i, starIntensity[i], starIntensity[i], starIntensity[i]);
}
}
}
}
}
void resetTransition() {
transitionInProgress = true;
targetState = NOISE;
}
void SetDMXLight(int lightIndex, uint8_t r, uint8_t g, uint8_t b) {
int baseChannel = lightIndex * 3 + 1;
leds[baseChannel + 0].r = r * brightnessMultiplier;
leds[baseChannel + 1].g = g * brightnessMultiplier;
leds[baseChannel + 2].b = b * brightnessMultiplier;
/* DmxSimple.write(baseChannel, r);
DmxSimple.write(baseChannel + 1, g);
DmxSimple.write(baseChannel + 2, b); */
}