Sound Reactive Cloud Lamp w/ "Lightning Mode"

I’m in the final stages of coding a project I’ve been struggling with (as I’m only a beginner when it comes to Arduino) - it uses Neopixels that react to sound (coming through an Adafruit sound sensor - A0), they work well on their own. What I’m trying my best to add is a “lightning mode” (as the Neopixels will sit inside lanterns that are designed to look like a cloud).

When a user places their hand over an LDR/photocell sat atop of the cloud, the sound reactive mode will cease and the Neopixels will begin flashing rapidly, much like lightning. I have the lightning code separately (see attached if you want to see it - it works well) but I’m struggling to combine the LDR reactive, sound reactive and lightning code. I want the sound reactive code to run constantly from the point the cloud is plugged into the mains - until the LDR is triggered, that is.

I hope that makes sense! My edition of the code is below. The error I’m currently getting is that “ledsOff” isn’t declared - prior to adding “else”, it was also telling me that “lightning” hadn’t been declared either - even though void lightning() is further down the code.

Go easy on me, I’ve researched quite heavily - I hope it’s just something minor tripping me up!

// Sound activated LEDs with Sound Sensor and NeoPixels
#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#define MIC_PIN A0 // Adafruit Amplifier/Mic
#define LED_PIN 6 // NeoPixel LED strand
#define N_PIXELS 60 // number of pixels in LED strand
#define N 25 // Number of samples to take each time readSamples is called
#define fadeDelay 30 // delay time for each fade amount
#define noiseLevel 6 // slope level of average mic noise without sound

#define SECTION_LEN (10)     // number of LEDs to be grouped as one
#define NUM_SECTIONS (1)   // number of LED groups
#define HEARTBEAT_PIN (13)  // output pin for heartbeat LED   <--- (these 3 lines ADDED)

Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);

int samples[N]; // storage for a sample collection set
int periodFactor = 0; // keep track of number of ms for period calculation
int t1 = -1; // times of slope > 100 detected.
int T; // period between times scaled to milliseconds
int slope; // the slope of two collected data sample points
byte periodChanged = 0;

int sensorPin = A2;            // select the input pin for the ldr
unsigned int sensorValue = 0;  // variable to store the value coming from the ldr (2 lines ADDED)

int loop_count = 0;
bool heartbeat = false; // <- 2 added lines

// Arduino setup Method
void setup() {
  pinMode(HEARTBEAT_PIN, OUTPUT);
  strip.begin();
  ledsOff();
  delay(500);
  displayColor(Wheel(100));
  strip.show();
  delay(500);
}

// Arduino loop Method
void loop() {

      //Check to see if hand is above LDR
      sensorValue = analogRead(sensorPin); 

      if(600 < sensorValue) {

 lightning(); //DO LIGHTING STUFF
  int delay_long = random(100, 200);
  delay(delay_long);
     }    
      else {
      
  readSamples();
      }

// Read and Process Sample Data from Mic
void readSamples() {
  for(int i=0; i<N; i++) {
    samples[i] = analogRead(0);
    if(i>0) {
      slope = samples[i] - samples[i-1];
    }
    else {
      slope = samples[i] - samples[N-1];
    }
    // Check if Slope greater than noiseLevel - sound that is not at noise level detected
    if(abs(slope) > noiseLevel) {
      if(slope < 0) {
        calculatePeriod(i);
        if(periodChanged == 1) {
          displayColor(getColor(T));
        }
      }
    }
    else {
      ledsOff();
    }
    periodFactor += 1;
    delay(0.5);
  }
}

void calculatePeriod(int i) {
  if(t1 == -1) {
    // t1 has not been set
    t1 = i;
  }
  else {
    // t1 was set so calc period
    int period = periodFactor*(i - t1);
    periodChanged = T==period ? 0 : 1;
    T = period;
    //Serial.println(T);
    // reset t1 to new i value
    t1 = i;
    periodFactor = 0;
  }
}

uint32_t getColor(int period) {
  if(period == -1)
    return Wheel(0);
  else if(period > 400)
    return Wheel(5);
  else
    return Wheel(map(-1*period, -400, -1, 50, 255));
}

void fadeOut()
{
  for(int i=0; i<5; i++) {
    strip.setBrightness(110 - i*20);
    strip.show(); // Update strip
    delay(fadeDelay);
    periodFactor +=fadeDelay;
  }
}

void fadeIn() {
  strip.setBrightness(100);
  strip.show(); // Update strip
  // fade color in
  for(int i=0; i<5; i++) {
    //strip.setBrightness(20*i + 30);
    //strip.show(); // Update strip
    delay(fadeDelay);
    periodFactor+=fadeDelay;
  }
}

void ledsOff() {
  fadeOut();
  for(int i=0; i<N_PIXELS; i++) {
    strip.setPixelColor(i, 0, 0, 0);
  }
}

void displayColor(uint32_t color) {
  for(int i=0; i<N_PIXELS; i++) {
    strip.setPixelColor(i, color);
  }
  fadeIn();
}

// Input a value 0 to 255 to get a color value.
// The colors are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  if(WheelPos < 85) {
    return strip.Color(WheelPos * 255, 0 - WheelPos * 3, 0);
  } 
  else if(WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } 
  else {
    WheelPos -= 170;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }

const int sec_count = 9;  // the maximum "width" of each lightning sequence
const int seq_count = 9;  // the maximum "duration" of each lightning sequence
// run lightning flash sequence once (call from main loop to repeat)
void lightning()
{
  // randomly select the color of the current lightning sequence
  int r = random(200, 255);
  int g = random(150, 255) - 100;
  int b = random(200, 255);

  // randomly select the order in which the LED sections will flash
  // for the current lightning sequence
  int seq_order[seq_count];
  int seq_max = 0;
  for (int i = 0; i < seq_count; i++)
  {
    seq_order[i] = random(0, sec_count);
    seq_max = max(seq_max, seq_order[i]);
  }
  
  // randomly select the "duration" of the current lightning sequence
  int sections = random(5, seq_count);
  
  // randomly select the starting location of the current lightning sequence
  int seq_start = random(0, NUM_SECTIONS - seq_max);
  
  // loop through each of the chosen sections
  for (int j = 0; j < sections; j++)
  {
    // loop through each LED of the current section
    for (int k = 0; k < SECTION_LEN; k++)
    {
      // turn on the current LED
      int pix_cur = ((seq_start + seq_order[j]) * SECTION_LEN) + k;
      pixels.setPixelColor(pix_cur, pixels.Color(r, g, b));

      // turn off the LEDs of the previous section
      if (j > 0)
      {
        int pix_prv = ((seq_start + seq_order[j - 1]) * SECTION_LEN) + k;
        pixels.setPixelColor(pix_prv, pixels.Color(0, 0, 0));
      }
    }

    // very short (random) delay so we actually see the lightning
    int delay_quick = random(15, 40);
    delay(delay_quick);
    pixels.show();
  }

  all_off();
}

  
}

LIGHTNING.ino (2.6 KB)

Oh, excuse the lack of closed bracket on the loop. Fixed that.

Still struggling, so if anyone can help me punctuate it correctly so it lets me upload, I'd be grateful! :)

First, get your indentation fixed. In the IDE editor, press control-T. That will make it much easier for us to read.

It also reveals the main problem: all the functions after loop are inside loop. Maybe you accidentally deleted the closing curly brace of loop? You can tell that there is a problem, because the functions were indented by the auto-format. That should never happen if you have the right "nesting" of curly braces. A programming editor can help immensely with matching up the braces.

You are also using a pixels variable. I'll guess that the lightning routine came from a different sketch, because most of your sketch uses a strip variable. Pick one name and use that throughout.

Cheers, /dev

Hi Dev,

Thank you so much for all your tips - I've finally sorted it out and I couldn't be happier, I've been working on it for so long now. Thank you for spelling it out clearly :) I've had bad forum experiences in the past so your reply was much appreciated.

Cheers!