#include <Adafruit_NeoPixel.h>
#define NUM_LEDS 60
#define DATA_PIN 6
#define BUTTON_PIN 2
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, DATA_PIN, NEO_GRB + NEO_KHZ800);
int effect = 0; // Effet actuel
bool buttonState = false;
bool lastButtonState = false;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;
// Tableau des noms de modes
const char* modeNames[32] = {
"Color Wipe Rouge",
"Rainbow Cycle",
"Theater Chase Bleu",
"Color Wipe Vert",
"Rainbow Simple",
"Theater Chase Rainbow",
"Clignotement Total (Blink Full)",
"Pulse Bleu",
"Scanner K2000",
"Glitter (Etincelles)",
"Twinkle (Scintillement)",
"Feu",
"Stroboscope",
"Confetti",
"Wave",
"Coucher de soleil",
// Modes sophistiqués :
"Color Twirl",
"Meteor Rain",
"Lavalamp",
"Comet Multicolor",
"Noise Wave",
"Juggle",
"Sinelon",
"BPM Pulse",
"Twinkle Random",
"Firework",
"Chase Rainbow",
"Confetti Dir.",
"Pacifica",
"Color Fade Mix",
"Dot Matrix",
"Plasma"
};
// ------- Variables d’animation --------
unsigned long lastUpdate = 0;
int wipeIndex = 0;
int rainbowIndex = 0;
int theaterChaseStep = 0;
int theaterChaseQ = 0;
int theaterChaseJ = 0;
// Blink Full
bool blinkState = false;
unsigned long lastBlinkTime = 0;
// Pulse
int pulseValue = 0;
int pulseDirection = 1;
// Scanner
int scannerPos = 0;
int scannerDir = 1;
unsigned long lastScannerUpdate = 0;
// Glitter
unsigned long lastGlitterUpdate = 0;
// Twinkle
#define NUM_TWINKLE 8
int twinklePos[NUM_TWINKLE];
int twinkleState[NUM_TWINKLE];
int twinkleBrightness[NUM_TWINKLE];
unsigned long lastTwinkleUpdate = 0;
// Variables pour effets avancés (static dans fonctions si possible)
// ---------------- SETUP ----------------
void setup() {
strip.begin();
strip.show();
strip.setBrightness(48);
pinMode(BUTTON_PIN, INPUT_PULLUP);
Serial.begin(9600);
// Initialisation pour Twinkle
for (int i = 0; i < NUM_TWINKLE; i++) {
twinklePos[i] = random(NUM_LEDS);
twinkleState[i] = 0;
twinkleBrightness[i] = random(50, 200);
}
Serial.print("Mode actuel : ");
Serial.println(modeNames[effect]);
}
// ---------------- LOOP ----------------
void loop() {
// Gestion bouton (non-bloquante)
bool reading = !digitalRead(BUTTON_PIN);
if (reading != lastButtonState) lastDebounceTime = millis();
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != buttonState) {
buttonState = reading;
if (buttonState) {
// Flash blanc rapide
for (int i = 0; i < NUM_LEDS; i++) strip.setPixelColor(i, 255, 255, 255);
strip.show();
delay(80);
effect = (effect + 1) % 32;
Serial.print("Mode actuel : ");
Serial.println(modeNames[effect]);
// Réinitialisation index
wipeIndex = rainbowIndex = theaterChaseStep = theaterChaseQ = theaterChaseJ = 0;
blinkState = false;
pulseValue = 0; pulseDirection = 1;
scannerPos = 0; scannerDir = 1;
lastUpdate = lastBlinkTime = lastScannerUpdate = lastGlitterUpdate = lastTwinkleUpdate = millis();
for (int i = 0; i < NUM_TWINKLE; i++) {
twinklePos[i] = random(NUM_LEDS);
twinkleState[i] = 0;
twinkleBrightness[i] = random(50, 200);
}
strip.clear(); strip.show();
}
}
}
lastButtonState = reading;
// ------- Sélecteur de modes -------
switch (effect) {
case 0: colorWipeNonBlocking(strip.Color(255, 0, 0), 30); break;
case 1: rainbowCycleNonBlocking(15); break;
case 2: theaterChaseNonBlocking(strip.Color(0, 0, 255), 80); break;
case 3: colorWipeNonBlocking(strip.Color(0, 255, 0), 30); break;
case 4: rainbowNonBlocking(10); break;
case 5: theaterChaseRainbowNonBlocking(80); break;
case 6: blinkFullNonBlocking(400); break;
case 7: pulseNonBlocking(10); break;
case 8: scannerNonBlocking(10); break;
case 9: glitterNonBlocking(60); break;
case 10: twinkleNonBlocking(25); break;
case 11: fireEffectNonBlocking(25); break;
case 12: strobeEffectNonBlocking(70); break;
case 13: confettiEffectNonBlocking(30); break;
case 14: waveEffectNonBlocking(20); break;
case 15: sunsetEffectNonBlocking(30); break;
// 16 nouveaux effets sophistiqués :
case 16: colorTwirlNonBlocking(18); break;
case 17: meteorRainNonBlocking(24); break;
case 18: lavalampNonBlocking(18); break;
case 19: cometMulticolorNonBlocking(15); break;
case 20: noiseWaveNonBlocking(20); break;
case 21: juggleNonBlocking(20); break;
case 22: sinelonNonBlocking(18); break;
case 23: bpmPulseNonBlocking(20); break;
case 24: twinkleRandomNonBlocking(18); break;
case 25: fireworkNonBlocking(15); break;
case 26: chaseRainbowNonBlocking(14); break;
case 27: confettiDirNonBlocking(18); break;
case 28: pacificaNonBlocking(22); break;
case 29: colorFadeMixNonBlocking(18); break;
case 30: dotMatrixNonBlocking(30); break;
case 31: plasmaNonBlocking(22); break;
}
}
/* ========== MODES CLASSIQUES ========== */
void colorWipeNonBlocking(uint32_t color, uint16_t wait) {
if (millis() - lastUpdate > wait) {
lastUpdate = millis();
strip.setPixelColor(wipeIndex, color);
strip.show();
wipeIndex++;
if (wipeIndex >= strip.numPixels()) {
wipeIndex = 0;
strip.clear();
}
}
}
void rainbowCycleNonBlocking(uint16_t wait) {
if (millis() - lastUpdate > wait) {
lastUpdate = millis();
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + rainbowIndex) & 255));
}
strip.show();
rainbowIndex++;
if (rainbowIndex >= 256 * 5) rainbowIndex = 0;
}
}
void theaterChaseNonBlocking(uint32_t color, uint16_t wait) {
if (millis() - lastUpdate > wait) {
lastUpdate = millis();
for (int i = 0; i < strip.numPixels(); i++) strip.setPixelColor(i, 0);
for (int i = theaterChaseQ; i < strip.numPixels(); i += 3) strip.setPixelColor(i, color);
strip.show();
theaterChaseQ++;
if (theaterChaseQ >= 3) theaterChaseQ = 0;
}
}
void rainbowNonBlocking(uint16_t wait) {
if (millis() - lastUpdate > wait) {
lastUpdate = millis();
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel((i + rainbowIndex) & 255));
}
strip.show();
rainbowIndex++;
if (rainbowIndex >= 256) rainbowIndex = 0;
}
}
void theaterChaseRainbowNonBlocking(uint16_t wait) {
if (millis() - lastUpdate > wait) {
lastUpdate = millis();
for (int i = 0; i < strip.numPixels(); i++) strip.setPixelColor(i, 0);
for (int i = theaterChaseQ; i < strip.numPixels(); i += 3) {
strip.setPixelColor(i, Wheel((i + theaterChaseJ) % 255));
}
strip.show();
theaterChaseQ++;
if (theaterChaseQ >= 3) {
theaterChaseQ = 0;
theaterChaseJ++;
if (theaterChaseJ >= 256) theaterChaseJ = 0;
}
}
}
void blinkFullNonBlocking(uint16_t interval) {
if (millis() - lastBlinkTime > interval) {
lastBlinkTime = millis();
blinkState = !blinkState;
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, blinkState ? strip.Color(255,255,255) : 0);
}
strip.show();
}
}
void pulseNonBlocking(uint16_t speed) {
pulseValue += pulseDirection * speed;
if (pulseValue > 255) { pulseValue = 255; pulseDirection = -1; }
if (pulseValue < 0) { pulseValue = 0; pulseDirection = 1; }
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(0, 0, pulseValue));
}
strip.show();
delay(10);
}
void scannerNonBlocking(uint16_t wait) {
if (millis() - lastScannerUpdate > wait) {
lastScannerUpdate = millis();
strip.clear();
strip.setPixelColor(scannerPos, strip.Color(255, 0, 0));
if (scannerPos > 0) strip.setPixelColor(scannerPos - 1, strip.Color(80, 0, 0));
if (scannerPos < strip.numPixels()-1) strip.setPixelColor(scannerPos + 1, strip.Color(80, 0, 0));
strip.show();
scannerPos += scannerDir;
if (scannerPos == strip.numPixels()-1 || scannerPos == 0) scannerDir = -scannerDir;
}
}
void glitterNonBlocking(uint16_t wait) {
if (millis() - lastGlitterUpdate > wait) {
lastGlitterUpdate = millis();
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(0,0,40));
}
for (int i = 0; i < 8; i++) {
int pix = random(strip.numPixels());
strip.setPixelColor(pix, strip.Color(255,255,255));
}
strip.show();
}
}
void twinkleNonBlocking(uint16_t wait) {
if (millis() - lastTwinkleUpdate > wait) {
lastTwinkleUpdate = millis();
for (int i = 0; i < strip.numPixels(); i++) strip.setPixelColor(i, 0);
for (int i = 0; i < NUM_TWINKLE; i++) {
if (twinkleState[i] == 0 && random(100) < 5) twinkleState[i] = 1;
if (twinkleState[i] == 1) {
twinkleBrightness[i] += 12;
if (twinkleBrightness[i] >= 255) { twinkleBrightness[i] = 255; twinkleState[i] = 2; }
} else if (twinkleState[i] == 2) {
twinkleBrightness[i] -= 8;
if (twinkleBrightness[i] <= 0) {
twinkleBrightness[i] = 0;
twinkleState[i] = 0;
twinklePos[i] = random(strip.numPixels());
}
}
strip.setPixelColor(twinklePos[i], strip.Color(twinkleBrightness[i], twinkleBrightness[i], 255));
}
strip.show();
}
}
void fireEffectNonBlocking(uint16_t wait) {
static byte heat[NUM_LEDS];
int COOLING = 55;
int SPARKING = 120;
if (millis() - lastUpdate > wait) {
lastUpdate = millis();
for (int i = 0; i < NUM_LEDS; i++) {
heat[i] = qsub8(heat[i], random(0, ((COOLING * 10) / NUM_LEDS) + 2));
}
for (int k = NUM_LEDS - 1; k >= 2; k--) {
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2]) / 3;
}
if (random(255) < SPARKING) {
int y = random(7);
heat[y] = qadd8(heat[y], random(160, 255));
}
for (int j = 0; j < NUM_LEDS; j++) {
strip.setPixelColor(j, HeatColor(heat[j]));
}
strip.show();
}
}
uint32_t HeatColor(uint8_t temperature) {
uint8_t t192 = scale8_video(temperature, 191);
uint8_t heatramp = t192 & 0x3F;
heatramp <<= 2;
if (t192 > 0x80)
return strip.Color(255, 255, heatramp);
else if (t192 > 0x40)
return strip.Color(255, heatramp, 0);
else
return strip.Color(heatramp, 0, 0);
}
uint8_t qsub8(uint8_t i, uint8_t j) { return (i > j) ? i - j : 0; }
uint8_t qadd8(uint8_t i, uint8_t j) { return (i + j > 255) ? 255 : i + j; }
uint8_t scale8_video(uint8_t i, uint8_t scale) { return ((uint16_t)i * (uint16_t)scale) >> 8; }
void strobeEffectNonBlocking(uint16_t interval) {
static bool strobeState = false;
static unsigned long lastStrobe = 0;
if (millis() - lastStrobe > interval) {
lastStrobe = millis();
strobeState = !strobeState;
uint32_t color = strobeState ? strip.Color(255, 255, 255) : strip.Color(0,0,0);
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, color);
}
strip.show();
}
}
void confettiEffectNonBlocking(uint16_t wait) {
static unsigned long lastConfetti = 0;
if (millis() - lastConfetti > wait) {
lastConfetti = millis();
for (int i = 0; i < strip.numPixels(); i++) {
uint32_t c = strip.getPixelColor(i);
strip.setPixelColor(i, ((c >> 16 & 0xFF) * 7) / 8, ((c >> 8 & 0xFF) * 7) / 8, ((c & 0xFF) * 7) / 8);
}
int pos = random(strip.numPixels());
strip.setPixelColor(pos, Wheel(random(256)));
strip.show();
}
}
void waveEffectNonBlocking(uint16_t wait) {
static unsigned long lastWave = 0;
static float phase = 0.0;
if (millis() - lastWave > wait) {
lastWave = millis();
phase += 0.20;
for (int i = 0; i < strip.numPixels(); i++) {
float value = (sin(i * 0.15 + phase) + 1) * 127.5;
strip.setPixelColor(i, strip.Color(0, (int)value, 255 - (int)value));
}
strip.show();
}
}
void sunsetEffectNonBlocking(uint16_t wait) {
static unsigned long lastSunset = 0;
static int sunsetIndex = 0;
static int direction = 1;
if (millis() - lastSunset > wait) {
lastSunset = millis();
sunsetIndex += direction;
if (sunsetIndex > 255) {sunsetIndex = 255; direction = -1;}
if (sunsetIndex < 0) {sunsetIndex = 0; direction = 1;}
for (int i = 0; i < strip.numPixels(); i++) {
int r = map(sunsetIndex, 0, 255, 30, 255);
int g = map(sunsetIndex, 0, 255, 60, 120);
int b = map(sunsetIndex, 0, 255, 150, 20);
strip.setPixelColor(i, strip.Color(r, g, b));
}
strip.show();
}
}
/* ========== MODES SOPHISTIQUÉS ========== */
// 16. Color Twirl
void colorTwirlNonBlocking(uint16_t wait) {
static unsigned long lastTwirl = 0;
static int twirlIndex = 0;
if (millis() - lastTwirl > wait) {
lastTwirl = millis();
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, Wheel(((i * 8) + twirlIndex) & 255));
}
strip.show();
twirlIndex++;
if (twirlIndex > 255) twirlIndex = 0;
}
}
// 17. Meteor Rain
void meteorRainNonBlocking(uint16_t wait) {
static unsigned long lastMeteor = 0;
static int pos = 0;
static int dir = 1;
static uint8_t trail[NUM_LEDS] = {0};
if (millis() - lastMeteor > wait) {
lastMeteor = millis();
for (int i = 0; i < strip.numPixels(); i++) {
if (trail[i] > 8) trail[i] -= 8; else trail[i] = 0;
uint32_t col = strip.Color(trail[i], 0, trail[i]);
strip.setPixelColor(i, col);
}
trail[pos] = 255;
strip.show();
pos += dir;
if (pos >= strip.numPixels() || pos < 0) {
dir = -dir; pos += dir;
}
}
}
// 18. Lavalamp (3 blobs colorés)
void lavalampNonBlocking(uint16_t wait) {
static unsigned long lastLava = 0;
static float phase = 0.0;
if (millis() - lastLava > wait) {
lastLava = millis();
phase += 0.03;
for (int i = 0; i < strip.numPixels(); i++) {
float val =
120 * (sin(phase + i*0.10)) +
80 * (sin(phase*1.7 - i*0.06)) +
50 * (sin(phase*0.8 + i*0.17));
int red = constrain((int)(127 + val), 0, 255);
int blue = constrain((int)(127 - val/1.4), 0, 255);
strip.setPixelColor(i, strip.Color(red, 50, blue));
}
strip.show();
}
}
// 19. Comet Multicolor
void cometMulticolorNonBlocking(uint16_t wait) {
static unsigned long lastComet = 0;
static int head = 0;
static int dir = 1;
if (millis() - lastComet > wait) {
lastComet = millis();
for (int i = 0; i < strip.numPixels(); i++) {
int dist = abs(head - i);
int fade = max(255 - dist * 60, 0);
strip.setPixelColor(i, Wheel((head * 8 + i * 8) & 255));
strip.setPixelColor(i, strip.Color(
(uint8_t)(((strip.getPixelColor(i) >> 16) & 0xFF) * fade / 255),
(uint8_t)(((strip.getPixelColor(i) >> 8) & 0xFF) * fade / 255),
(uint8_t)((strip.getPixelColor(i) & 0xFF) * fade / 255)
));
}
strip.show();
head += dir;
if (head == strip.numPixels() - 1 || head == 0) dir = -dir;
}
}
// 20. Noise Wave (pseudo bruit)
void noiseWaveNonBlocking(uint16_t wait) {
static unsigned long lastNoise = 0;
static float phase = 0.0;
if (millis() - lastNoise > wait) {
lastNoise = millis();
phase += 0.08;
for (int i = 0; i < strip.numPixels(); i++) {
int v = 128 + 127 * sin(i * 0.22 + phase * (0.7 + sin(i*0.12)/3.0));
strip.setPixelColor(i, strip.Color(v, 128-v/2, 255-v));
}
strip.show();
}
}
// 21. Juggle (4 points qui se croisent)
void juggleNonBlocking(uint16_t wait) {
static unsigned long lastJuggle = 0;
static float theta = 0;
int dots = 4;
if (millis() - lastJuggle > wait) {
lastJuggle = millis();
strip.clear();
for (int d = 0; d < dots; d++) {
int pos = (int)(strip.numPixels() / 2 * (1.0 + sin(theta + d * 2 * 3.1416 / dots)));
strip.setPixelColor(pos, Wheel((d * 256 / dots) & 255));
}
strip.show();
theta += 0.18;
if (theta > 6.2832) theta -= 6.2832;
}
}
// 22. Sinelon (pointe sinusoïdale)
void sinelonNonBlocking(uint16_t wait) {
static unsigned long lastSin = 0;
static int pos = 0;
static int dir = 1;
static uint32_t fade[NUM_LEDS] = {0};
if (millis() - lastSin > wait) {
lastSin = millis();
for (int i = 0; i < strip.numPixels(); i++) {
fade[i] = (fade[i] > 30) ? fade[i] - 30 : 0;
strip.setPixelColor(i, strip.Color(fade[i], 0, fade[i]));
}
fade[pos] = 255;
strip.show();
pos += dir;
if (pos == strip.numPixels() - 1 || pos == 0) dir = -dir;
}
}
// 23. BPM Pulse
void bpmPulseNonBlocking(uint16_t wait) {
static unsigned long lastPulse = 0;
static int beat = 0;
const int bpm = 120;
float t = millis() / 1000.0;
int p = (int)(128 + 127 * sin(2 * 3.1416 * bpm / 60.0 * t));
if (millis() - lastPulse > wait) {
lastPulse = millis();
for (int i = 0; i < strip.numPixels(); i++) {
strip.setPixelColor(i, strip.Color(p, 0, 255-p));
}
strip.show();
}
}
// 24. Twinkle Random
void twinkleRandomNonBlocking(uint16_t wait) {
static unsigned long lastTwinkle = 0;
if (millis() - lastTwinkle > wait) {
lastTwinkle = millis();
for (int i = 0; i < strip.numPixels(); i++) {
if (random(100) < 2) {
strip.setPixelColor(i, Wheel(random(256)));
} else {
uint32_t c = strip.getPixelColor(i);
uint8_t r = (c >> 16) & 0xFF;
uint8_t g = (c >> 8) & 0xFF;
uint8_t b = c & 0xFF;
r = (r > 2) ? r - 2 : 0;
g = (g > 2) ? g - 2 : 0;
b = (b > 2) ? b - 2 : 0;
strip.setPixelColor(i, strip.Color(r, g, b));
}
}
strip.show();
}
}
// 25. Firework (explosion centrale)
void fireworkNonBlocking(uint16_t wait) {
static unsigned long lastFirework = 0;
static int radius = 0;
static int center = NUM_LEDS / 2;
static bool explose = true;
static uint32_t col = 0;
if (explose) { col = Wheel(random(256)); explose = false; radius = 0; }
if (millis() - lastFirework > wait) {
lastFirework = millis();
strip.clear();
for (int i = -radius; i <= radius; i++) {
int pos = center + i;
if (pos >= 0 && pos < strip.numPixels()) strip.setPixelColor(pos, col);
}
strip.show();
radius++;
if (radius > NUM_LEDS / 2) { explose = true; }
}
}
// 26. Chase Rainbow (serpent)
void chaseRainbowNonBlocking(uint16_t wait) {
static unsigned long lastChase = 0;
static int chaseIndex = 0;
if (millis() - lastChase > wait) {
lastChase = millis();
for (int i = 0; i < strip.numPixels(); i++) {
int idx = (i + chaseIndex) % strip.numPixels();
strip.setPixelColor(idx, Wheel((i * 256 / strip.numPixels()) & 255));
}
strip.show();
chaseIndex++;
if (chaseIndex > strip.numPixels()) chaseIndex = 0;
}
}
// 27. Confetti Directionnel
void confettiDirNonBlocking(uint16_t wait) {
static unsigned long lastConfetti = 0;
static int offset = 0;
if (millis() - lastConfetti > wait) {
lastConfetti = millis();
for (int i = 0; i < strip.numPixels(); i++) {
uint32_t c = strip.getPixelColor(i);
strip.setPixelColor(i, ((c >> 16 & 0xFF) * 7) / 8, ((c >> 8 & 0xFF) * 7) / 8, ((c & 0xFF) * 7) / 8);
}
int pos = (offset++) % strip.numPixels();
strip.setPixelColor(pos, Wheel(random(256)));
strip.show();
}
}
// 28. Pacifica (ondes bleues)
void pacificaNonBlocking(uint16_t wait) {
static unsigned long lastPacifica = 0;
static float phase = 0.0;
if (millis() - lastPacifica > wait) {
lastPacifica = millis();
phase += 0.07;
for (int i = 0; i < strip.numPixels(); i++) {
int c = 100 + 55 * sin(phase + i * 0.13) + 80 * sin(phase * 0.9 + i * 0.07);
int r = 0, g = 0, b = constrain(c, 0, 255);
strip.setPixelColor(i, strip.Color(r, g, b));
}
strip.show();
}
}
// 29. Color Fade Mix (dégradé dynamique)
void colorFadeMixNonBlocking(uint16_t wait) {
static unsigned long lastFade = 0;
static int mix = 0;
static int dir = 1;
uint32_t c1 = strip.Color(0,255,70);
uint32_t c2 = strip.Color(255,0,50);
if (millis() - lastFade > wait) {
lastFade = millis();
for (int i = 0; i < strip.numPixels(); i++) {
uint8_t r = ((c1 >> 16 & 0xFF) * (255-mix) + (c2 >> 16 & 0xFF) * mix) / 255;
uint8_t g = ((c1 >> 8 & 0xFF) * (255-mix) + (c2 >> 8 & 0xFF) * mix) / 255;
uint8_t b = ((c1 & 0xFF) * (255-mix) + (c2 & 0xFF) * mix) / 255;
strip.setPixelColor(i, strip.Color(r,g,b));
}
strip.show();
mix += dir * 2;
if (mix >= 255 || mix <= 0) dir = -dir;
}
}
// 30. Dot Matrix (points qui apparaissent/disparaissent)
void dotMatrixNonBlocking(uint16_t wait) {
static unsigned long lastDot = 0;
static bool state = false;
if (millis() - lastDot > wait) {
lastDot = millis();
state = !state;
for (int i = 0; i < strip.numPixels(); i++) {
if ((i % 4 == 0) ^ state) strip.setPixelColor(i, strip.Color(255,255,255));
else strip.setPixelColor(i, 0);
}
strip.show();
}
}
// 31. Plasma (couleurs "organiques")
void plasmaNonBlocking(uint16_t wait) {
static unsigned long lastPlasma = 0;
static float phase = 0.0;
if (millis() - lastPlasma > wait) {
lastPlasma = millis();
phase += 0.13;
for (int i = 0; i < strip.numPixels(); i++) {
float v = sin(i * 0.18 + phase) + sin(i * 0.08 + phase * 1.8) + sin(i * 0.12 + phase * 2.3);
int col = 127 + 90 * v / 3.0;
strip.setPixelColor(i, Wheel(constrain(col, 0, 255)));
}
strip.show();
}
}
/* ========== UTILITAIRES ========== */
uint32_t Wheel(byte WheelPos) {
WheelPos = 255 - WheelPos;
if (WheelPos < 85) return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
if (WheelPos < 170) {
WheelPos -= 85;
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
}
WheelPos -= 170;
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}