BLYNK
BLYNK.IO       📲 GETTING STARTED       📗 DOCS       👉 SKETCH BUILDER

Simple 4 relay irrigation scheduler

Hi All.
I am new to blynk and needed a simple scheduler for my home irrigation system using 4 relay device (sonoff 4ch pro).
The device receives for each relay, duration time (V16…V19), and 4 optional start times (and active days) using the time input widget(V0…V3 for relay 0 V4…V7 for relay 1 … ) .
Also at the app for each relay I have a button (V20…V23) that enables activating the relay immediately (the relay will turn off after the configured duration time).

since I could not find BLYNK code that match my requirements I wrote one and am sharing it here if anyone finds it useful.

/*************************************************************
  Download latest Blynk library here:
    https://github.com/blynkkk/blynk-library/releases/latest

  Blynk is a platform with iOS and Android apps to control
  Arduino, Raspberry Pi and the likes over the Internet.
  You can easily build graphic interfaces for all your
  projects by simply dragging and dropping widgets.

    Downloads, docs, tutorials: http://www.blynk.cc
    Sketch generator:           http://examples.blynk.cc
    Blynk community:            http://community.blynk.cc
    Follow us:                  http://www.fb.com/blynkapp
                                http://twitter.com/blynk_app

  Blynk library is licensed under MIT license
  This example code is in public domain.

 *************************************************************
  This example runs directly on ESP8266 chip.

  Note: This requires ESP8266 support package:
    https://github.com/esp8266/Arduino

  Please be sure to select the right ESP8266 module
  in the Tools -> Board menu!

  Change WiFi ssid, pass, and Blynk auth token to run :)
  Feel free to apply it to any other example. It's simple!
 *************************************************************/

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial
#define WIFI_LED 13

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <TimeLib.h>
#include <WidgetRTC.h>

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "xxxxxx";
char pass[] = "xxxxxxxxxxxx";

byte switch_pins[] = {12 , 5 , 4 , 15}; // number of gpio to be used as switch/relay control


/////////////////////////////////////////////////////////////////////
// this code can control up to 4 switches                          //
// for each switch up to 4 schedule start times can be configured  //
// for each switch one duration is used (when schedule time is     //
//    reached the switch turns on for the duration)                //
/////////////////////////////////////////////////////////////////////
int start_time_sec[4][4];   // array of 4 start times (in seconds) for 4 switches [switch number][schedule timer number]
bool start_valid[4][4];     // is the start time valid ?
bool weekdays[4][4][8];     // array of 8 days (day 0 not used) for each schedule time
byte active_duration[4];    // duration per switch (in minuets)
bool wifi_led_status = false;

// when activating a switch a timer is set for the configured duration
// when the duration ends the switch is turned off by the timer
// the number of the timer is saved using end_timer_id
// if switch is manualy turned off the end_timer_id is used to stop the timer.
int end_timer_id[4] = {32, 32, 32, 32};

// timer object declaration
BlynkTimer timer;

// this code use Real Time Clock widget in the blynk app to keep the clock updated from net
WidgetRTC rtc;


BLYNK_CONNECTED() {
  // Synchronize time on connection
  rtc.begin();
  Blynk.syncAll();
}

//////////////////////////////////////////////////////////
// get schedual parameters from App                     //
//////////////////////////////////////////////////////////
void set_time(BlynkParam param, byte switch_no, byte time_no){

     TimeInputParam t(param);
  // Process start time

  if (t.hasStartTime())
  {
    
    Serial.println(String("Start: ") +
                   t.getStartHour() + ":" +
                   t.getStartMinute() + ":" +
                   t.getStartSecond());
    Serial.println(String("Start in sec: ") + param[0].asLong() + String(" for switch") + switch_no + String(" time_no: ") + time_no);
    start_time_sec[switch_no][time_no]= param[0].asLong();
    start_valid[switch_no][time_no] = true;


  }
  else
  {
    // Do nothing
    Serial.println(String("No Start Time Given for switch: ") + switch_no + String(" time_no: ") + time_no);
    start_valid[switch_no][time_no] = false;
  }

 
  // Process weekdays (1. Mon, 2. Tue, 3. Wed, ...)

  for (int i = 1; i <= 7; i++) {
    if (t.isWeekdaySelected(i)) {
      Serial.println(String("Day ") + i + " is selected");
      weekdays[switch_no][time_no][i] = true;
    }
    else {
      weekdays[switch_no][time_no][i] = false;
    }
    
  }

    Serial.println();

}


BLYNK_WRITE(V0)  { set_time(param, 0,0);  }
BLYNK_WRITE(V1)  { set_time(param, 0,1);  }
BLYNK_WRITE(V2)  { set_time(param, 0,2);  }
BLYNK_WRITE(V3)  { set_time(param, 0,3);  }

BLYNK_WRITE(V4)  { set_time(param, 1,0);  }
BLYNK_WRITE(V5)  { set_time(param, 1,1);  }
BLYNK_WRITE(V6)  { set_time(param, 1,2);  }
BLYNK_WRITE(V7)  { set_time(param, 1,3);  }

BLYNK_WRITE(V8)  { set_time(param, 2,0);  }
BLYNK_WRITE(V9)  { set_time(param, 2,1);  } 
BLYNK_WRITE(V10) { set_time(param, 2,2);  }
BLYNK_WRITE(V11) { set_time(param, 2,3);  }

BLYNK_WRITE(V12) { set_time(param, 3,0);  }
BLYNK_WRITE(V13) { set_time(param, 3,1);  }
BLYNK_WRITE(V14) { set_time(param, 3,2);  }
BLYNK_WRITE(V15) { set_time(param, 3,3);  }





BLYNK_WRITE(V16) { active_duration[0] = param.asInt(); }
BLYNK_WRITE(V17) { active_duration[1] = param.asInt(); }
BLYNK_WRITE(V18) { active_duration[2] = param.asInt(); }
BLYNK_WRITE(V19) { active_duration[3] = param.asInt(); }

/////////////////////////////////////////////////////////////////
// Handle switch events (from app or from scheduler )          //
/////////////////////////////////////////////////////////////////

// turn off switch after active duration ends
void turn_off_switch_no_0(){ turn_on_off(0,0); Blynk.virtualWrite(V20,0); Serial.println(String("timer turn off switch 0 ") );}
void turn_off_switch_no_1(){ turn_on_off(0,1); Blynk.virtualWrite(V21,0); Serial.println(String("timer turn off switch 1 ") );}
void turn_off_switch_no_2(){ turn_on_off(0,2); Blynk.virtualWrite(V22,0); Serial.println(String("timer turn off switch 2 ") );}
void turn_off_switch_no_3(){ turn_on_off(0,3); Blynk.virtualWrite(V23,0); Serial.println(String("timer turn off switch 3 ") );}

// handle switch state
void turn_on_off(int on_off, byte switch_no){
    if (on_off==1) 
    {
      
      digitalWrite(switch_pins[switch_no],HIGH);
      long active_duration_ms = ((long)active_duration[switch_no])*60000;
      
      switch (switch_no) {
        case 0: 
          Blynk.virtualWrite(V20,1);
          end_timer_id[0]=timer.setTimeout(active_duration_ms, turn_off_switch_no_0);
          
         break;
        case 1: 
          Blynk.virtualWrite(V21,1);
          end_timer_id[1]=timer.setTimeout(active_duration_ms, turn_off_switch_no_1);
         break;
        case 2: 
          Blynk.virtualWrite(V22,1);
          end_timer_id[2]=timer.setTimeout(active_duration_ms, turn_off_switch_no_2);
         break;
        case 3: 
          Blynk.virtualWrite(V23,1);
          end_timer_id[3]=timer.setTimeout(active_duration_ms, turn_off_switch_no_3);
         break;    
      } 
      Serial.println(String("turn ON switch: ") + switch_no);
    }
    else 
    {
      digitalWrite(switch_pins[switch_no],LOW);
      timer.deleteTimer(end_timer_id[switch_no]);
      end_timer_id[switch_no]=32;
      Serial.println(String("turn OFF switch: ") + switch_no);
      

    }   
}

// set switch state from APP
BLYNK_WRITE(V20) { turn_on_off(param.asInt(),0); }
BLYNK_WRITE(V21) { turn_on_off(param.asInt(),1); }
BLYNK_WRITE(V22) { turn_on_off(param.asInt(),2); }
BLYNK_WRITE(V23) { turn_on_off(param.asInt(),3); }



// schedual events handling
void activetoday(){         // check if schedule #1 should run today

  if(Blynk.connected())
  {
    digitalWrite(WIFI_LED,LOW); 
  }
  else
  {
    wifi_led_status =!wifi_led_status;
    digitalWrite(WIFI_LED,wifi_led_status); 
  }
  
  if(year() != 1970){
    unsigned int nowseconds = ((hour() * 3600) + (minute() * 60) + second());
    int dayadjustment = -1;  
    if(weekday() == 1){
      dayadjustment = 6; // needed for Sunday Time library is day 1 and Blynk is day 7
    }
   
 
     for (int switch_cnt = 0;  switch_cnt<= 3; switch_cnt++) {
         for (int timer_cnt = 0;  timer_cnt<= 3; timer_cnt++) {
              if (start_valid[switch_cnt][timer_cnt] == true) {
                if (weekdays[switch_cnt][timer_cnt][weekday() + dayadjustment]==true){
                  
                   if (nowseconds >= start_time_sec[switch_cnt][timer_cnt]){
                      
                      if(nowseconds < start_time_sec[switch_cnt][timer_cnt]+90){
                        turn_on_off(1,switch_cnt);
                        Serial.println(String("turn ON switch: ") + switch_cnt);

                      }
                   }
                }
              }
         }
      
     }
 
  } 
}

/////////////////////////////////////
// BLYNK 
void setup()
{
  // Debug console
  Serial.begin(9600);
  for (int i = 0; i<4 ; i++){
    pinMode(switch_pins[i], OUTPUT);
    
  }
  pinMode(WIFI_LED, OUTPUT);


  
  Blynk.begin(auth, ssid, pass);
  timer.setInterval(60000L, activetoday);  // check every 60s if ON / OFF trigger time has been reached
  setSyncInterval(10 * 60); // Sync interval in seconds (10 minutes)

}

void loop()
{
  Blynk.run();
  timer.run();
}
9 Likes

@hagay
good job !

What widget did you use to get different start and stop times? How do you set this up in the app? I’ve tried using the eventer widget with no luck.

@Gcsos21 This is from the Time Input Widget

http://docs.blynk.cc/#widgets-interface-time-input

It is simple in it’s own operation, all it does is send preset start/stop times to the device for later processing… but you will need to use a bit of code to make all the magic happen.

You can read more about that here…

1 Like

Thanks for the quick response and advice!

Really nice app @hagay ! Can you add screen from your Blync app? I’m not sure I understand correct layout of timer etc. Here you have my Blynk - I’m don’t know why schedule turn on relay (by high state) but don’t turn off relay after one minute or more.

For duration time (V16…V19) I use a slide (or vertical slider). This means that V16…V19 will receive a simple value from app.
It looks like you are using a time input for the duration time. So you will need some translation from time to simple value.

I use the tabs to separate the relays (that I use for different irrigation zones) .
I currently only use two zones.

Sliders set time in minutes?

Four zones in one screen in attachment

hagay–thank you for the code!!!

I was able to adapt your code to work with LinkNode R4 Relay module with very few modifications.

I added a few features to monitor ESP8266 Clock time (hearbeat and reality check) and a slider to shut the system off when it is raining:

I have one question:
You programmed each zone with 4 start times but with only 1 duration setting for each of those times.

I have been trying to figure out how I can use 4 unique duration times for each of the 4 start times within a given zone. The reason is the dry ground is somewhat hydrophobic–water runs off easily. So if I initially water each zone for 5 minutes and the come back and water a second time for 15 minutes, I get better water absorption.

I tried building an array like you did for the start times but with very little success. Any thoughts on how to integrate a unique time duration for each start time?

Thanks!!

My User interface looks like this for the 4 primary zones:

This shows the basic VPIN assignments I used:

I haven’t had a chance to really play with the app. I basically have a short version. I use push buttons to manually control the sprinklers and eventor to schedule the times.

I made some updates to the code (see below).
following changes made:

  • enable start and end time for each time input.
    if you will not use an end time then the duration will be taken from a single slider (V16…V19) like before

  • added new slider (V24…V27) for max duration
    (I may use this code for activating a boiler and need a safety measure).
    if max duration is less than two min it is ignored!

  • added switch_default array to define the OFF position of the switch (in case you are using reverse polarity)

  • printing the activation time on the activation button (V20…V23)
    (this will help to know when was the switch activated).

I did not fully test so please let me know if you find bugs.

/*************************************************************
  Download latest Blynk library here:
    https://github.com/blynkkk/blynk-library/releases/latest

  Blynk is a platform with iOS and Android apps to control
  Arduino, Raspberry Pi and the likes over the Internet.
  You can easily build graphic interfaces for all your
  projects by simply dragging and dropping widgets.

    Downloads, docs, tutorials: http://www.blynk.cc
    Sketch generator:           http://examples.blynk.cc
    Blynk community:            http://community.blynk.cc
    Follow us:                  http://www.fb.com/blynkapp
                                http://twitter.com/blynk_app

  Blynk library is licensed under MIT license
  This example code is in public domain.

 *************************************************************
  This example runs directly on ESP8266 chip.

  Note: This requires ESP8266 support package:
    https://github.com/esp8266/Arduino

  Please be sure to select the right ESP8266 module
  in the Tools -> Board menu!

  Change WiFi ssid, pass, and Blynk auth token to run :)
  Feel free to apply it to any other example. It's simple!
 *************************************************************/

/* Comment this out to disable prints and save space */
#define BLYNK_PRINT Serial

#define WIFI_LED 13

// define configuration (number of switches and number of timers)
#define SWITCH_CNT 4
#define TIME_CNT 4

#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <TimeLib.h>
#include <WidgetRTC.h>


// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "xxxxxxxxxxxxxxxxxxxxxxxxxx";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "xxxxxxxx";
char pass[] = "xxxxxxxxxxxxx";


byte switch_pins[] = {2 , 5 , 14 , 15}; // number of gpio to be used as switch/relay control

bool switch_default[] = {LOW,HIGH,LOW,HIGH}; // switches that use reverse polarity should be set to HIGH here
////////////////////////////////////////////////////////////////////////////////////////
// This code can contruol up to 4 switches                                            //
// For each switch up to 4 schedual start and end times can be configured - (V0..V15) //
// A default duration can be defined per switch                           - (V16..V19)//
// If an end time is not defined at the app the default duration is used              //
// default duration is also used when manualy activating the switch       - (V20..V23)//
// for each switch when start time is reached the switch turns on for the duration    //
//                                                                                    //
// maximum duration is used for safty (to limit activation time)          - (V24..V27)//
////////////////////////////////////////////////////////////////////////////////////////
int  start_time_sec[SWITCH_CNT][TIME_CNT];     // array of 4 start times (in seconds) for 4 switches [switch number][schedual timer number]
bool start_valid[SWITCH_CNT][TIME_CNT];        // is the start time valid ?
bool weekdays[SWITCH_CNT][TIME_CNT][8];        // array of 8 days (day 0 not used) for each schedual time
int  active_duration[SWITCH_CNT][TIME_CNT+1];  // duration per switch per time(in sec)
bool end_valid[SWITCH_CNT][TIME_CNT];          // is the end time valid ?
int  max_duration[SWITCH_CNT];                 // max duration per switch


// when activating a switch a timer is set for the configured duration
// when the duration ends the switch is turned off by the timer
// the id of the timer is saved using end_timer_id
// if switch is manualy turned off the end_timer_id is used to stop the timer.
// end_timer_id is initialized to 32 (per entry) at the setup section
int end_timer_id[SWITCH_CNT];

// timer object declaration
BlynkTimer timer;

// this code use Real Time Clock widget in the blynk app to keep the clock updated from net
WidgetRTC rtc;


BLYNK_CONNECTED() {
  // Synchronize time on connection
  rtc.begin();
  Blynk.syncAll();
}

//////////////////////////////////////////////////////////
// get schedual parameters from App                     //
//////////////////////////////////////////////////////////
void set_time(BlynkParam param, byte switch_no, byte time_no){

     TimeInputParam t(param);
  // Process start time

  if (t.hasStartTime())
  {
    
    Serial.println(String("Start: ") +
                   t.getStartHour() + ":" +
                   t.getStartMinute() + ":" +
                   t.getStartSecond());
    Serial.println(String("Start in sec: ") + param[0].asLong() + String(" for switch") + switch_no + String(" time_no: ") + time_no);
    start_time_sec[switch_no][time_no]= param[0].asLong();
    start_valid[switch_no][time_no] = true;

  }
  else
  {
    // Do nothing
    Serial.println(String("No Start Time Given for switch: ") + switch_no + String(" time_no: ") + time_no);
    start_valid[switch_no][time_no] = false;
  }



  //////////////////////////////////////////////////////////////////////////////
  // check if end time is received convert and save it as day time in seconds //
  //////////////////////////////////////////////////////////////////////////////
  if (t.hasStopTime())
  {
    
    Serial.println(String("Stop: ") +
                   t.getStopHour() + ":" +
                   t.getStopMinute() + ":" +
                   t.getStopSecond());
    Serial.println(String("Stop in sec: ") + param[1].asLong() + String(" for switch") + switch_no + String(" time_no: ") + time_no);

    active_duration[switch_no][time_no] = (param[1].asLong()-start_time_sec[switch_no][time_no]);
    
    // if end time is smaller than start time this means end time is at next day
    if (active_duration[switch_no][time_no]<0) active_duration[switch_no][time_no]=86400+active_duration[switch_no][time_no];
    
    Serial.println(String("Stop duration: ") + active_duration[switch_no][time_no]);

    end_valid[switch_no][time_no] = true;


  }
  else // if end time is not defined //
  {
    // Do nothing
    Serial.println(String("No Stop Time Given for switch: ") + switch_no + String(" time_no: ") + time_no);
    end_valid[switch_no][time_no] = false;
  }

 
  // Process weekdays (1. Mon, 2. Tue, 3. Wed, ...)

  for (int i = 1; i <= 7; i++) {
    if (t.isWeekdaySelected(i)) {
      Serial.println(String("Day ") + i + " is selected");
      weekdays[switch_no][time_no][i] = true;
    }
    else {
      weekdays[switch_no][time_no][i] = false;
    }
    
  }

    Serial.println();

}

// V0..V3 for switch 0, V4..V7 for switch 1 ...
BLYNK_WRITE(V0)  { set_time(param, 0,0);  }
BLYNK_WRITE(V1)  { set_time(param, 0,1);  }
BLYNK_WRITE(V2)  { set_time(param, 0,2);  }
BLYNK_WRITE(V3)  { set_time(param, 0,3);  }

BLYNK_WRITE(V4)  { set_time(param, 1,0);  }
BLYNK_WRITE(V5)  { set_time(param, 1,1);  }
BLYNK_WRITE(V6)  { set_time(param, 1,2);  }
BLYNK_WRITE(V7)  { set_time(param, 1,3);  }

BLYNK_WRITE(V8)  { set_time(param, 2,0);  }
BLYNK_WRITE(V9)  { set_time(param, 2,1);  } 
BLYNK_WRITE(V10) { set_time(param, 2,2);  }
BLYNK_WRITE(V11) { set_time(param, 2,3);  }

BLYNK_WRITE(V12) { set_time(param, 3,0);  }
BLYNK_WRITE(V13) { set_time(param, 3,1);  }
BLYNK_WRITE(V14) { set_time(param, 3,2);  }
BLYNK_WRITE(V15) { set_time(param, 3,3);  }




// use a slider to define default activation duration (slider count in minute)
BLYNK_WRITE(V16) { active_duration[0][TIME_CNT] = param.asInt()*60; }
BLYNK_WRITE(V17) { active_duration[1][TIME_CNT] = param.asInt()*60; }
BLYNK_WRITE(V18) { active_duration[2][TIME_CNT] = param.asInt()*60; }
BLYNK_WRITE(V19) { active_duration[3][TIME_CNT] = param.asInt()*60; }

// use a slider to define default max duration (slider count in minute)
BLYNK_WRITE(V24) { max_duration[0] = param.asInt()*60; }
BLYNK_WRITE(V25) { max_duration[1] = param.asInt()*60; }
BLYNK_WRITE(V26) { max_duration[2] = param.asInt()*60; }
BLYNK_WRITE(V27) { max_duration[3] = param.asInt()*60; }

/////////////////////////////////////////////////////////////////
// Handle switch events (from app or from scheduler )          //
/////////////////////////////////////////////////////////////////

// turn off switch after active duration ends
// duration number is not important here 
void turn_off_switch_no_0(){ turn_on_off(0,0,0); Blynk.virtualWrite(V20,0); Serial.println(String("timer turn off switch 0 ") );}
void turn_off_switch_no_1(){ turn_on_off(0,1,0); Blynk.virtualWrite(V21,0); Serial.println(String("timer turn off switch 1 ") );}
void turn_off_switch_no_2(){ turn_on_off(0,2,0); Blynk.virtualWrite(V22,0); Serial.println(String("timer turn off switch 2 ") );}
void turn_off_switch_no_3(){ turn_on_off(0,3,0); Blynk.virtualWrite(V23,0); Serial.println(String("timer turn off switch 3 ") );}

// handle switch state
void turn_on_off(int on_off, byte switch_no , byte time_no){
    long active_duration_ms ;
    char Time_print[16];
    
    if (on_off==1) 
    {
      // create time as string to print on activation butten
      sprintf(Time_print, "%02d:%02d", hour(), minute());

      // turn on the switch (or off if default is on)
      digitalWrite(switch_pins[switch_no],!switch_default[switch_no]);

      // if end time is valid use the active duration assigned to this time
      // (change to msec will be done later)
      if (end_valid[switch_no][time_no])
         active_duration_ms = ((long)active_duration[switch_no][time_no]);
      else // otherwise use the general time duration
         active_duration_ms = ((long)active_duration[switch_no][4]);

      
      // max duration smaller than two min is not valid
      if ( (max_duration[switch_no]< 120) | (max_duration[switch_no]>active_duration_ms) )
         active_duration_ms = active_duration_ms*1000;
      else
        active_duration_ms = ((long)max_duration[switch_no])*1000;
       

      // if new timer is set before another one ended then disable previous timer
      if (end_timer_id[switch_no]!=32) timer.deleteTimer(end_timer_id[switch_no]);

      // turn on switch and set timer 
      switch (switch_no) {
        case 0: 
          Blynk.setProperty(V20, "onLabel", String(Time_print));
          Blynk.virtualWrite(V20,1);
          end_timer_id[0]=timer.setTimeout(active_duration_ms, turn_off_switch_no_0);
          
         break;
        case 1: 
          Blynk.setProperty(V21, "onLabel", String(Time_print));
          Blynk.virtualWrite(V21,1);
          end_timer_id[1]=timer.setTimeout(active_duration_ms, turn_off_switch_no_1);
         break;
        case 2: 
          Blynk.setProperty(V22, "onLabel", String(Time_print));
          Blynk.virtualWrite(V22,1);
          end_timer_id[2]=timer.setTimeout(active_duration_ms, turn_off_switch_no_2);
         break;
        case 3: 
          Blynk.setProperty(V23, "onLabel", String(Time_print));
          Blynk.virtualWrite(V23,1);
          end_timer_id[3]=timer.setTimeout(active_duration_ms, turn_off_switch_no_3);
         break;    
      } 
      Serial.println(String("turn ON switch: ") + switch_no + String(" for duration: ") + active_duration_ms/60000 + String("min "));
    }
    else 
    {
      digitalWrite(switch_pins[switch_no],switch_default[switch_no]);
      timer.deleteTimer(end_timer_id[switch_no]);
      end_timer_id[switch_no]=32;
      Serial.println(String("turn OFF switch: ") + switch_no);
    }   
}

// set switch state from APP
BLYNK_WRITE(V20) { turn_on_off(param.asInt(),0,TIME_CNT); }
BLYNK_WRITE(V21) { turn_on_off(param.asInt(),1,TIME_CNT); }
BLYNK_WRITE(V22) { turn_on_off(param.asInt(),2,TIME_CNT); }
BLYNK_WRITE(V23) { turn_on_off(param.asInt(),3,TIME_CNT); }

/////////////////////////////////////////////////////////////////////////////////////////////
// the following function is called every 60 seconds by a timer                            //
//  the function checks if a start time is reached and if yes it will call                 //
//   the turn_on_off function (to turn on the switch and set timer for turning off switch) //
/////////////////////////////////////////////////////////////////////////////////////////////
void activetoday(){         // check if schedule #1 should run today

  if(Blynk.connected()) // set wifi led if no connection
  {
    digitalWrite(WIFI_LED,LOW); 
  }
  else
  {
    digitalWrite(WIFI_LED,HIGH); 
  }
  
  if(year() != 1970){
    unsigned int nowseconds = ((hour() * 3600) + (minute() * 60) + second());
    int dayadjustment = -1;  
    if(weekday() == 1){
      dayadjustment = 6; // needed for Sunday Time library is day 1 and Blynk is day 7
    }
   
 
     for (int switch_cnt = 0;  switch_cnt< SWITCH_CNT; switch_cnt++) {
         for (int timer_cnt = 0;  timer_cnt< TIME_CNT; timer_cnt++) {
              if (start_valid[switch_cnt][timer_cnt] == true) {
                if (weekdays[switch_cnt][timer_cnt][weekday() + dayadjustment]==true){
                  
                   if (nowseconds >= start_time_sec[switch_cnt][timer_cnt]){
                      
                      if(nowseconds < start_time_sec[switch_cnt][timer_cnt]+90){
                        turn_on_off(1,switch_cnt,timer_cnt);
                        Serial.println(String("turn ON switch: ") + switch_cnt);

                      }
                   }
                }
              }
         }
      
     }
 
  } 
}

/////////////////////////////////////
// BLYNK 
void setup()
{
  // Debug console
  Serial.begin(9600);
  
  // reset output pins used and system variables
  for (int i = 0; i<SWITCH_CNT ; i++){
    pinMode(switch_pins[i], OUTPUT); // reset output pins
    digitalWrite(switch_pins[i],switch_default[i]); // set switch to default
    end_timer_id[i] = 32;            // reset end timer id's

    for (int j = 0; j<TIME_CNT ; j++)
    {
      end_valid[i][j] = false;       // reset end valid array
    }
    
  }

  
  pinMode(WIFI_LED, OUTPUT);

  
  Blynk.begin(auth, ssid, pass);
  timer.setInterval(60000L, activetoday);  // check every 60s if ON / OFF trigger time has been reached
  setSyncInterval(10 * 60); // Sync interval in seconds (10 minutes)

}

void loop()
{
  Blynk.run();
  timer.run();
}

Thanks @hagay - nice improvement. Please add screen from your Blynk application.

I think now about soil humidity level as a rain sensor.

what app are you using to take phone snapshot ?

it is better to make a clone of your Android Blynk app and attach here the qr code ( stop your project, tap at the nut icon at the top, scroll down, tap Clone )

attaching QR code of my app.
I am currently only using two switches.

2 Likes

Hi @hagay, thank you very much for sharing your project. I was wondering if you could take the time and add some code to include a system on/off button so that if for example when it rains you could turn the timers off with just a press of one button.

I got a not valid code…