Need help, motion and LDR sensor to turn on LED using MIT App Inventor

Hey guys, I am working on a smart lighting project which have the ability for me to turn on the lights manually and adjust the preset brightness and could also have it on auto mode which the motion and LDR sensor would take over the control. I am able to run both the auto and manual program individually and working but the problem comes when I merge the two programs together into a single sketch. I am still able to turn on and off the LED lights manually but the program is unable to enter the while loop when "k" was sent. Below are my current code progress

//LDR_PIR Digital Without Dimmer
//Initialization and calibration code
char incoming_value  = 0;    // default value for bluetooth communication

int dimLed  = 5;  //First LED
int dimLed2 = 6;  //Second LED

const int DUTY_25 = 32;   //Preset Brightness level to 25% for LED 1 
const int DUTY_50 = 64;   //Preset Brightness level to 50% for LED 1 
const int DUTY_75 = 128;  //Preset Brightness level to 75% for LED 1 

const int DUTY2_25 = 32;  // Preset Brightness level to 25% for LED 2
const int DUTY2_50 = 64;  // Preset Brightness level to 25% for LED 2
const int DUTY2_75 = 128; // Preset Brightness level to 25% for LED 2


int pirsensor = 2;    //pir sensor to be at pin 2

int calibrationTime = 30; //calibration timing for PIR set at 30 sec

void setup()
{
  Serial.begin(9600);
  pinMode(dimLed, OUTPUT);     //declaring dimLed as the output for LED 1 
  pinMode(dimLed2, OUTPUT);    //declaring dimLed as the output for LED 2 
  pinMode(pirsensor, INPUT);   //PIR as input 
  pinMode(A0, INPUT);          //A0 connects to LDR as input 

  Serial.println("Waiting for the sensor to warm up.");
  delay(calibrationTime * 1000); // Convert the time from seconds to milliseconds.
  Serial.println("SENSOR ACTIVE");
}

void loop()
{
  if (Serial.available())  //Any incoming value
  {
    Serial.println(analogRead(A0));
    pirsensor = digitalRead(2);        //pirsensor value between 1 or 0
    Serial.println(digitalRead(2));    //show PIR value on serial monitor
    delay(300);

    char incoming_value = Serial.read();  //whatever read on serial to store into incoming_value
    Serial.println(incoming_value);    //show the value read by Serial.read

    // Manual mode
    if (incoming_value == '7')         //when user send '7' , turn on 1st led
    {
      digitalWrite(dimLed, HIGH);
    }
    else if (incoming_value == '8')   //when user send '8' , turn off 1st led
    {
      digitalWrite(dimLed, LOW);
    }
    else if (incoming_value == 'c') . //when user send 'c' , adjust brightness level to 25%
    {
      analogWrite( dimLed, DUTY_25 );
    }
    else if (incoming_value == 'd')   //when user send 'd' , adjust brightness level to 50%
    {
      analogWrite( dimLed, DUTY_50 );
    }
    else if (incoming_value == 'e')  //when user send 'e' , adjust brightness level to 75%
    {
      analogWrite( dimLed, DUTY_75 );
    }

   
    if (incoming_value == 'f')       //LED 2 be same as first LED program 
    {
      digitalWrite(dimLed2, HIGH);
    }
    else if (incoming_value == 'g')
    {
      digitalWrite(dimLed2, LOW);
    }
    else if (incoming_value == 'h')
    {
      analogWrite( dimLed2, DUTY2_25 );
    }
    else if (incoming_value == 'i')
    {
      analogWrite( dimLed2, DUTY2_50 );
    }
    else if (incoming_value == 'j')
    {
      analogWrite( dimLed2, DUTY2_75 );
    }
  }
  
  else if (incoming_value == 'k')     // Activating "Auto" mode when incoming_value is "k"
  {
    while ( analogRead(A0) > 0  )     //  Upon receiving "k", enters while loop  
    {
      if (analogRead(A0) > 400 && digitalRead(2) == HIGH) .  // When LDR reading is above 400 and PIR detected motion = HIGH
      {
        digitalWrite(dimLed, HIGH);                          //LDR reading > 400 indicating sky is dark 
        digitalWrite(dimLed2, HIGH);                         //Both LED will turned on automatically 
        Serial.println("Sky is dark and motion is detected"); // Displaying current status in Auto mode 
      }
      else if (analogRead(A0) > 400 && digitalRead(2) == LOW) // When LDR reading is above 400 and PIR detected no motion = LOW
      {
        digitalWrite(dimLed, LOW);                            //Both LED will remained off
        digitalWrite(dimLed2, LOW);
        Serial.println("Sky is Dark and no motion is detected"); // Display current status 
      }

      else if (analogRead(A0) < 400 && digitalRead(2) == LOW)  // When LDR reading is below 400 and PIR detected no motion = LOW
      {
        digitalWrite(dimLed, LOW);                              //Both LED will remained off
        digitalWrite(dimLed2, LOW);
        Serial.println("Sky is bright and no motion is detected"); // Display current status 
      }

      else if (analogRead(A0) < 400 && digitalRead(2) == HIGH) // When LDR reading is below 400 and PIR detected motion = HIGH
      {
        digitalWrite(dimLed, LOW);                             //Both LED remained off 
        digitalWrite(dimLed2, LOW);
        Serial.println("Sky is bright and motion is detected");  //Display current status 
      }
    }
  }
}


image

Hi
Do you know the importance of commenting out each line of your code?
I'll talk about at least 2 good reasons to comment the lines:

  1. When you ask someone to help you with your code,
    this person will have to spend the crystal ball credits to
    "discover" what went through your mind when you wrote each
    line.
  2. After some time, you discover a bug in your code.
    Then he looks at him and thinks: Why did I even put this
    line here......?

Commenting out each line of code is not writing the obvious thing it shows.
It is to describe the reason for the line.

Ex:
If(count == 5) --> obvious --> If the counter is = 5;
If(pin2 == HIGH) --> Functional --> If 5 objects passed in the detector .....

Please, if you want good help, comment out the lines of your code.

Good programming practice is to use //and add comments telling what the intention is.
The same goes for naming the pins. A0, D2 tells absolutely nothing for us, and some years later it will not tell You either.

The "k" reads A0 and takes action for every value greater than 0.
If possible use greater than 5, 10 or something even higher.

Use serial monitor, in the IDE, and Serial.print in the code. Printing the A0 values would be highly valuable.

Hi @lemonss

try this modifications in your code:

//Initialization and calibration code
char incoming_value  = 0;

int dimLed  = 5;
int dimLed2 = 6;

const int DUTY_25 = 32;
const int DUTY_50 = 64;
const int DUTY_75 = 128;

const int DUTY2_25 = 32;
const int DUTY2_50 = 64;
const int DUTY2_75 = 128;


int pirsensor = 2;

int calibrationTime = 30;
//--------------------------------------------------------------------
void setup()
{
  Serial.begin(9600);
  pinMode(dimLed, OUTPUT);
  pinMode(dimLed2, OUTPUT);
  pinMode(pirsensor, INPUT);
  pinMode(A0, INPUT);

  Serial.println("Waiting for the sensor to warm up.");
  delay(calibrationTime * 1000); // Convert the time from seconds to milliseconds.
  Serial.println("SENSOR ACTIVE");
}
//--------------------------------------------------------------------
void loop()
{
  pirsensor = digitalRead(2);          // Read PIR status for dimmer routines
  if (Serial.available())
  {
    Serial.println(analogRead(A0));
    //pirsensor = digitalRead(2);
    Serial.println(digitalRead(2));
    delay(300);

    char incoming_value = Serial.read();
    Serial.println(incoming_value);
  }
  // Manual mode
  if (incoming_value == '7')
  {
    digitalWrite(dimLed, HIGH);
  }
  else if (incoming_value == '8')
  {
    digitalWrite(dimLed, LOW);
  }
  else if (incoming_value == 'c')
  {
    analogWrite( dimLed, DUTY_25 );
  }
  else if (incoming_value == 'd')
  {
    analogWrite( dimLed, DUTY_50 );
  }
  else if (incoming_value == 'e')
  {
    analogWrite( dimLed, DUTY_75 );
  }

  //LED2
  if (incoming_value == 'f')
  {
    digitalWrite(dimLed2, HIGH);
  }
  else if (incoming_value == 'g')
  {
    digitalWrite(dimLed2, LOW);
  }
  else if (incoming_value == 'h')
  {
    analogWrite( dimLed2, DUTY2_25 );
  }
  else if (incoming_value == 'i')
  {
    analogWrite( dimLed2, DUTY2_50 );
  }
  else if (incoming_value == 'j')
  {
    analogWrite( dimLed2, DUTY2_75 );
  }
  //}
  //Auto mode
  else if (incoming_value == 'k')
  {
    //    while ( analogRead(A0) > 0  )
    while ( analogRead(A0) > 20  )
    {
      if (analogRead(A0) > 400 && digitalRead(2) == HIGH)
      {
        digitalWrite(dimLed, HIGH);
        digitalWrite(dimLed2, HIGH);
        Serial.println("Sky is dark and motion is detected");
      }
      else if (analogRead(A0) > 400 && digitalRead(2) == LOW)
      {
        digitalWrite(dimLed, LOW);
        digitalWrite(dimLed2, LOW);
        Serial.println("Sky is Dark and no motion is detected");
      }

      else if (analogRead(A0) < 400 && digitalRead(2) == LOW)
      {
        digitalWrite(dimLed, LOW);
        digitalWrite(dimLed2, LOW);
        Serial.println("Sky is bright and no motion is detected");
      }

      else if (analogRead(A0) < 400 && digitalRead(2) == HIGH)
      {
        digitalWrite(dimLed, LOW);
        digitalWrite(dimLed2, LOW);
        Serial.println("Sky is bright and motion is detected");
      }
    }
  }
  incoming_value = ' ';   // Clear incoming_value to avoid repeat action
}

Hi, Sorry for the inconvenience. I have included the remarks

Hello, I have included the remarks :slight_smile:

Hi, I have test it. Both manual and auto are not working for this modified code.

That does not tell anything useful. What does serial monitor show up?
Adding more Serial.print in strategic places can tell things....

char incoming_value  = 0;    // default value for bluetooth communication
 char incoming_value = Serial.read();

You have redeclared incoming_value and have scope issues for what is being used in the conditional.

Just use the global declaration and then use
incoming_value = Serial.read();

Try this:

//Initialization and calibration code
char incoming_value  = 0;

int dimLed  = 5;
int dimLed2 = 6;

const int DUTY_25 = 32;
const int DUTY_50 = 64;
const int DUTY_75 = 128;

const int DUTY2_25 = 32;
const int DUTY2_50 = 64;
const int DUTY2_75 = 128;


int pirsensor = 2;

int calibrationTime = 30;

//--------------------------------------------------------------------
void setup()
{
  Serial.begin(9600);
  pinMode(dimLed, OUTPUT);
  pinMode(dimLed2, OUTPUT);
  pinMode(pirsensor, INPUT);
  pinMode(A0, INPUT);

  Serial.println("Waiting for the sensor to warm up.");
  delay(calibrationTime * 1000); // Convert the time from seconds to milliseconds.
  Serial.println("SENSOR ACTIVE");
}
//--------------------------------------------------------------------
void loop()
{
  pirsensor = digitalRead(2);          // Read PIR status for dimmer routines
  if (Serial.available())
  {
    Serial.println(analogRead(A0));
    //pirsensor = digitalRead(2);
    Serial.println(digitalRead(2));
    delay(300);

    incoming_value = Serial.read();
    //char incoming_value = Serial.read();
    //Serial.println(incoming_value);
  }
  // Manual mode
  if (incoming_value == '7')
  {
    digitalWrite(dimLed, HIGH);
    Serial.println(incoming_value);       // For DEBUG only
  }
  else if (incoming_value == '8')
  {
    digitalWrite(dimLed, LOW);
    Serial.println(incoming_value);       // For DEBUG only
  }
  else if (incoming_value == 'c')
  {
    Serial.println(incoming_value);       // For DEBUG only
    analogWrite( dimLed, DUTY_25 );
  }
  else if (incoming_value == 'd')
  {
    Serial.println(incoming_value);       // For DEBUG only
    analogWrite( dimLed, DUTY_50 );
  }
  else if (incoming_value == 'e')
  {
    Serial.println(incoming_value);       // For DEBUG only
    analogWrite( dimLed, DUTY_75 );
  }

  //LED2
  if (incoming_value == 'f')
  {
    Serial.println(incoming_value);       // For DEBUG only
    digitalWrite(dimLed2, HIGH);
  }
  else if (incoming_value == 'g')
  {
    Serial.println(incoming_value);       // For DEBUG only
    digitalWrite(dimLed2, LOW);
  }
  else if (incoming_value == 'h')
  {
    Serial.println(incoming_value);       // For DEBUG only
    analogWrite( dimLed2, DUTY2_25 );
  }
  else if (incoming_value == 'i')
  {
    Serial.println(incoming_value);       // For DEBUG only
    analogWrite( dimLed2, DUTY2_50 );
  }
  else if (incoming_value == 'j')
  {
    Serial.println(incoming_value);       // For DEBUG only
    analogWrite( dimLed2, DUTY2_75 );
  }
  //}
  //Auto mode
  else if (incoming_value == 'k')
  {
    Serial.println(incoming_value);       // For DEBUG only
    //    while ( analogRead(A0) > 0  )
    while ( analogRead(A0) > 20  )
    {
      if (analogRead(A0) > 400 && digitalRead(2) == HIGH)
      {
        digitalWrite(dimLed, HIGH);
        digitalWrite(dimLed2, HIGH);
        Serial.println("Sky is dark and motion is detected");
      }
      else if (analogRead(A0) > 400 && digitalRead(2) == LOW)
      {
        digitalWrite(dimLed, LOW);
        digitalWrite(dimLed2, LOW);
        Serial.println("Sky is Dark and no motion is detected");
      }

      else if (analogRead(A0) < 400 && digitalRead(2) == LOW)
      {
        digitalWrite(dimLed, LOW);
        digitalWrite(dimLed2, LOW);
        Serial.println("Sky is bright and no motion is detected");
      }

      else if (analogRead(A0) < 400 && digitalRead(2) == HIGH)
      {
        digitalWrite(dimLed, LOW);
        digitalWrite(dimLed2, LOW);
        Serial.println("Sky is bright and motion is detected");
      }
    }
  }
  incoming_value = ' ';   // Clear incoming_value to avoid repeat action
}

Yes, this helps a lot. However, it works one way and does not exit the while loop when I want to control the LED manually again.

Is analogRead(A0) ever less than 20?

Or are you looking for a manual way to exit the while loop the reading is greater than 20?

Yes A0 will always be bigger than 20 in my case as I am using LDR to check the light intensity of the environment.

I can’t seem to think of a solution where if I were to send an incoming value of lets say, “z” to end while loop. So I am able to control LED manually again.

Good idea. You could start off the while loop like this

while ( analogRead(A0) > 20  )
    {
      if(Serial.available())
      {
        incoming_value= Serial.read();
        if(incoming_value == 'z') break; //will exit while loop
      }

Thank you!

Hi, I am having this issue where the while loop is not able to exit if I let it run for a while (several seconds). However, it can stop if I send the "z" signal immediately after sending "k". Do you have any idea what is causing this problem?

Throughout this thread there have been several recommended changes to the code.

Please post the exact code you are using, and provide more information on the failure conditions if you can.

Currently, I am able to adjust the lighting manually on my own by sending all the char. As for the Auto side, the program is able to go into the while loop by sending "k" and trigger the lightings and the fan as well. But I realised after letting the code run by itself on Auto mode for alittle longer ( 10-20 sec ), it is not able to exit the while loop when "z" is sent again? I am only able to exit the while loop when I send "z" quickly after entering it. Still, over the long run the program can't seem to receive "z" signal anymore.

//Initialization and calibration code
char incoming_value  = 0;  // default value for bluetooth communication

int dimLed  = 5;              //First LED
int dimLed2 = 6;              //Second LED

const int DUTY_25 = 32;       //Preset Brightness level to 25% for LED 1 
const int DUTY_50 = 64;       //Preset Brightness level to 50% for LED 1 
const int DUTY_75 = 128;      //Preset Brightness level to 75% for LED 1 

const int DUTY2_25 = 32;      // Preset Brightness level to 25% for LED 2
const int DUTY2_50 = 64;      // Preset Brightness level to 25% for LED 2
const int DUTY2_75 = 128;     // Preset Brightness level to 25% for LED 2


int pirsensor = 2;            //pir sensor to be at pin 2

int fan = 8;                  //dc motor to be at pin 8

int calibrationTime = 30;     //calibration timing for PIR set at 30 sec

//--------------------------------------------------------------------
void setup()
{
  Serial.begin(9600);
  pinMode(dimLed, OUTPUT);       //declaring dimLed as the output for LED 1
  pinMode(dimLed2, OUTPUT);     //declaring dimLed as the output for LED 2 
  pinMode(pirsensor, INPUT);    //A0 connects to LDR as input
  pinMode(A0, INPUT);
  pinMode(fan, OUTPUT);

  Serial.println("Waiting for the sensor to warm up.");
  delay(calibrationTime * 1000); // Convert the time from seconds to milliseconds.
  Serial.println("SENSOR ACTIVE");
}
//--------------------------------------------------------------------
void loop()
{
  pirsensor = digitalRead(2);          // Read PIR status for dimmer routines
  if (Serial.available())              //Any incoming value
  {
    Serial.println(analogRead(A0));
    Serial.println(digitalRead(2));
    delay(300);

    incoming_value = Serial.read();     //whatever read on serial to store into incoming_value
  }
  // Manual mode , users turning on/off and adjusting brightness manually 
  if (incoming_value == '7')            //when user send '7' , turn on 1st led
  {
    digitalWrite(dimLed, HIGH);
    Serial.println(incoming_value);       //show the value read by Serial.read
  }
  else if (incoming_value == '8')         //when user send '8' , turn off 1st led
  {
    digitalWrite(dimLed, LOW);
    Serial.println(incoming_value);       
  }
  else if (incoming_value == 'c')         //when user send 'c' , adjust brightness level to 25%
  {
    Serial.println(incoming_value);       
    analogWrite( dimLed, DUTY_25 );
  }
  else if (incoming_value == 'd')         //when user send 'd' , adjust brightness level to 50%
  {
    Serial.println(incoming_value);       
    analogWrite( dimLed, DUTY_50 );
  }
  else if (incoming_value == 'e')         //when user send 'd' , adjust brightness level to 75%
  {
    Serial.println(incoming_value);       
    analogWrite( dimLed, DUTY_75 );
  }



  //LED2                                    //LED 2 be same as 1st LED
  if (incoming_value == 'f')
  {
    Serial.println(incoming_value);       // For DEBUG only
    digitalWrite(dimLed2, HIGH);
  }
  else if (incoming_value == 'g')
  {
    Serial.println(incoming_value);       // For DEBUG only
    digitalWrite(dimLed2, LOW);
  }
  else if (incoming_value == 'h')
  {
    Serial.println(incoming_value);       // For DEBUG only
    analogWrite( dimLed2, DUTY2_25 );
  }
  else if (incoming_value == 'i')
  {
    Serial.println(incoming_value);       // For DEBUG only
    analogWrite( dimLed2, DUTY2_50 );
  }
  else if (incoming_value == 'j')
  {
    Serial.println(incoming_value);       // For DEBUG only
    analogWrite( dimLed2, DUTY2_75 );
  }

  //fan

  else if (incoming_value == 't')
  {
    Serial.println(incoming_value);       
    digitalWrite( fan, HIGH );
  }

  else if (incoming_value == 'y')
  {
    Serial.println(incoming_value);       
    digitalWrite( fan, LOW );
  }


  //}
  //Auto mode
  else if (incoming_value == 'k')         // Activating "Auto" mode when incoming_value is "k"
  {
    Serial.println(incoming_value);       // For DEBUG only

    while ( analogRead(A0) > 20  )         //  Enters while loop ,upon receiving "k"
    {
      if (Serial.available())
      {
        incoming_value = Serial.read();

        if (incoming_value == 'z')

          Serial.println(incoming_value);

        break;                           //will exit while loop

      }

      else if (analogRead(A0) > 400 && digitalRead(2) == HIGH)    // When LDR reading is above 400 and PIR detected motion = HIGH
      {
        digitalWrite(dimLed, HIGH);                               //LDR reading > 400 indicating sky is dark
        digitalWrite(dimLed2, HIGH);                              //Both LED will turned on automatically 
        Serial.println("Fan on");       
        digitalWrite(fan, HIGH);                                  //Fan on when motion is detected 
        delay(8000);
        digitalWrite(fan, LOW);
        Serial.println("Sky is dark and motion is detected");     // Displaying current status in Auto mode


      }
      else if (analogRead(A0) > 400 && digitalRead(2) == LOW)     // When LDR reading is above 400 and PIR detected no motion = LOW
      { 
        digitalWrite(dimLed, LOW);                                  //Both LED will remained off     
        digitalWrite(dimLed2, LOW);
        Serial.println("Sky is Dark and no motion is detected");    // Displaying current status in Auto mode

      }

      else if (analogRead(A0) < 400 && digitalRead(2) == LOW)     // When LDR reading is below 400 and PIR detected no motion = LOW
      {
        digitalWrite(dimLed, LOW);
        digitalWrite(dimLed2, LOW);                                  //Both LED will remained off
        Serial.println("Sky is bright and no motion is detected");   // Displaying current status in Auto mode

      }

      else if (analogRead(A0) < 400 && digitalRead(2) == HIGH)     // When LDR reading is below 400 and PIR detected motion = HIGH
      {
        digitalWrite(dimLed, LOW);
        digitalWrite(dimLed2, LOW);                               //Both LED remained off
        Serial.println("Fan on");
        digitalWrite(fan, HIGH);                                //Fan on when motion is detected     
        delay(8000);
        digitalWrite(fan, LOW);
        Serial.println("Sky is bright and motion is detected");   //Display current status 

      }
    }
  }
  incoming_value = ' ';   // Clear incoming_value to avoid repeat action
}

I can not confirm you findings.

Is your monitor set for "no line ending"?
What is the condition inside the while loop? With "Fan On" and the delay, the response to 'z' is sluggish get does indeed break after the delay.

The bracketing for the reading of the 'z' to break the while loop was not quite correct after you added the serial print, but you should have broken with any letter sent.

Try this start of the while loop.

else if (incoming_value == 'k')         // Activating "Auto" mode when incoming_value is "k"
  {
    Serial.println(incoming_value);       // For DEBUG only

    while ( analogRead(A0) > 20  )         //  Enters while loop ,upon receiving "k"
    {
      if (Serial.available())
      {
        incoming_value = Serial.read();

        if (incoming_value == 'z') 
        {
          Serial.println(incoming_value);
          break;                           //will exit while loop
        }
      }

I have tried to insert the bracket for the "z" and also tried removing the fan, changing the new line to no line ending on the serial monitor. Still not able to receive "z" and exit the while loop after running for a while. It is weird because the program is able to run smoothly for the first few seconds ( going in and out of Auto Mode ).

Both my program storage space and dynamic memory are about 20% after uploaded so memory shouldn't be the issue I guess?

I have placed the "z" inside the while loop bracket, so "z" is the only letter that can exit the while loop.