switch case with timer help

larryd:
Made some cosmetic changes.
However, I tried it here, things work with using simple button switches to change the cases as I don't have a Bluetooth module right now.

Try this again, make sure you upload it to the Arduino.

#include <SoftwareSerial.h>// import the serial library

SoftwareSerial bluetooth(3, 4); // RX, TX
const int relayPin =  13;
unsigned long currentMillis;
unsigned long myRelayMillis;
unsigned long waitTime = 0;
char bluetoothData; // the data given from mobile app
boolean newData = false;

//***************************************************
void setup()
{
  bluetooth.begin(9600);
  pinMode(relayPin, OUTPUT);
  Serial.begin (9600); //uncomment for debugging
}

//***************************************************
void loop()
{

currentMillis = millis(); //for milli second timing

recvOneChar();
  controlWater();
}

//***************************************************
void recvOneChar()
{
  if (bluetooth.available() > 0)
  {
    bluetoothData = bluetooth.read();
    newData = true;
  }
}

//***************************************************
void controlWater()
{
  if (newData == true)
  {
    //cancel the timer as a new command has come in
    waitTime = 0;
    newData = false;
    myRelayMillis = millis();
  }

//is it time to process the next state code?
  if (currentMillis - myRelayMillis < waitTime)
  {
    //No, it is not time
    return;
  }

switch (bluetoothData)
  {
//*************
    case '1':
      {
        //Start watering
        digitalWrite(13, HIGH);  // turn the water on
        Serial.println("Start watering");
        myRelayMillis = millis();
        waitTime = 5000;
      }
      break;

//*************
    case '2':
      {
        //Stop watering when timing is over
        Serial.println("Stop watering");
        digitalWrite(13, LOW);    // turn the water off
        myRelayMillis = millis();
        waitTime = 5000;
      }
      break;

//*************
    case '3':
      {
        //Water for 1 hour
        Serial.println("Water for 1 hour");
        myRelayMillis = millis();
        waitTime = 5000ul;  //testing
        //waitTime = 1 * 60 * 60 * 1000ul;
        digitalWrite(13, HIGH);  // turn the water on

//Stop watering when timing is over
        bluetoothData = '2';
      }
      break;

//*************
    case '4':
      {
        //Water for 2 hours
        Serial.println("Water for 2 hours");
        myRelayMillis = millis();
        //waitTime = 10000;  //testing
        waitTime = 2 * 60 * 60 * 1000ul;
        digitalWrite(13, HIGH);  // turn the water on

//Stop watering when timing is over
        bluetoothData = '2';
      }
      break;

//*************
    case '5':
      {
        //Water for 3hours
        Serial.println("Water for 3 hours");
        digitalWrite(13, HIGH);  // turn the water on
        myRelayMillis = millis();
        //waitTime = 15000;  //testing
        waitTime = 3 * 60 * 60 * 1000ul;

//Stop watering when timing is over
        bluetoothData = '2';
      }
      break;

} //END of switch/case

} //END of function

//***************************************************

Just tried this code now, and still wont turn relay off when set time is passed.

As I mentioned it works here.

Please show us a good image of your hardware wiring so we can see how things are connected.

Memnon:
Just tried this code now, and still wont turn relay off when set time is passed.

It is my guess your Bluetooth sends more than one character, perhaps a \r at the end of a transmission.

Try this, it refuses characters not equal to '1'-'5'.

#include <SoftwareSerial.h>// import the serial library
SoftwareSerial bluetooth(3, 4); // RX, TX
const int relayPin =  13;
unsigned long currentMillis;
unsigned long myRelayMillis;
unsigned long waitTime = 0;
char bluetoothData; // the data given from mobile app
boolean newData = false;
char currentState;

//***************************************************
void setup()
{
  bluetooth.begin(9600);
  pinMode(relayPin, OUTPUT);
  Serial.begin (9600); //uncomment for debugging
}

//***************************************************
void loop()
{

  currentMillis = millis(); //for milli second timing

  recvOneChar();
  controlWater();
}

//***************************************************
void recvOneChar()
{
  if (bluetooth.available() > 0)
  {
    bluetoothData = bluetooth.read();
        
    //limit BT data to '1'-'5'
    if (bluetoothData > '0' && bluetoothData < '6')
    {
      newData = true;
      currentState = bluetoothData;      
    }
  }

}

//***************************************************
void controlWater()
{
  if (newData == true)
  {
    //cancel the timer as a new command has come in
    waitTime = 0;
    newData = false;
    myRelayMillis = millis();
  }

  //is it time to process the next state code?
  if (currentMillis - myRelayMillis < waitTime)
  {
    //No, it is not time
    return;
  }


  switch (currentState)
  {
    //*************
    case '1':
      {
        //Start watering
        digitalWrite(13, HIGH);   // turn the water on
        Serial.println("Start watering");
        myRelayMillis = millis();
        waitTime = 5000;
      }
      break;

    //*************
    case '2':
      {
        //Stop watering when timing is over
        Serial.println("Stop watering");
        digitalWrite(13, LOW);    // turn the water off
        myRelayMillis = millis();
        waitTime = 5000;
      }
      break;

    //*************
    case '3':
      {
        //Water for 1 hour
        Serial.println("Water for 1 hour");
        myRelayMillis = millis();
        waitTime = 5000ul;  //testing
        //waitTime = 1 * 60 * 60 * 1000ul;
        digitalWrite(13, HIGH);   // turn the water on

        //Stop watering when timing is over
        currentState = '2';
      }
      break;

    //*************
    case '4':
      {
        //Water for 2 hours
        Serial.println("Water for 2 hours");
        myRelayMillis = millis();
        //waitTime = 10000;  //testing
        waitTime = 2 * 60 * 60 * 1000ul;
        digitalWrite(13, HIGH);   // turn the water on

        //Stop watering when timing is over
        currentState = '2';
      }
      break;

    //*************
    case '5':
      {
        //Water for 3hours
        Serial.println("Water for 3 hours");
        digitalWrite(13, HIGH);   // turn the water on
        myRelayMillis = millis();
        //waitTime = 15000;  //testing
        waitTime = 3 * 60 * 60 * 1000ul;

        //Stop watering when timing is over
        currentState = '2';
      }
      break;

  } //END of switch/case

} //END of function

//***************************************************

.

larryd:
It is my guess your Bluetooth sends more than one character, perhaps a \r at the end of a transmission.

Try this, it refuses characters not equal to '1'-'5'.

#include <SoftwareSerial.h>// import the serial library

SoftwareSerial bluetooth(3, 4); // RX, TX
const int relayPin =  13;
unsigned long currentMillis;
unsigned long myRelayMillis;
unsigned long waitTime = 0;
char bluetoothData; // the data given from mobile app
boolean newData = false;
char currentState;

//***************************************************
void setup()
{
  bluetooth.begin(9600);
  pinMode(relayPin, OUTPUT);
  Serial.begin (9600); //uncomment for debugging
}

//***************************************************
void loop()
{

currentMillis = millis(); //for milli second timing

recvOneChar();
  controlWater();
}

//***************************************************
void recvOneChar()
{
  if (bluetooth.available() > 0)
  {
    bluetoothData = bluetooth.read();
       
    //limit BT data to '1'-'5'
    if (bluetoothData > '0' && bluetoothData < '6')
    {
      newData = true;
      currentState = bluetoothData;     
    }
  }

}

//***************************************************
void controlWater()
{
  if (newData == true)
  {
    //cancel the timer as a new command has come in
    waitTime = 0;
    newData = false;
    myRelayMillis = millis();
  }

//is it time to process the next state code?
  if (currentMillis - myRelayMillis < waitTime)
  {
    //No, it is not time
    return;
  }

switch (currentState)
  {
    //*************
    case '1':
      {
        //Start watering
        digitalWrite(13, HIGH);  // turn the water on
        Serial.println("Start watering");
        myRelayMillis = millis();
        waitTime = 5000;
      }
      break;

//*************
    case '2':
      {
        //Stop watering when timing is over
        Serial.println("Stop watering");
        digitalWrite(13, LOW);    // turn the water off
        myRelayMillis = millis();
        waitTime = 5000;
      }
      break;

//*************
    case '3':
      {
        //Water for 1 hour
        Serial.println("Water for 1 hour");
        myRelayMillis = millis();
        waitTime = 5000ul;  //testing
        //waitTime = 1 * 60 * 60 * 1000ul;
        digitalWrite(13, HIGH);  // turn the water on

//Stop watering when timing is over
        currentState = '2';
      }
      break;

//*************
    case '4':
      {
        //Water for 2 hours
        Serial.println("Water for 2 hours");
        myRelayMillis = millis();
        //waitTime = 10000;  //testing
        waitTime = 2 * 60 * 60 * 1000ul;
        digitalWrite(13, HIGH);  // turn the water on

//Stop watering when timing is over
        currentState = '2';
      }
      break;

//*************
    case '5':
      {
        //Water for 3hours
        Serial.println("Water for 3 hours");
        digitalWrite(13, HIGH);  // turn the water on
        myRelayMillis = millis();
        //waitTime = 15000;  //testing
        waitTime = 3 * 60 * 60 * 1000ul;

//Stop watering when timing is over
        currentState = '2';
      }
      break;

} //END of switch/case

} //END of function

//***************************************************




.

YES Now it works as i want :slight_smile: :slight_smile: :slight_smile: :slight_smile:
Many many thanks

Memnon:
YES Now it works as i want :slight_smile: :slight_smile: :slight_smile: :slight_smile:
Many many thanks

We sometimes have an argument here about whether using the delay() function is a good thing for new people to learn about.
In this case, your original sketch did use delay() which hid a few potential bugs as it freezes code execution.
In this case it didn’t read the extra BT characters that are sent at the end of the message.
Once delay() was removed, the controller is fast enough to process all characters that arrive, hence screwing up receive logic.
We therefore had to limit the received characters to 1-5.
==========================================================
Now it’s your turn.
For payment, you must answer the questions below:
waitTime = 0; <----<<<< Explain why this is necessary:

  if (newData == true)
  {
    //cancel the timer as a new command has come in
    waitTime = 0;
    newData = false;
    myRelayMillis = millis();
  }

  //is it time to process the next state code?
  if (currentMillis - myRelayMillis < waitTime)
  {
    //No, it is not time
    return;
  }

What do these lines do?
myRelayMillis = millis(); //<----<<<<

    case '1':
      {
        // Start watering

        digitalWrite(13, HIGH);   // turn the water on
        Serial.println("Start watering");
        myRelayMillis = millis(); //<----<<<< 
        waitTime = 5000;
      }
      break;

    case '2':
      {
        //Stop watering when timing is over
        Serial.println("Stop watering");
        digitalWrite(13, LOW);    // turn the water off
        myRelayMillis = millis();  //<----<<<< 
        waitTime = 5000;
      }
      break;

What do these lines do for the code?
myRelayMillis = millis();
waitTime = 5000;

//*************
    case '2':
      {
        //Stop watering when timing is over
        Serial.println("Stop watering");
        digitalWrite(13, LOW);    // turn the water off
        myRelayMillis = millis();
        waitTime = 5000;
      }

What does this line do?
Why is it necessary?
currentState = bluetoothData;

void recvOneChar()
{
  if (bluetooth.available() > 0)
  {
    bluetoothData = bluetooth.read();

    //limit BT data to '1'-'5'
    if (bluetoothData > '0' && bluetoothData < '6')
    {
      newData = true;
      currentState = bluetoothData;
    }
  }

}

If you turn on the water by sending a ‘1’ to the Arduino how can you make sure it will not keep running forever if you walk away?

    //**********************
    case '1':
      {
        //Start watering
        digitalWrite(13, HIGH);   // turn the water on
        Serial.println("Start watering");
        myRelayMillis = millis();
        //every 1/2 second
        waitTime = 500;
      }
      break;

larryd:
We sometimes have an argument here about whether using the delay() function is a good thing for new people to learn about.
In this case, your original sketch did use delay() which hid a few potential bugs as it freezes code execution.
In this case it didn’t read the extra BT characters that are sent at the end of the message.
Once delay() was removed, the controller is fast enough to process all characters that arrive, hence screwing up receive logic.
We therefore had to limit the received characters to 1-5.
==========================================================
Now it’s your turn.
For payment, you must answer the questions below:
waitTime = 0; <----<<<< Explain why this is necessary: Cancel current timer to recive new data

  if (newData == true)

{
    //cancel the timer as a new command has come in
    waitTime = 0;
    newData = false;
    myRelayMillis = millis();
  }

//is it time to process the next state code?
  if (currentMillis - myRelayMillis < waitTime)
  {
    //No, it is not time
    return;
  }




**What do these lines do? capture the latest value of millis** 
**myRelayMillis = millis(); //<----<<<<** 



case '1':
      {
        // Start watering

digitalWrite(13, HIGH);  // turn the water on
        Serial.println("Start watering");
        myRelayMillis = millis(); //<----<<<<
        waitTime = 5000;
      }
      break;

case '2':
      {
        //Stop watering when timing is over
        Serial.println("Stop watering");
        digitalWrite(13, LOW);    // turn the water off
        myRelayMillis = millis();  //<----<<<<
        waitTime = 5000;
      }
      break;




**What do these lines do for the code? Im not sure about this one.**
**myRelayMillis = millis();**
**waitTime = 5000;** 



//*************
    case '2':
      {
        //Stop watering when timing is over
        Serial.println("Stop watering");
        digitalWrite(13, LOW);    // turn the water off
        myRelayMillis = millis();
        waitTime = 5000;
      }





**What does this line do?**
**Why is it necessary?**
**currentState = bluetoothData; it tells what state to go to from recived bluetooth data**



void recvOneChar()
{
  if (bluetooth.available() > 0)
  {
    bluetoothData = bluetooth.read();

//limit BT data to '1'-'5'
    if (bluetoothData > '0' && bluetoothData < '6')
    {
      newData = true;
      currentState = bluetoothData;
    }
  }

}





**If you turn on the water by sending a ‘1’ to the Arduino how can you make sure it will not keep running forever if you walk away?**
we can set a timer on it like the other states, but higher. Lets say 5hours max


//**********************
    case '1':
      {
        //Start watering
        digitalWrite(13, HIGH);  // turn the water on
        Serial.println("Start watering");
        myRelayMillis = millis();
        //every 1/2 second
        waitTime = 500;
      }
      break;

waitTime = 0; <----<<<< Explain why this is necessary:
Cancel current timer to recive new data
Yes and this is necessary as we want to ensure the timing check falls through the following 'if' statement.

if (newData == true)
{
 //cancel the timer as a new command has come in
 waitTime = 0;
 newData = false;
 myRelayMillis = millis();
}

//is it time to process the next state code?
if (currentMillis - myRelayMillis < waitTime)
{
 //No, it is not time
 return;
}

What do these lines do?
capture the latest value of millis
It does do that but more important, it resets the timing
i.e. if we set myRelayMillis = millis() then the math that follows is:
millis() - millis() < 0, which restarts the timing sequence.

myRelayMillis = millis(); //<----<<<<

case '1':
   {
     // Start watering

     digitalWrite(13, HIGH);   // turn the water on
     Serial.println("Start watering");
     myRelayMillis = millis(); //<----<<<< 
     waitTime = 5000;
   }
   break;

 case '2':
   {
     //Stop watering when timing is over
     Serial.println("Stop watering");
     digitalWrite(13, LOW);    // turn the water off
     myRelayMillis = millis();  //<----<<<< 
     waitTime = 5000;
   }
   break;

What do these lines do for the code? Im not sure about this one.
myRelayMillis = millis();
waitTime = 5000;

Without these two lines the case '1' and case '2' would update at microsecond speed.
Now there is nothing wrong with this, however it slows program execution down.
waitTime = 5000 sets the timer to 5 seconds or in other words, the case will run every 5 second.
This is more than adequate, hence the water is turned OFF every 5 seconds as in this case.

//*************
 case '2':
   {
     //Stop watering when timing is over
     Serial.println("Stop watering");
     digitalWrite(13, LOW);    // turn the water off
     myRelayMillis = millis();
     waitTime = 5000;
   }

What does this line do?
Why is it necessary?
currentState = bluetoothData; it tells what state to go to from recived bluetooth data
Yes but more important if we used 'switch (bluetoothData)' instead of 'switch (currentState)'
a BT received character such as '\r' or '\n' would mess our logic flow up.

void recvOneChar()
{
if (bluetooth.available() > 0)
{
 bluetoothData = bluetooth.read();

 //limit BT data to '1'-'5'
 if (bluetoothData > '0' && bluetoothData < '6')
 {
   newData = true;
   currentState = bluetoothData;
 }
}

}

If you turn on the water by sending a '1' to the Arduino how can you make sure it will not keep running forever if you walk away?
we can set a timer on it like the other states, but higher. Lets say 5 hours max
Yes, I would suggest you do something like this:
myRelayMillis = millis();
//set maximum on time to 5 hours
waitTime = 56060*1000ul;
//Stop watering when timing is over
currentState = '2';

//**********************
 case '1':
   {
     //Start watering
     digitalWrite(13, HIGH);   // turn the water on
     Serial.println("Start watering");
     myRelayMillis = millis();
     //every 1/2 second
     waitTime = 500;
   }
   break;

Would you do me a favor and check this works with your BT module.

Note: add a LED with a 220R resistor on pin D12 going to GND
This LED is a heart beat LED and shows you the code is executing.

Please give us a link to the BT module that you are using.

#include <SoftwareSerial.h>

SoftwareSerial bluetooth(3, 4);

const int relayPin     = 13;
const int heartBeatLED = 12;

unsigned long currentMillis;
unsigned long myRelayMillis;
unsigned long heartBeatMillis;
unsigned long heartBeatDelay = 500ul;
unsigned long waitTime       = 1000ul;
unsigned long maxTime        = 4 * 60 * 60 * 1000ul;

char bluetoothData;      //the data given from mobile app
char currentState = '2'; //startup by stoping watering

boolean newData = false;

//*****************************************************************
void setup()
{
  bluetooth.begin(9600);

  //connect a relay circuit to the relayPin
  pinMode(relayPin, OUTPUT);
  //connect a LED from the pin to GND through a 220R resistor
  pinMode(heartBeatLED, OUTPUT);

  Serial.begin (9600);

} //END of                s e t u p ( )

//*****************************************************************
void loop()
{
  currentMillis = millis(); //for milli second timing

  //***************************
  //some code to see if the sketch is blocking
  //toggle the heartBeatLED every 1/2 second
  if (currentMillis - heartBeatMillis >= heartBeatDelay)
  {
    //reset the timing
    heartBeatMillis = heartBeatMillis + heartBeatDelay;

    //toggle the heartBeatLED
    digitalWrite(heartBeatLED, !digitalRead(heartBeatLED));
  }

  //None blocking code goes here
  //***************************
  recvOneChar();
  controlWater();

} //END of                 l o o p ( )


//*****************************************************************
void recvOneChar()
{
  //Debug using the Serial monitor
  //if (Serial.available() > 0)
  //{
  //  bluetoothData = Serial.read();

  //using BlueTooth
  if (bluetooth.available() > 0)
  {
    bluetoothData = bluetooth.read();

    //limit BT data to '1' through '5'
    if (bluetoothData > '0' && bluetoothData < '6')
    {
      newData = true;
      currentState = bluetoothData;
    }
  }

} //END of            r e c v O n e C h a r ( )


//*****************************************************************
void controlWater()
{
  //**********************
  //was there new data received
  if (newData == true)
  {
    //cancel the timer as a new command has come in
    newData  = false;
    waitTime = 0;
    myRelayMillis = millis();
  }

  //**********************
  //is it time to process the next state code?
  if (currentMillis - myRelayMillis < waitTime)
  {
    //No, it is not time
    return;
  }

  //***********************************************
  switch (currentState)
  {
    //**********************
    case '1':
      {
        //Start watering
        digitalWrite(13, HIGH);   // turn the water on
        Serial.println("Start watering");

        //reset the timer
        myRelayMillis = millis();

        //maximum of 4 hours allowed
        waitTime = maxTime;

        //Stop watering when timing is over
        currentState = '2';
      }
      break;

    //**********************
    case '2':
      {
        //Stop watering
        Serial.println("Stop watering");
        digitalWrite(13, LOW);    // turn the water off

        //reset the timer
        myRelayMillis = millis();

        //every 1/2 second
        waitTime = 500;
      }
      break;

    //**********************
    case '3':
      {
        //Water for 1 hour
        Serial.println("Water for 1 hour");

        //reset the timer
        myRelayMillis = millis();

        waitTime = 5000ul;  //debug
        //waitTime = 1 * 60 * 60 * 1000ul;
        digitalWrite(13, HIGH);   // turn the water on

        //Stop watering when timing is over
        currentState = '2';
      }
      break;

    //**********************
    case '4':
      {
        //Water for 2 hours
        Serial.println("Water for 2 hours");

        //reset the timer
        myRelayMillis = millis();

        waitTime = 10000;  //debug
        //waitTime = 2 * 60 * 60 * 1000ul;
        digitalWrite(13, HIGH);   // turn the water on

        //Stop watering when timing is over
        currentState = '2';
      }
      break;

    //**********************
    case '5':
      {
        //Water for 3 hours
        Serial.println("Water for 3 hours");
        digitalWrite(13, HIGH);   // turn the water on

        //reset the timer
        myRelayMillis = millis();

        waitTime = 15000;  //debug
        //waitTime = 3 * 60 * 60 * 1000ul;

        //Stop watering when timing is over
        currentState = '2';
      }
      break;

    default:
      {
        //default stuff here
      }
      break;

  } //END of switch/case

} //END of             c o n t r o l W a t e r ( )

//*****************************************************************

larryd:
Would you do me a favor and check this works with your BT module.

Note: add a LED with a 220R resistor on pin D12 going to GND
This LED is a heart beat LED and shows you the code is executing.

Please give us a link to the BT module that you are using.

#include <SoftwareSerial.h>

SoftwareSerial bluetooth(3, 4);

const int relayPin     = 13;
const int heartBeatLED = 12;

unsigned long currentMillis;
unsigned long myRelayMillis;
unsigned long heartBeatMillis;
unsigned long heartBeatDelay = 500ul;
unsigned long waitTime       = 1000ul;
unsigned long maxTime        = 4 * 60 * 60 * 1000ul;

char bluetoothData;      //the data given from mobile app
char currentState = '2'; //startup by stoping watering

boolean newData = false;

//*****************************************************************
void setup()
{
 bluetooth.begin(9600);

//connect a relay circuit to the relayPin
 pinMode(relayPin, OUTPUT);
 //connect a LED from the pin to GND through a 220R resistor
 pinMode(heartBeatLED, OUTPUT);

Serial.begin (9600);

} //END of                s e t u p ( )

//*****************************************************************
void loop()
{
 currentMillis = millis(); //for milli second timing

//***************************
 //some code to see if the sketch is blocking
 //toggle the heartBeatLED every 1/2 second
 if (currentMillis - heartBeatMillis >= heartBeatDelay)
 {
   //reset the timing
   heartBeatMillis = heartBeatMillis + heartBeatDelay;

//toggle the heartBeatLED
   digitalWrite(heartBeatLED, !digitalRead(heartBeatLED));
 }

//None blocking code goes here
 //***************************
 recvOneChar();
 controlWater();

} //END of                 l o o p ( )

//*****************************************************************
void recvOneChar()
{
 //Debug using the Serial monitor
 //if (Serial.available() > 0)
 //{
 //  bluetoothData = Serial.read();

//using BlueTooth
 if (bluetooth.available() > 0)
 {
   bluetoothData = bluetooth.read();

//limit BT data to '1' through '5'
   if (bluetoothData > '0' && bluetoothData < '6')
   {
     newData = true;
     currentState = bluetoothData;
   }
 }

} //END of            r e c v O n e C h a r ( )

//*****************************************************************
void controlWater()
{
 //**********************
 //was there new data received
 if (newData == true)
 {
   //cancel the timer as a new command has come in
   newData  = false;
   waitTime = 0;
   myRelayMillis = millis();
 }

//**********************
 //is it time to process the next state code?
 if (currentMillis - myRelayMillis < waitTime)
 {
   //No, it is not time
   return;
 }

//***********************************************
 switch (currentState)
 {
   //**********************
   case '1':
     {
       //Start watering
       digitalWrite(13, HIGH);   // turn the water on
       Serial.println("Start watering");

//reset the timer
       myRelayMillis = millis();

//maximum of 4 hours allowed
       waitTime = maxTime;

//Stop watering when timing is over
       currentState = '2';
     }
     break;

//**********************
   case '2':
     {
       //Stop watering
       Serial.println("Stop watering");
       digitalWrite(13, LOW);    // turn the water off

//reset the timer
       myRelayMillis = millis();

//every 1/2 second
       waitTime = 500;
     }
     break;

//**********************
   case '3':
     {
       //Water for 1 hour
       Serial.println("Water for 1 hour");

//reset the timer
       myRelayMillis = millis();

waitTime = 5000ul;  //debug
       //waitTime = 1 * 60 * 60 * 1000ul;
       digitalWrite(13, HIGH);   // turn the water on

//Stop watering when timing is over
       currentState = '2';
     }
     break;

//**********************
   case '4':
     {
       //Water for 2 hours
       Serial.println("Water for 2 hours");

//reset the timer
       myRelayMillis = millis();

waitTime = 10000;  //debug
       //waitTime = 2 * 60 * 60 * 1000ul;
       digitalWrite(13, HIGH);   // turn the water on

//Stop watering when timing is over
       currentState = '2';
     }
     break;

//**********************
   case '5':
     {
       //Water for 3 hours
       Serial.println("Water for 3 hours");
       digitalWrite(13, HIGH);   // turn the water on

//reset the timer
       myRelayMillis = millis();

waitTime = 15000;  //debug
       //waitTime = 3 * 60 * 60 * 1000ul;

//Stop watering when timing is over
       currentState = '2';
     }
     break;

default:
     {
       //default stuff here
     }
     break;

} //END of switch/case

} //END of             c o n t r o l W a t e r ( )

//*****************************************************************

Yes this code works fine. LED is pulsating

Link for bluetooth module

Thank you.

Suggest you 'not' use delay() in your future sketches unless its rarely executed and only for a short period of time such as delay(10); (10 milliseconds).

Good luck with the project.

.

I looked into the OP's sketch and had an idea to move most of the logic in the watering control over to the user input. That turns the user input into processed user input and the watering control into an easily interrupted watering timer.

Example uses serial monitor IO (no BT) and led13 (no relay) to show watering with timed 1, 3, and 5 second periods.
Check the time stamps in the output to show actions matching commands. Note that 1 turns the water on w/o timer.

// test of watering sketch

// test does not require BT and I have no BT to check that with so for now no BT
// #include <SoftwareSerial.h>// import the serial library
// SoftwareSerial bluetooth(3, 4); // RX, TX
char bluetoothData; // the data given from mobile app

const int relayPin =  13;

unsigned long wateringStartMs = 0;
unsigned long wateringPeriod = 0;


void setup() 
{
  //  bluetooth.begin( 9600 );             // can it not run faster?
  pinMode( relayPin, OUTPUT );
  Serial.begin ( 9600 ); //uncomment for debugging
}

void loop() 
{
  userCommand();
  waterTimer();
}


inline void userCommand() // convert user input into control values
{

  if ( Serial.available() > 0 ) 
  {
    bluetoothData = Serial.read();
    Serial.print(F( "user input 0x" ));
    Serial.print( bluetoothData, HEX );
    Serial.println(F( " hex" ));

    switch (bluetoothData) 
    {

    case '1': 
      { 
        digitalWrite( relayPin, HIGH );   // turn the water on
        Serial.print( millis());
        Serial.println(F( " Command start watering with no timer." ));
        wateringPeriod = 0; // does not use the timer, shuts timer off
      }
      break;

    case '2': 
      { 
        Serial.print( millis());
        Serial.println(F( " Stop watering" ));
        digitalWrite( relayPin, LOW );    // turn the water off
        wateringPeriod = 0; // shuts timer off
      }
      break;

    case '3':  
      { 
        Serial.print( millis());
        Serial.println(F( " Water for 1 second" ));
        digitalWrite( relayPin, HIGH );    // turn the water on
        wateringPeriod = 1000;    // wait for x second
        wateringStartMs = millis();
      }
      break;

    case '4': 
      { 
        Serial.print( millis());
        Serial.println(F( " Water for 3 seconds" ));
        digitalWrite( relayPin, HIGH );    // turn the water on
        wateringPeriod = 3000;    // wait for x second
        wateringStartMs = millis();
      }
      break;

    case '5':  
      { 
        Serial.print( millis());
        Serial.println(F( " Water for 5 seconds" ));
        digitalWrite( relayPin, HIGH );    // turn the water on
        wateringPeriod = 5000;    // wait for x second
        wateringStartMs = millis();
      }
      break;
    }

  }
}

inline void waterTimer() 
{
  if ( wateringPeriod > 0 ) 
  {
    if ( millis() - wateringStartMs < wateringPeriod )
    {
      return;  // keep watering
    }
    else
    {
      Serial.print( millis());
      Serial.println(F( " Watering time is over" ));
      digitalWrite( relayPin, LOW );    // turn the water off
      wateringPeriod = 0;
      return;
    }
  }
}
inline void userCommand() // convert user input into control values

static is a better choice than inline. It keeps the name out of the global scope avoiding any potential conflicts and the compiler does a fine job of choosing when to inline.

Liberal use of static to keep things out of the global scope is always a good choice.

TYVM CB! Karma for you!

All I remembered was that inline meant don't make this a call and return function.

GoForSmoke:
TYVM CB! Karma for you!

You are welcome!

All I remembered was that inline meant don't make this a call and return function.

In my experience with avr-gcc inline is useless: the compiler is very aggressive about inlining and always will if it makes sense.

The opposite is actually true. If the compiler inlines and the function should not be it is rather annoying to get it to stop.

This compiler is a bit of a pain at times. I learn much to avoid as well as to do and then some new version shifts things seemingly just to keep it fresh so we won't get bored.

But nah, really it is improvements! By 1.6 I no longer regretted leaving 0023.