LED's reacting to music

Hello,

I currently have 3 LED strips (not the standard, I just got these from Target as Christmas tree lights, just a bunch of 1.5v LEDs in parallel for about 9’ each) connected to my Photon in D0, D1 and D2. I have a functioning section of code that’s more or less getting the results I want for the LEDs to actually react to the music, but it’s in the void loop section. I would like to be able to turn it on or off via Amazon Alexa via IFTTT. I have had some success in testing turning on solid colors and such, but anything that’s a loop will end up timing out the Photon and I can’t turn them off. I would like to figure out a way to loop it without timing out, as well as have a solid on state option as well.

This is the code I currently have, “musicTrigger” is a digitalOut that I could send to a mosfet to interrupt the signal to the lights, but I would like to avoid this to save space and make it more code reliant than component.

int r = D0; //red strip
int g = D1; //green strip
int w = D2; //white/yellow strip

int led1 = D7; //onboard led

int Ai = A2; //where I am reading the audio input from; a subwoofer line out channel on my receiver.

int musicTrigger = D3; //the on/off for the loop if using a mosfet

void setup()
{

  pinMode(r, OUTPUT);
  pinMode(g, OUTPUT);
  pinMode(w, OUTPUT);
  pinMode(musicTrigger, OUTPUT);

  pinMode(led1, OUTPUT);

  pinMode(Ai, INPUT);


  Particle.subscribe("simple", simpleLights); //solid lights
  Particle.subscribe("music", musicLights); //lights reacting to music via line out subwoofer channel on receiver
  //both of those have an IFTTT on/off recipe



  analogWrite(r, 0); //starts in off mode whenever photon restarts or is flashed
  analogWrite(g, 0);
  analogWrite(w, 0);
  digitalWrite(led1, LOW);

  digitalWrite(musicTrigger, LOW);


}



void loop()   // this is what I want to get into a function to turn on and off. As is, it just is always on. If I use the while loop it stays off until the trigger is 1, then times out.
{

  // while(musicTrigger == 1) {  // 1 is On and 0 is Off.  Only using this if a mosfet is necessary

  int lightOut = analogRead(Ai);

  if (lightOut >= 9) {  // if audio source is "louder" than an input of 9, it will output that times 20 to the lights. They're roughly fully on here if it is true.
    analogWrite(r, (lightOut * 20));
    delay(0);
  }

  else if (lightOut >= 6) {  //same as above, but a little less bright and more frequent
    analogWrite(g, (lightOut * 17));
    delay(0);
  }

  else if (lightOut >= 4) {  //same pattern as above
    analogWrite(w, (lightOut * 15));
    delay(0);
  }

  else if (lightOut < 3) {  // whenever the signal is lower than 3 I just have the lights in a low brightness state but still on, usefull for long breaks in bass.

    analogWrite(r, 10);
    analogWrite(g, 10);
    analogWrite(w, 10);
  }
  else {

  }
  //I know that if I made the delay on those longer, it would be fine. But in doing so I lose the effect of lighting to the beat.

  /*  analogWrite(r,255);  //A test function when music isn't available, this actually works fine and doesn't time out when in use.
    analogWrite(g,150);
    analogWrite(w,0);
    delay(250);
    analogWrite(w,255);
    delay(250);
  */
  //    }
}



void simpleLights(const char *event, const char *data)  //I couldn't get calling a function to work in IFTTT, so I had to learn the subscribe method instead. Not sure If I'm utilizing it correctly though, although it seems to work fine so far.
{


  if (strcmp(data, "On") == 0) {

    digitalWrite(musicTrigger, LOW); // turns off the loop if using a mosfet

    analogWrite(r, 255);
    analogWrite(g, 255);
    analogWrite(w, 255);

    digitalWrite(led1, HIGH);   // blink onboard led 3 times
    delay(250);
    digitalWrite(led1, LOW);
    delay(250);
    digitalWrite(led1, HIGH);
    delay(250);
    digitalWrite(led1, LOW);
    delay(250);
    digitalWrite(led1, HIGH);
    delay(250);
    digitalWrite(led1, LOW);
    delay(250);

  }


  else if (strcmp(data, "Off") == 0) {

    digitalWrite(musicTrigger, LOW);

    analogWrite(r, 0);
    analogWrite(g, 0);
    analogWrite(w, 0);

    digitalWrite(led1, HIGH);
    delay(250);
    digitalWrite(led1, LOW);
    delay(250);
    digitalWrite(led1, HIGH);
    delay(250);
    digitalWrite(led1, LOW);
    delay(250);
    digitalWrite(led1, HIGH);
    delay(250);
    digitalWrite(led1, LOW);
    delay(250);

  }
  else {

  }

}

void musicLights(const char *event, const char *data)
{


  if (strcmp(data, "On") == 0) {


    digitalWrite(musicTrigger, HIGH);

    digitalWrite(led1, HIGH);
    delay(250);
    digitalWrite(led1, LOW);
    delay(250);
    digitalWrite(led1, HIGH);
    delay(250);
    digitalWrite(led1, LOW);
    delay(250);
    digitalWrite(led1, HIGH);
    delay(250);
    digitalWrite(led1, LOW);
    delay(250);

  }


  else if (strcmp(data, "Off") == 0) {


    digitalWrite(musicTrigger, LOW);

    analogWrite(r, 0);
    analogWrite(g, 0);
    analogWrite(w, 0);


    digitalWrite(led1, HIGH);
    delay(250);
    digitalWrite(led1, LOW);
    delay(250);
    digitalWrite(led1, HIGH);
    delay(250);
    digitalWrite(led1, LOW);
    delay(250);
    digitalWrite(led1, HIGH);
    delay(250);
    digitalWrite(led1, LOW);
    delay(250);

  }
  else {

  }

}

If anyone has any ideas or a solution to this, it is much appreciated!
Thanks!

Since the loop() is already a loop, there's no need to create a new one using a while() loop. Try making that an if(), since that will loop, yet allow outside functions to interact in between loops.
And you might as well take the delay(0) out, since they really don't do anything like that.

Just to make sure, you are not driving the LEDs from the pins direct, are you?

@Jacob_813

You can try using more descriptive variable names and de-clutter your code’s commentary:

int redPin = D0;
int greenPin = D1;
int yellowPin = D2;
int onboardLed = D7;
int AudioInputPin = A2;
int musicTrigger = D3;

try a basic “state machine” structure based on your three possible Modes:

enum Modes{
    LIGHTS_OFF,
    SIMPLE_LIGHTS,
    LIGHTS_TO_MUSIC,
    MODES_MAX
};

int onboardLed = D7;

Modes mode = LIGHTS_OFF;
Modes lastMode = LIGHTS_OFF;

int blinkLed = 0;

void setup(void)
{
  pinMode(onboardLed, OUTPUT);
  Particle.subscribe("simple", simpleLights); //, MY_DEVICES);
  Particle.subscribe("music", musicLights); //, MY_DEVICES);
  Particle.function("SetMode", setMode);
}

void loop(void)
{
  if(mode == LIGHTS_OFF)
  {
    if(lastMode != LIGHTS_OFF)
    {
      // turn off the strip
      lastMode = LIGHTS_OFF;
    }
  }
  else if(mode == SIMPLE_LIGHTS)  // edited to correct to comparison operator
  {
    if(lastMode != SIMPLE_LIGHTS)
    {
      //turn on the lights
      lastMode = SIMPLE_LIGHTS;
    }
  }
  else // must be music
  {
    if(lastMode != LIGHTS_TO_MUSIC)
    {
      lastMode = LIGHTS_TO_MUSIC;
    }
    //
    // put your lights-to-music code here
    //
  }
  flashLed();
}

void simpleLights(const char* event, const char* data)
{
  if(strstr(data, "On"))
  {
    mode = SIMPLE_LIGHTS;
  }
  else if(strstr(data, "Off"))
  {
    mode = LIGHTS_OFF;
  }
  else
  {
    return;
  }
  blinkLed = 3;
}

void musicLights(const char* event, const char* data)
{
  if(strstr(data, "On"))
  {
    mode = LIGHTS_TO_MUSIC;
  }
  else if(strstr(data, "Off"))
  {
    mode = LIGHTS_OFF;
  }
  else
  {
    return;
  }
  blinkLed = 3;
}
// but I would do it with a function like this:

int setMode(String command)
{
  int newValue = command.toInt();
  if(newValue >= 0 and newValue < MODES_MAX)
  {
    mode = static_cast <Modes>(newValue);
    blinkLed = 3;
    return newValue;
  }
  return -1;
}

void flashLed()
{
  static int lastUpdateMillis = 0;
  if(blinkLed)
  {
    if(millis() - lastUpdateMillis > 250)
    {
      if(digitalRead(onboardLed))
      {
        blinkLed--;
      }
      digitalWrite(onboardLed, !digitalRead(onboardLed));
      lastUpdateMillis = millis();
    }
  }
}

compiles/tested as it is, you need to insert your different Modes code and add in the rest.

and you can make your code more responsive by getting rid of all your blocking code, particularly in Particle function calls. I added a non-blocking blink function (flashLed) for you to consider.

Okay thanks, I was wondering about the delay as 0, glad you could clear that up for me.

I am currently, but only because these LEDs are driven by low voltages that the pins can handle. Usually I wouldn’t and I would use mosfets connected to a separate source, but in this case that didn’t seem necessary. Is there any particular reason I shouldn’t be running these off of the pins? They were rated at 1.5v and were originally powered by AA batteries.

It’s not the voltage, but the current you’ll be drawing with several LEDs in parallel where GPIO pins can only source 25mA max.
Also what current limiting resistors are you using?

Ah okay, that would make sense. It seems to work fine right now, is it a continued usage that could damage the LEDs or the board? And would the best thing be to use mosfets to power it or would there be a different method you recommend?

You might frazzle the pin when drawing too much current.

MOSFET is fine.

Okay, I shall add that to my design to avoid this. Thanks!

@Jacob_813, the STM32F205 on the photon can only handle a TOTAL of 120ma through all pins. Beyond that, you risk damaging it.