timing, display & smart greenhouse

Hi everyone!

I plan to use arduino in smart greenhouse. My question is what is the best way to set up waiting time? Because after I water the flowers arduino should enter the sleep mode at least for ф few hours (it's not needed to check humidity sensors earlier). So, how do I do that? But the main complexity is that I want to use display and preferences menu, so any time I press the menu button arduino should wake up and start listening for new menu commands for a few seconds. It does not matter what will be after menu timeout: continue to sleep or normal working cycle

If you want to wake up an Arduino (which one? you didn’t say) with a button, then it will need to be wired to one of the pins that has that ability. On a Uno, that is pin 2 and 3. On an ESP2866, I believe it is every pin.

Sleep mode is only useful if you are on battery power. Proper use of sleep mode can allow an Arduino to work for months or years on a coin-cell battery.

If you are powered, then just wait until the appropriate time. Since you will probably want to run the watering at a specific time of day and you don't want that time to drift by more than a dozen minutes per year, you should consider using a RTC (Real Time Clock) module.

blh64:
If you want to wake up an Arduino (which one? you didn't say) with a button, then it will need to be wired to one of the pins that has that ability. On a Uno, that is pin 2 and 3. On an ESP2866, I believe it is every pin.

Sorry, I forget to specify more details: arduino nano (ATmega 328P). Will read more about the interrupts

MorganS:
Sleep mode is only useful if you are on battery power. Proper use of sleep mode can allow an Arduino to work for months or years on a coin-cell battery.

If you are powered, then just wait until the appropriate time. Since you will probably want to run the watering at a specific time of day and you don't want that time to drift by more than a dozen minutes per year, you should consider using a RTC (Real Time Clock) module.

Thank you, probably I will not use sleep mode - because I'm powered. So another question, is it okay just to wait for some specific values of millis and then check humidity and light sensors? I already bought RTC module, as I had hoped for him from the beginning. I'm developer, but it's my first "big" arduino project and I don't know if it's okay to write such code, that simply checks the millis() function

millis() is great. The only drawback is that it doesn't stay synchronised to real time. It can drift, by minutes per day in the worst case.

For something that must happen every 30 seconds, then that drift is irrelevant. For testing your watering system, you don't want to wait 24 hours for something to happen, so the drift is also irrelevant.

I think the time.h library can use either RTC or millis() as its timing input. That will get you started without a RTC and it's just one line of code to hook in the RTC when the hardware arrives.

Thank You so much! Solved :slight_smile: If I could use millis for that it's perfect. Also drift is not a problem for me, as I do not need to wait exact time, just several minutes, about an hour and then check light sensors (and turn on the light if needed) and check the menu state.

My question is what is the best way to set up waiting time?

If I could use millis for that it's perfect. Also drift is not a problem for me, as I do not need to wait exact time, just several minutes, about an hour and then check light sensors (and turn on the light if needed) and check the menu state.

You want to use the "Blink without Delay" method which uses a non blocking millis() timer. There is an example in the ide 02 Digital examples and a "sticky" post millis() tutorial at the top of the Programming forum section.

Here’s a basic framework around which you might build something.

It uses three state machines; one for the menu, one for controlling the plant watering and one for controlling the lighting. It’s all theoretical timing for demonstrative purposes but it shows how you might go about doing multiple things (essentially) simultaneously in a context “close-ish” to your project.

It doesn’t use any sleep functionality, rather just millis() timings. Serial debug messages are used to show you it moving around the various state machines.

const byte pinWaterControl = LED_BUILTIN;   //LED simulates water valve
const byte pinMenuSw = 2;                   //menu input
const byte pinLights = 3;                   //light control output
const byte pinLDR = 4;                      //light sensor digital input

byte
    lastMenuSw;
    
void setup() 
{
    Serial.begin(9600);
    
    pinMode( pinLDR, INPUT_PULLUP );
    pinMode( pinMenuSw, INPUT_PULLUP );
    lastMenuSw = digitalRead( pinMenuSw );
    
    pinMode( pinWaterControl, OUTPUT );
    pinMode( pinLights, OUTPUT );

}//setup

void loop() 
{
    ServiceMenuSM();
    WaterControlSM();
    LightControlSM();

}//loop

//
#define TM_READ_MENU_SW         50ul        //time interval between menu switch reads
// state names
#define ST_WAIT_ACTIVATE        0
#define ST_PROCESS_MENU         1
//
void ServiceMenuSM( void )
{
    static unsigned long
        timeMenu = 0;
    unsigned long
        timeNow;
    byte
        menuSw;
    static byte
        stateMenu = ST_WAIT_ACTIVATE;

    timeNow = millis();
    if( (timeNow - timeMenu) < TM_READ_MENU_SW )
        return;

    timeMenu = timeNow;
        
    switch( stateMenu )
    {
            case    ST_WAIT_ACTIVATE:
                //has user pressed menu button down?
                menuSw = digitalRead( pinMenuSw );
                //reading not the same as last time?
                if( menuSw != lastMenuSw )
                {                    
                    lastMenuSw = menuSw;
                    //is it now low?
                    if( menuSw == LOW )
                    {
                        //yes; pin went high to low (press) so move to process menu
                        stateMenu = ST_PROCESS_MENU;
                        
                    }//if
                    
                }//if
                                
            break;

            case    ST_PROCESS_MENU:
                //debug; show processing menu now
                Serial.println( "Processing menu..." );
                
                //do menu processing stuff

                //when done, go back and wait for another menu button press
                timeMenu = timeNow;
                stateMenu = ST_WAIT_ACTIVATE;
                
            break;
        
    }//switch
    
}//ServiceMenuSM

//state times
#define TM_CHECK_HUMIDITY       10000ul     //check humidity every 10-seconds
#define TM_WATER_PLANTS         3000ul      //run water for 3-seconds

//state names
#define ST_CHECK_HUMIDITY       0
#define ST_WATER_PLANTS         1
//
void WaterControlSM( void )
{
    static byte
        stateWater = ST_CHECK_HUMIDITY;
    static unsigned long
        timeDelay = TM_CHECK_HUMIDITY,
        timeWater = 0;
    unsigned long
        timeNow;

    //has time elapsed for action?
    timeNow = millis();
    if( (timeNow - timeWater) < timeDelay )
        return;

    timeWater = timeNow;

    switch( stateWater )
    {
        case    ST_CHECK_HUMIDITY:
            Serial.println( "Checking humidity..." );

            //check humidity
            //if required, turn on water...
            //if( humidity low )
            //{
                //pretend we're turning on the water by turning on an LED
                Serial.println( "Turning on water..." );
                digitalWrite( pinWaterControl, HIGH );
                //and set a timer to run water
                timeDelay = TM_WATER_PLANTS;
                stateWater = ST_WATER_PLANTS;
            //}
            //else
            //{
            //  //set up time to check humidity again and stay in this state
            //  timeDelay = TM_CHECK_HUMIDITY;
            //}
            
        break;

        case    ST_WATER_PLANTS:
            //in this state the time delay for water has run down
            Serial.println( "Turning off water..." );
            //turn off the water
            digitalWrite( pinWaterControl, LOW );
            //and set up for another humidty check
            timeDelay = TM_CHECK_HUMIDITY;
            stateWater = ST_CHECK_HUMIDITY;
            
        break;
        
    }//switch
    
}//WaterControlSM

#define TM_MIN_LIGHT_TIME   10000ul     //lights-on min 10-sec
//
#define ST_LIGHTS_OFF       0
#define ST_LIGHTS_ON        1
//
void LightControlSM( void )
{
    static byte
        stateLights = ST_LIGHTS_OFF;
    static unsigned long
        timeDelay,
        timeLights = 0;
    unsigned long
        timeNow;

    timeNow = millis();
    switch( stateLights )
    {
            case    ST_LIGHTS_OFF:
                //is light sensor showing darkness?
                if( digitalRead( pinLDR ) == LOW )
                {
                    Serial.println( "Turning lights on..." );
                    //yes; set minimum lights on-time...
                    timeLights = timeNow;
                    //...turn on the lights...
                    digitalWrite( pinLights, HIGH );
                    //...and move to on state
                    stateLights = ST_LIGHTS_ON;                    
                    
                }//if
                                
            break;

            case    ST_LIGHTS_ON:
                //if LDR is saying it's still dark enough for lights, refresh the min on-time timer
                if( digitalRead( pinLDR ) == LOW )
                {
                    timeLights = timeNow;
                    
                }//if
                else
                {
                    //when LCD says it's light out, wait for min on-time to expire
                    if( (timeNow - timeLights) >= TM_MIN_LIGHT_TIME )
                    {
                        Serial.println( "Turning lights off..." );
                        //then turn lights off
                        digitalWrite( pinLights, LOW );
                        //and go back to lights-off state
                        stateLights = ST_LIGHTS_OFF;                                            
                        
                    }//if
                    
                }//else
                
            break;
        
    }//switch
    
}//LightControlSM