/*
 * Arduino code for Relay timer with potentiometer and LCD1602 with I2C
 * Version 1.1 Display is added to show the set time
 * 
 * this Arduino sketch makes it possible to control a relay with the set time
 * which is set by the potentiometer
* Watch video instruction for this code: https://youtu.be/BhEIFzFSMuE
* * 
 * Written by Ahmad Shamshiri for Robojax.com on Sunday Oct 18, 2018 
 * at 05:34 in Ajax, Ontario, Canada
 * 
 * Features of Version 1.1
 *    -Set time by rotating potentiometer (variable resistor)
      -SW1 is START switch. By pushing this button the relay will turn ON and the timer is shown on LCD
      -SW2 is RESET switch. The timer can be cancelled any time pressing this switch
      -When the timer is runing, if potentiometer is rotated, it will not affect the remaining time
      -When SW1 is pressed during the run time, the timer is resetted and it will start over again
   Schematic is provided at robo    
 * This code is "AS IS" without warranty or liability. Free to be used as long as you keep this note intact.* 
 * This code has been download from Robojax.com
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see .
 */
 
// start of settings for LCD1602 with I2C
#include  
#include 
// Set the LCD address to 0x27 for a 16 chars and 2 line display
LiquidCrystal_I2C lcd(0x27, 16, 2);
// end of settings for LCD1602 with I2C
#define relayPin 8 // the pin relay is connected
#define potPin  A0 // the pin potentiometer is connected
#define resetPin 3 // the pin where rest switch is connected
#define startPin 2 // the pin where start switch is connected
#define relayType 'L' // Relay trigger type. L for low and H for high
const int maxTime = 720;// maximum timer time in seconds
const int minTime = 10; // miniimum timer time in seconds
// do not change anything bellow here
long duration;// holds the duration of timer
int potValue;// holds the variable resistor (potentiometer) value
long rememTime;// holds current run time
int relayState =0;// holds relay state
void setup() {
  // initialize the LCD
  lcd.init();
  lcd.backlight();// turn the backlight ON for the LCD
    
  pinMode(relayPin, OUTPUT);// define relayPin  as output
  pinMode(resetPin, INPUT_PULLUP);// define input pin with pullup (watch video)
  pinMode(startPin, INPUT_PULLUP);// define input pin with pullup (watch video)
  attachInterrupt(digitalPinToInterrupt(resetPin), reset, LOW);// Interrupt Service Routines. "reset" is a function in this code
    
  Serial.begin(9600);// initialize serial monitor with 9600 baud
  if(relayType == 'L')
  {
    digitalWrite(relayPin, HIGH);// turn the relay OFF and keep it OFF
      lcd.print("UV-Belichter");
      lcd.setCursor(0,1);
      lcd.print("Augenschutz!  ");     
      Serial.println("Robojax Relay 1.1"); 
      Serial.println("Type:LOW Trigger");      
  }else{
    digitalWrite(relayPin, LOW);// turn the relay OFF and keep it OFF
      lcd.print("Robojax Relay1.1");
      lcd.setCursor(0,1);
      lcd.print("Type:H Trigger");     
      Serial.println("Robojax Relay 1.1"); 
      Serial.println("Type:HIGH Trigger");  
  } 
  delay(3000);// change this line if you want not to wait
  lcd.clear();// clearn previous values from screen
}
void loop() {
  // Robojax.com Relay Timer V 1.1 with LCD1602 I2C display
    potValue = analogRead(potPin)/10;// reads the value of the potentiometer (value between 0 and 1023)
    int durationCalc = map(potValue, 0, 102, minTime, maxTime);// convert A0 value to time set at minTime and maxTime
    
    if(digitalRead(startPin) ==LOW)
    {
     duration = durationCalc;
     rememTime = millis()/1000;
     relayState = 1;
     controlRelay();// send command to turn the relay ON
           
    }
   if(  ( millis()/1000- rememTime) > duration )
   {
    relayState = 0;// change relay state to OFF
    controlRelay();// control relay with new relay state
    
   }
      Serial.print("Belichtungszeit:");
      Serial.print(duration);
      Serial.print (" s ");  
 
            
    if(relayState ==1){  
      lcdDisplay(0, "Belichtungszeit ", duration, " s "); 
      lcdDisplay(1, "Rest: ", getRtime(), " s   ");         
      Serial.print(" remain: ");
      Serial.print(getRtime());//
      Serial.print(" s");  
    }else{
      lcdDisplay(0, "Sollzeit: ", durationCalc, " s "); 
      lcdDisplay(1, "UV-Licht AUS          ", 0, " ");         
    }
    Serial.println();  
          
 delay(10); // wait for 200 milliseconds       
}// loop end
/*
 * 
 * @brief Turns the relay ON or OFF 
 * @param none
 * @return no return value
 */
 void controlRelay()
 {
  // Robojax.com Relay Timer V 1.1 with LCD1602 I2C display
  if(relayType == 'L')
  {
     if(relayState == 1)
     {
    digitalWrite(relayPin, LOW);// turns Low-Trigger relay ON
      Serial.print("LT-Relay ON for ");
      Serial.print(duration);// display in seconds
      Serial.println(" Seconds");
     }else{
    digitalWrite(relayPin, HIGH); // turns Low-Trigger relay OFF
      Serial.println("====Relay is OFF");
     }
      
  }else{
    // Robojax.com Relay Timer V 1.1 with LCD1602 I2C display
     if(relayState == 1)
     {    
      digitalWrite(relayPin, HIGH);// turns High-Trigger relay ON
      Serial.print("HT-Relay ON for ");
      Serial.print(duration);// display in seconds
      Serial.println(" Seconds");  
     }else{
      digitalWrite(relayPin, LOW); // turns High-Trigger relay OFF
      Serial.println("==Relay OFF");  
     }  
  }
}//controlRelay end
/*
 * 
 * @brief resets the timer and turns OFF relay
 * @param none
 * @return no return value
 */
void reset()
{
  // Robojax.com Relay Timer V 1.1 with LCD1602 I2C display
  duration =0;
   if(relayType == 'L')
  {
    digitalWrite(relayPin, HIGH);// turn OFF High trigger relay     
  }else{
    digitalWrite(relayPin, LOW);// turn OFF Low trigger relay
  
  } 
  Serial.println("Relay OFF"); 
}//reset()
/*
 * 
 * @brief returns the remaining time set 
 * @param none
 * @return the remaining time as integet second
 */
int getRtime()
{
  // Robojax.com Relay Timer V 1.1 with LCD1602 I2C display
  return duration - (millis()/1000- rememTime);
}
/*
 * lcdDisplay(int tc, int tr, String title, int vc, int vr, float int)
  for example to display
 * tc  is character number  (0)
 * tr is row in the lcd (1)
 * title is the text (Voltage:)
 * vcn character number for value 
 * vr row number for the value
 * value is the value (13.56)
 * 
 * @brief prints text on the screen on specific row and character
 * @param tc=text character number, trc=text row nubmer, 
 * @return the remaining time as integet second
 * usage example for example 
 * to print "Time Set: 34s" on line 2
 * titleText = Time Set:
 * valueText = 34
 * value2Text = S. print 's" as second
 * type this:
 * lcdDisplay(0,"Time Set: ",  34,   "S");
 * 
 */
void lcdDisplay(int rowNum, String titleText, int valueText, String value2Text)
{
    clearRow(rowNum);
    String myStr;
    myStr = String(valueText);
    int titleTextLength = titleText.length();
   // Robojax.com Relay Timer V 1.1 with LCD1602 I2C display
   lcd.setCursor (0,rowNum); //
   lcd.print(titleText);
   
   lcd.setCursor (titleTextLength,rowNum); //
   lcd.print(myStr);
   
   lcd.setCursor (myStr.length()+titleTextLength,rowNum); //
   lcd.print(value2Text);   
 
}
/*
 * 
 * @brief clears only one row of display
 * @param r, the row number integer
 * @return no return value
 */
void clearRow(int r)
{
  //
  for(int i=0; i<16; i++)
  {
   lcd.setCursor (i,r); //
   lcd.print("");
  }
}//clearRow end