#include "FastLED.h"
// --- Configuration ---
#define DATA_PIN 2
// #define BRIGHTNESS_PIN A1 // Removed A1 brightness pin
#define LED_TYPE WS2812
#define COLOR_ORDER RGB
#define NUM_LEDS 75
#define VOLTS 5
#define MASTER_BRIGHTNESS 200 // Fixed brightness for standalone example
// #define MIN_BRIGHTNESS 200 // Removed minimum brightness
// --- Meteor Shower Constants ---
#define METEOR_INITIAL_LENGTH_FRAMES 280
#define METEOR_MEDIUM_LENGTH_FRAMES 500
#define METEOR_RANDOM_PICK_START_FRAMES 600
#define METEOR_RANDOM_PICK_END_FRAMES 790
#define METEOR_RANDOM_LENGTH_START_FRAMES 790
#define METEOR_RANDOM_LENGTH_END_FRAMES 1090
#define METEOR_FULL_CYCLE_FRAMES 1180
#define METEOR_DELAY 30 // Delay between meteor steps
// --- Global Variables ---
CRGB leds[NUM_LEDS]; // LED strip array
byte ledsX[NUM_LEDS][3]; // Used to store previous LED states for trailing effect
uint8_t hue = 0; // Hue for the meteor head
uint16_t timeframe = 0; // Tracks frames for time-based meteor behavior
byte idex = 0; // Current index/position of the meteor head
byte colorTIP = 0; // Controls the color of the meteor head
byte meteorLENGTH; // Length of the meteor tail
boolean RAINBOWs = false; // Flag for rainbow head color
boolean RANDOMpick = false; // Flag for random head position
byte loopCount = 1; // Tracks full cycles of the meteor pattern
// int potValA; // Removed potentiometer value
// uint8_t brightnessa; // Removed dynamic brightness variable
// int MASTER_BRIGHTNESS_INIT = MASTER_BRIGHTNESS; // Removed initial brightness variable
// --- Function Declarations ---
void meteorShower();
byte adjacent_ccw(byte i);
void showStrip();
void setPixel(int Pixel, byte red, byte green, byte blue);
void setAll(byte red, byte green, byte blue); // FIXED: Added 'byte' keyword for 'blue'
// --- Setup Function ---
void setup() {
delay(3000); // Startup delay
Serial.begin(57600); // Initialize serial communication (optional)
FastLED.addLeds<LED_TYPE, DATA_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
FastLED.setMaxPowerInVoltsAndMilliamps(VOLTS, 2000); // Set power limits
FastLED.setBrightness(MASTER_BRIGHTNESS); // Set fixed brightness
// Initialize ledsX to black
for (int i = 0; i < NUM_LEDS; i++) {
ledsX[i][0] = 0;
ledsX[i][1] = 0;
ledsX[i][2] = 0;
}
}
// --- Main Loop ---
void loop() {
// Brightness control removed. Brightness is now fixed at MASTER_BRIGHTNESS.
// potValA = analogRead(BRIGHTNESS_PIN);
// brightnessa = map(potValA, 0, 1023, MIN_BRIGHTNESS, MASTER_BRIGHTNESS_INIT);
// FastLED.setBrightness(brightnessa);
// if (brightnessa > MIN_BRIGHTNESS) // Run patterns only if brightness is above minimum
// {
meteorShower(); // Execute the meteor shower pattern
FastLED.show(); // Display the LEDs
// The meteorShower function itself contains a delay, so no additional FastLED.delay is needed here.
// } else {
// // Turn off LEDs if brightness is below minimum (potentiometer turned down)
// FastLED.clear();
// FastLED.show();
// }
}
// --- Pattern Functions ---
// Meteor shower effect
void meteorShower() {
hue++; // Increment hue for color cycling
// Copy current LEDs to ledsX for trailing effect
// ledsX stores the previous frame's state to create the tail
for (byte i = 0; i < NUM_LEDS; i++) {
ledsX[i][0] = leds[i].r;
ledsX[i][1] = leds[i].g; // FIXED: Corrected to .g (green component)
ledsX[i][2] = leds[i].b; // FIXED: Corrected to .b (blue component)
}
byte iCCW; // Counter-clockwise adjacent pixel index
timeframe++; // Increment the global timeframe counter
// --- Time-based meteor length and color variations ---
// Initial short meteor
if ((timeframe >= 1) && (timeframe <= METEOR_INITIAL_LENGTH_FRAMES)) { meteorLENGTH = 29; }
// Medium length meteor
if ((timeframe > METEOR_INITIAL_LENGTH_FRAMES) && (timeframe <= METEOR_MEDIUM_LENGTH_FRAMES)) { meteorLENGTH = 45; }
// Rainbow head color during initial phase
if ((timeframe > 0) && (timeframe <= METEOR_INITIAL_LENGTH_FRAMES)) { RAINBOWs = true; }
else { RAINBOWs = false; }
if (RAINBOWs == true) { hue = hue - 20; if (hue <= 0) { hue = 1; } } // Adjust hue for rainbow effect
// Random head position during a specific timeframe
if ((timeframe > METEOR_RANDOM_PICK_START_FRAMES) && (timeframe <= METEOR_RANDOM_PICK_END_FRAMES)) { RANDOMpick = true; }
else { RANDOMpick = false; }
if (RANDOMpick == true) { idex = random8(46); } // Random index for meteor head
else {
idex++; // Increment index for normal movement
if (idex > meteorLENGTH) { idex = 0; } // Reset index if it exceeds current meteor length
}
// Random meteor length during another timeframe
if ((timeframe > METEOR_RANDOM_LENGTH_START_FRAMES) && (timeframe <= METEOR_RANDOM_LENGTH_END_FRAMES)) { meteorLENGTH = random8(7, 38); }
// Reset timeframe and increment loop count after a full cycle
if (timeframe == METEOR_FULL_CYCLE_FRAMES) {
timeframe = 0;
loopCount++;
}
// Cycle through different color TIP modes based on loopCount
if (loopCount == 1) { colorTIP = 0; } // Default hue
if (loopCount == 2) { colorTIP = 1; } // White
if (loopCount == 3) { colorTIP = random8(11); } // Random fixed color
if (loopCount == 4) {
colorTIP = 0;
loopCount = 0; // Reset loop count
}
// --- Color selection for meteor head based on idex and colorTIP ---
switch (idex) {
case 0: // Brightest head of the meteor
switch (colorTIP) {
case 0: leds[0] = CHSV(hue, 255, 255); break; // Current hue
case 1: leds[0] = CRGB(100, 100, 100); break; // Dim white
case 2: leds[0] = CRGB::Yellow; break;
case 3: leds[0] = CRGB::Violet; break;
case 4: leds[0] = CRGB::Green; break;
case 5: leds[0] = CRGB::Purple; break;
case 6: leds[0] = CRGB::Orange; break;
case 7: leds[0] = CRGB::Cyan; break;
case 8: leds[0] = CRGB::GreenYellow; break;
case 9: leds[0] = CRGB::Magenta; break;
case 10: leds[0] = CRGB::SkyBlue; break;
}
break;
// Fading tail segments behind the head
case 1: leds[0] = CHSV((hue - 20), 255, 210); break;
case 2: leds[0] = CHSV((hue - 22), 255, 180); break;
case 3: leds[0] = CHSV((hue - 23), 255, 150); break;
case 4: leds[0] = CHSV((hue - 24), 255, 110); break;
case 5: leds[0] = CHSV((hue - 25), 255, 90); break;
case 6: leds[0] = CHSV((hue - 26), 160, 60); break;
case 7: leds[0] = CHSV((hue - 27), 140, 40); break;
case 8: leds[0] = CHSV((hue - 28), 120, 20); break;
case 9: leds[0] = CHSV((hue - 29), 100, 20); break;
// Meteor tail fade out (all black after this point)
default: // Covers cases 10 through 45 and beyond
leds[0] = CRGB::Black;
break;
}
// --- Shift meteor effect down the strip ---
// Each pixel takes the color of the pixel "behind" it from the previous frame
// This creates the movement effect
for (byte i = 1; i < NUM_LEDS; i++) {
iCCW = adjacent_ccw(i); // Get the index of the pixel "behind" the current one
leds[i].r = ledsX[iCCW][0];
leds[i].g = ledsX[iCCW][1];
leds[i].b = ledsX[iCCW][2];
}
delay(METEOR_DELAY); // Pause for a short duration to control speed
}
// Helper function for meteor shower - get adjacent pixel counter-clockwise
// This makes the meteor move from right to left (or end to start of strip)
byte adjacent_ccw(byte i) {
byte r;
if (i > 0) { r = i - 1; }
else { r = NUM_LEDS - 1; } // Wrap around to the end of the strip
return r;
}
// --- LED Strip Output Functions ---
// Shows the current LED buffer on the strip
void showStrip() {
FastLED.show();
}
// Sets a single pixel's color
void setPixel(int Pixel, byte red, byte green, byte blue) {
if (Pixel >= 0 && Pixel < NUM_LEDS) { // Safety check for pixel index
leds[Pixel].r = red;
leds[Pixel].g = green;
leds[Pixel].b = blue;
}
}
// Sets all pixels to the same RGB color
void setAll(byte red, byte green, byte blue) {
for (int i = 0; i < NUM_LEDS; i++) {
setPixel(i, red, green, blue);
}
showStrip();
}