Using millis for time delay for (push ON/OFF button)

so guys i finally managed to hack the ac remote and control AC via PIR sensor.

but for this i am using the delay() function and the problem is even though there is movement because of the delay() the arduino wont implement it, even if there is movement when AC is turned on it switches off after the preset time from the first movement but not the last movement detected because delay is triggered after the first movement!

the code is

void loop()
{ 
 val = digitalRead(sensor);                             //reads value from PIR proximity sensor
  potval = analogRead(pot);                           //reads potentiometer value
  timedelay = map(potval, 0, 1023, 20, 600);  //scales potentiometer value for delay
  timedelay=timedelay*1000;
  Serial.println(potval);
  Serial.println(timedelay);
 if(val == 1)                                                 // when proximity is detected
{
  ac();                                                         //activates ON/OFF button
  delay(timedelay);
  ac();                                                             
  }
  delay(1000);  
}

void ac()                                                     // for ON/OFF
{
  
  digitalWrite(led, HIGH);   
  delay(500);
  digitalWrite(led, LOW);
}

i cant implement the else if loop for using millis function as it triggers the ac() function each and every loop because of the ac() function in the else loop....

the code for led version using millis function for time delay is

void loop()
{
  val = digitalRead(sensor);                                //pir sensor
  potval = analogRead(pot);                                //pot value for time delay
  timedelay = map(potval, 0, 1023, 20, 600);

  if(val == 1)                                                     // if pir sensor triggered
  {
    digitalWrite(led, HIGH);
    time = millis()/1000;
  }
  timep=millis()/1000;
  if( abs(timep-time) <= timedelay)
  {
    digitalWrite(led, HIGH);
  }
  else
  {
    digitalWrite(led, LOW);
  }
  
  Serial.println(timedelay);
  delay(100);
}

please help me out as there is only single button to control the switching of the AC and tell me how i can implement it using millis

How would YOU perform the required actions, using a pencil, paper, and a watch? The millis() function takes the place of the watch. The pencil and paper are replaced by variables in the code.

i would do that using the else if loop for a led which works perfectly fine for led

if( abs(timep-time) <= timedelay)
{
digitalWrite(led, HIGH);
}
else
{
digitalWrite(led, LOW);
}

but if i use the same structure for my ac remote

if( abs(timep-time) <= timedelay)
{
ac(); //executes repeatedly until the set time
}
else
{
ac(); //executes repeatedly when it is idle
}

when these are being executed repeatedly the whole purpose is not satisfied as the AC keeps Switching ON and OFF every cycle irrespective of the value of the sensor

the hurdle is that while the led has 2 different commands to turn it ON and OFF

the ac remote has just a single command for ON and OFF

kiriti:
the ac remote has just a single command for ON and OFF

So you need to keep track of whether it is on or off, and only switch it if it's different to what you want it to be.

Also you shouldn't need the abs() calls as the type of your "timep" and "time" variables will be "unsigned long" already.

crimony:
Also you shouldn't need the abs() calls as the type of your "timep" and "time" variables will be "unsigned long" already.

yea crimony, but the millis button will overflow back to 0 after 50 days, that time the "timep-time" would go negative and the condition without abs "(timep-time) <= timedelay" would be satisfied for 50 more days :stuck_out_tongue:

thats why i included the abs function, or is it not necessary or am i overlooking something?

and thanks crimony and Pauls, will post the final code in few mins :smiley:

kiriti:
i would do that using the else if loop for a led which works perfectly fine for led

That's not what PaulS asked you to do.
Write down the steps you would take if you were doing it with a stopwatch.

  1. wait for button to be pressed
  2. start stopwatch
  3. do something
  4. wait until the stopwatch shows the delay time
    You continue....
    When you've done that, perhaps you will understand what you're trying to do and how to do it.

Also note that

if(millis() - starttime >=delaytime)

avoids any problems with rollover.

kiriti:
yea crimony, but the millis button will overflow back to 0 after 50 days, that time the "timep-time" would go negative and the condition without abs "(timep-time) <= timedelay" would be satisfied for 50 more days :stuck_out_tongue:

thats why i included the abs function, or is it not necessary or am i overlooking something?

Your code uses time in seconds, so you can't use the standard transparent technique for managing millis() rollover, which would be something like this (not tested, likely to contain some errors):

unsigned long timedelay;
unsigned long time;
unsigned long timep;
bool ac_on = false;

void loop()
{
  val = digitalRead(sensor);                                //pir sensor
  potval = analogRead(pot);                                //pot value for time delay
  timedelay = 1000 * map(potval, 0, 1023, 20, 600); // delay in milliseconds

  if(val == 1)                                                     // if pir sensor triggered
  {
    digitalWrite(led, HIGH);
    if (!ac_on)                                              // only toggle the AC if it's not on yet.
    {
      ac();
      ac_on = true;
    }
    time = millis();
  }
  timep = millis();
  if( ac_on && timep - time > timedelay)                   // time delay exceeded
  {
    digitalWrite(led, LOW);
    ac();
    ac_on = false;
  }
  
  Serial.println(timedelay);
  delay(100);
}

This code assumes the AC starts OFF. If it's not, then the logic will be reversed. You really should have a mechanism for detecting whether the AC is on or off, it would make your solution much more robust.

henry it means that i had to use the else if loop right?

my final working code:)

void loop(){
  val = digitalRead(sensor);
  potval = analogRead(pot);
  timedelay = map(potval, 0, 1023, 20, 600);
  Serial.println(potval);
  Serial.println(timedelay);
  
  if(val == 1)
  {
    time = millis()/1000;
  }
  timep=millis()/1000;
  if( timep-time <= timedelay)
  {
    acon();
  }
  else
  {
    acoff();
  }
  delay(1000);  
}

void acon(){
  if(state == 0)
  {
    digitalWrite(led, HIGH);   
    delay(500);
    digitalWrite(led, LOW);
    state = 1;
    Serial.println("AC ON");
  }
}

void acoff(){
  if(state == 1)
  {
    digitalWrite(led, HIGH);   
    delay(500);
    digitalWrite(led, LOW);
    state = 0;
    Serial.println("AC OFF");
  }
}

crimony i did it the same way as your code, but using int and not boolean

if by mechanism you mean external feedback to see weather AC is on, i dont think it is required as the AC remote sends different signals for ON and OFF so even though ac is initially ON, the functions wont get reversed :smiley:

i tried overriding with external remote, works good without inverting the states of the AC