#include <Adafruit_NeoPixel.h>
// --------- Pin Definitions ---------
#define SELECT_BUTTON_PIN 2 // Button to select a color & sparkle
#define EFFECT_BUTTON_PIN 3 // Button to run the pulse effect & trigger solenoid
#define SOLENOID_PIN 4 // Controls the MOSFET for the solenoid
#define NEOPIXEL_PIN 6 // Data pin for the NeoPixel strip
// --------- NeoPixel Settings ---------
#define NUM_PIXELS 180 // Full 3 m strip at 60 LEDs/m
#define TAIL_LENGTH 8 // Number of LEDs lit in the moving pulse
#define SPARK_TIME 2000 // try 2000
#define PULSE_SPEED 20 //try 20 for ~5 seconds
// --------- Color Options ---------
// Define a list of colors (using Adafruit_NeoPixel's Color() function).
// You can add or remove colors as desired.
uint32_t colorOptions[] = {
Adafruit_NeoPixel::Color(255, 0, 0), // Red
Adafruit_NeoPixel::Color(0, 255, 0), // Green
Adafruit_NeoPixel::Color(0, 0, 255), // Blue
Adafruit_NeoPixel::Color(255, 255, 0), // Yellow
Adafruit_NeoPixel::Color(255, 0, 255), // Magenta
Adafruit_NeoPixel::Color(0, 255, 255), // Cyan
Adafruit_NeoPixel::Color(255, 128, 0) // Orange
};
const int numColors = sizeof(colorOptions) / sizeof(colorOptions[0]);
// Default selected color is white.
uint32_t selectedColor = Adafruit_NeoPixel::Color(255, 255, 255);
Adafruit_NeoPixel strip(NUM_PIXELS, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800);
void setup() {
// Initialize buttons with internal pull-ups
pinMode(SELECT_BUTTON_PIN, INPUT_PULLUP);
pinMode(EFFECT_BUTTON_PIN, INPUT_PULLUP);
// Set up the solenoid control pin
pinMode(SOLENOID_PIN, OUTPUT);
digitalWrite(SOLENOID_PIN, LOW); // Ensure the solenoid is off
// Initialize the NeoPixel strip
strip.begin();
strip.show(); // Turn all pixels off
// Seed the random number generator with noise from an unconnected analog pin.
randomSeed(analogRead(A0));
}
void loop() {
// ----- Color Select & Sparkle Effect -----
// When the select button is pressed, pick a random color and sparkle the strip.
if (digitalRead(SELECT_BUTTON_PIN) == LOW) {
delay(50); // debounce
if (digitalRead(SELECT_BUTTON_PIN) == LOW) { // Confirm button is still pressed
// Pick a random color from the list.
int index = random(0, numColors);
selectedColor = colorOptions[index];
// Sparkle the scepter with the chosen color for 3 seconds.
sparklingEffect(selectedColor, SPARK_TIME);
// Wait until the button is released.
while (digitalRead(SELECT_BUTTON_PIN) == LOW) {
delay(10);
}
delay(100); // extra debounce
}
}
// ----- Pulse Effect & Solenoid Activation -----
// When the effect button is pressed, run the pulse effect (using the preselected color)
// and then activate the solenoid briefly.
if (digitalRead(EFFECT_BUTTON_PIN) == LOW) {
delay(50); // debounce
if (digitalRead(EFFECT_BUTTON_PIN) == LOW) { // Confirm button is still pressed
pulseEffect(selectedColor);
// Briefly pulse the solenoid (adjust duration as needed)
digitalWrite(SOLENOID_PIN, HIGH);
delay(100); // 100 ms pulse; change if necessary
digitalWrite(SOLENOID_PIN, LOW);
// Wait until the button is released.
while (digitalRead(EFFECT_BUTTON_PIN) == LOW) {
delay(10);
}
delay(100); // extra debounce
}
}
}
// -----------------
// sparklingEffect()
// -----------------
// Flashes the scepter by lighting 10 random pixels in the given color.
// The effect runs for the specified duration (in milliseconds).
void sparklingEffect(uint32_t color, unsigned long durationMillis) {
unsigned long startTime = millis();
while (millis() - startTime < durationMillis) {
strip.clear();
// Light up 10 random pixels.
for (int i = 0; i < 10; i++) {
int pix = random(NUM_PIXELS);
strip.setPixelColor(pix, color);
}
strip.show();
delay(100); // Cycle speed (adjust for faster or slower sparkles)
}
strip.clear();
strip.show();
}
// -----------------
// pulseEffect()
// -----------------
// Creates a moving “pulse” (with a fading tail) from the bottom to the top of the strip,
// using the specified color. After the pulse, the strip is cleared.
void pulseEffect(uint32_t color) {
// The pulse will travel from pixel NUM_PIXELS-1 to 0 with a tail of TAIL_LENGTH pixels.
for (int i = NUM_PIXELS + TAIL_LENGTH - 1; i >= 0; i--) {
strip.clear();
// Light the tail (the head is the current i, and the tail fades behind it)
for (int j = 0; j < TAIL_LENGTH; j++) {
int pixelIndex = i + j;
if (pixelIndex >= 0 && pixelIndex < NUM_PIXELS) {
// Calculate a fading effect: the head is full brightness, fading with each pixel behind.
uint8_t brightness = 255 - (j * (255 / TAIL_LENGTH));
// Decompose the selected color into its RGB components.
uint8_t r = (color >> 16) & 0xFF;
uint8_t g = (color >> 8) & 0xFF;
uint8_t b = color & 0xFF;
// Scale the components by the brightness.
r = (uint8_t)(((uint16_t)r * brightness) / 255);
g = (uint8_t)(((uint16_t)g * brightness) / 255);
b = (uint8_t)(((uint16_t)b * brightness) / 255);
uint32_t fadeColor = strip.Color(r, g, b);
strip.setPixelColor(pixelIndex, fadeColor);
}
}
strip.show();
delay(PULSE_SPEED); // Adjust the speed of the pulse (smaller = faster)
}
strip.clear();
strip.show();
//for changing colors
int index = random(0, numColors);
selectedColor = colorOptions[index];
}