/* Author : John Marchant G0RJM
  Created : 25/01/2024 - 10/1/2025 V3.0
  Description : A project to display the current date, time and temperature on the 20x4 LCD screen
  and create a programmable thermostatic heating control of three zones to include frost protection and override facilities.
  Incorporating the facility to change the temperature settings and On-Off settings from pushbuttons.
  This has been very loosely based on the RTClib ds3231 example along with many code parts borrowed
  from several other files/sketches and in collaboration with the input and help from several authors from the
  Arduino Forum with particular thanks to @alto777, @blh64, @cattledog, @StefanL38 and @UKHeliBob.  */
#include "RTClib.h"
#include <OneWire.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <ezButton.h>
#include <DallasTemperature.h>
#include <EEPROM.h>
#include <DST_RTC.h>

#define ONE_WIRE_BUS_1 3
#define ONE_WIRE_BUS_2 4
#define ONE_WIRE_BUS_3 5
#define TEMPERATURE_PRECISION 11    // 0.125deg resolution
#define heart_beat_pin LED_BUILTIN  // digital pin for heart beat LED

OneWire oneWire_range(ONE_WIRE_BUS_1);
OneWire oneWire_club(ONE_WIRE_BUS_2);
OneWire oneWire_airgun(ONE_WIRE_BUS_3);

const byte range_relay = 11;  // Relay outputs
const byte club_relay = 12;
const byte airgun_relay = A1;
const byte boiler_relay = A2;
const byte buzzer_pin = A0;

float range_temperature;
float club_temperature;
float airgun_temperature;

float range_temperature_setpoint;   // C
float club_temperature_setpoint;    // C
float airgun_temperature_setpoint;  // C
const int frost_setpoint = 12.0;    // C
const float deadzone = 1.0;         // C

ezButton leftbutton(6);    // create ezButton object that is attached to pin 6;
ezButton upbutton(7);      // create ezButton object that is attached to pin 7;
ezButton downbutton(8);    // create ezButton object that is attached to pin 8;
ezButton rightbutton(9);   // create ezButton object that is attached to pin 9;
ezButton enterbutton(10);  // create ezButton object that is attached to pin 10;

const int LONG_PRESS_TIME = 2000;  // 1000 milliseconds
const int SHORT_PRESS_TIME = 800;  // 1000 milliseconds

const unsigned OffTimed1 = 4000;
const unsigned OffTimed2 = 4000;
const unsigned menuOnTime = 20000;
const unsigned upButtonTime = 100;
const unsigned downButtonTime = 100;
const unsigned backlightOnTime = 15000;
const unsigned overrideRunOnTime = 60000;

int value = 0;
int menuselector = 0;
int timeselector = 0;
int temperatureselector = 0;

int EEPROM_address_1 = 0;    // Address of the location of range setpoint temperature setting
int EEPROM_address_2 = 4;    // Address of the location of club setpoint temperature setting
int EEPROM_address_3 = 8;    // Address of the location of airgun setpoint temperature setting
int EEPROM_address_4 = 12;   // Address of the location of Range On time setting
int EEPROM_address_5 = 16;   // Address of the location of Range Off time setting
int EEPROM_address_6 = 20;   // Address of the location of Club On time setting
int EEPROM_address_7 = 24;   // Address of the location of Club Off time setting
int EEPROM_address_8 = 28;   // Address of the location of Airgun On time setting
int EEPROM_address_9 = 32;   // Address of the location of Airgun Off time setting
int EEPROM_address_10 = 36;  // Address of the location of Sunday On time setting
int EEPROM_address_11 = 40;  // Address of the location of Sunday Off time setting

unsigned long startMillis = 0;
unsigned long menuOffTime = 0;
unsigned long pressedTime = 0;
unsigned long releasedTime = 0;
unsigned long currentMillis = 0;
unsigned long previousMillis = 0;
unsigned long last_heart_beat_time;    // time in milliseconds of last heart beat status change
unsigned long heart_beat_freq = 1000;  // time in milliseconds of heart beat frequency
unsigned long heart_beat_on_off_time;  // the time the LED is on and off - 1/2 frequency
unsigned long previousMillisMenu = 0;
unsigned long previousMillisTimeMenu = 0;
unsigned long previousMillisBacklight = 0;
unsigned long previousMillisTimedStart1 = 0;
unsigned long previousMillisTimedStart2 = 0;
unsigned long previousMillisOverrideStart = 0;
unsigned long previousMillisTemperatureMenu = 0;
unsigned long previousMillisAdjustSetpointUp = 0;
unsigned long previousMillisAdjustSetpointDown = 0;

bool isPressed = false;                 // if = True button has been pressed
bool isClubHeatOn = false;              // if = True allows the Club heating
bool isRangeHeatOn = false;             // if = True allows the Range heating
bool isBacklightOn = false;             // if = True the backlight is ON
bool isHeartBeatOn = false;             // if = True shows current status of heart beat
bool isLongDetected = false;            // if = True allows long button press to be used
bool isAirgunHeatOn = false;            // if = True allows the Airgun heating
bool isMenuSelectOn = false;            // if = True allows the setup menu to be used
bool isTimeControlOn = false;           // if = True allows normal time control function
bool isTimeSettingOn = false;           // if = True allows the time to be adjusted
bool isSetpointSaveOn = false;          // if = True allows the new setpoints to be saved to EEPROM
bool isAdjustSetpointUp = false;        // if = True allows the Setpoint increment
bool isHeatingOverrideOn = false;       // if = True allows the heating override facility
bool isAdjustSetpointDown = false;      // if = True allows the Setpoint decrement
bool isTemperatureSettingOn = false;    // if = True allows the temperature to be adjusted
bool isClubSetpointAdjustOn = false;    // if = True allows the club setpoint to be adjusted
bool isRangeSetpointAdjustOn = false;   // if = True allows the range setpoint to be adjusted
bool isAirgunSetpointAdjustOn = false;  // if = True allows the airgun setpoint to be adjusted

DallasTemperature range_sensor(&oneWire_range);
DallasTemperature club_sensor(&oneWire_club);
DallasTemperature airgun_sensor(&oneWire_airgun);

enum { SUNDAY,
       MONDAY,
       TUESDAY,
       WEDNESDAY,
       THURSDAY,
       FRIDAY,
       SATURDAY
     };

enum operationModes { NORMAL_MODE,
                      OVERRIDE_MODE,
                      SETUP_MODE
                    };

enum setupmodes { TIME_SETUP_MODE,
                  TEMPERATURE_SETUP_MODE
                };

int myMode = NORMAL_MODE;

int On_Normal_Range;    // 16:00 Normal ON time
int Off_Normal_Range;   // 21:30 Normal OFF time
int On_Normal_Club;     // 16:00 Normal ON time
int Off_Normal_Club;    // 21:30 Normal OFF time
int On_Normal_Airgun;   // 16:00 Normal ON time
int Off_Normal_Airgun;  // 21:30 Normal OFF time
int On_Sunday;          // 12:00 Sunday ON time
int Off_Sunday;         // 17:30 Sunday OFF time

LiquidCrystal_I2C lcd(0X27, 20, 4);
RTC_DS3231 rtc;
DST_RTC dst_rtc;  // DST object

// Define US or EU rules for DST comment out as required. More countries could be added with different rules in DST_RTC.cpp
// const char rulesDST[] = "US"; // US DST rules
const char rulesDST[] = "EU";  // EU DST rules

char daysOfTheWeek[7][4] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
byte char_temp[8] = { B00100, B01010, B01010, B01110, B01110, B11111, B11111, B01110 };  // for thermometer icon

void setup() {
  Serial.begin(9600);
  Serial.println( F("Setup-Start") );
  Wire.begin();
  Serial.println( F("Wire.begin done") );

  rtc.begin();
  Serial.println( F("rtc.begin done") );
  checkRTC();
  Serial.println(F ("setup checkRTC() done")  );

  startMillis = millis();
  heart_beat_on_off_time = heart_beat_freq / 2;  // LED is on and off at 1/2 frequency time

  setPinModes();
  Serial.println( F("setPinModes done")  );
  setupOneWireSensors();
  Serial.println( F("setupOneWireSensors done") );
  setDebounceTimes();
  Serial.println( F("setDebounceTimes done") );

  InitiateSetpoints();
  Serial.println( F("InitiateSetpoints done") );
  delay(2000);
  RetrieveSetpoint();
  Serial.println( F("RetrieveSetpoint done") );
  initLCD();
  Serial.println( F("initLCD done") );
  delay(1000);
  lcd.clear();

  Serial.println(F("G0RJM Three zone Temperature Control"));

}  // End of setup

void loop() {
  Serial.println("Top of loop");
  //       ("ABCDEFGHIJ1234567890")
  unsigned long currentMillis = millis();  // all time elements are data type unsigned long
  //---------------------------Button control-------------------------//
  leftbutton.loop();   // MUST call the loop() function first
  upbutton.loop();     // MUST call the loop() function first
  downbutton.loop();   // MUST call the loop() function first
  rightbutton.loop();  // MUST call the loop() function first
  enterbutton.loop();  // MUST call the loop() function first

  Heartbeat();

  if (myMode == NORMAL_MODE) {
    NormalModeSelect();
  }
  else if (myMode == OVERRIDE_MODE) {
    HeatingOverrideSelect();
  }
  else if (myMode == SETUP_MODE) {
    SetupSelect();
  }
  else {
    Serial.println( F("oops. unallocated mode") );
  }

  myStateMachine();

  BoilerInterlock();

  SerialPrintTemperature();

  // -------------------------Backlight display-----------------------//

  if ((leftbutton.isPressed() || (upbutton.isPressed() || (downbutton.isPressed() || (rightbutton.isPressed() || (enterbutton.isPressed())))))) {
    lcd.backlight();
    Serial.println(F("        Backlight is ON"));
    previousMillisBacklight = currentMillis;
  }

  if ((!isHeatingOverrideOn) && (!isMenuSelectOn) && (currentMillis - previousMillisBacklight >= backlightOnTime)) {
    lcd.noBacklight();
    Serial.println(F("        Backlight is OFF"));
  }

  //--------------------Daylight Saving Setting---------------------//
  DateTime standardTime = rtc.now();

  Serial.println(F("Standard Time"));
  printTheTime(standardTime);

  DateTime theTime = dst_rtc.calculateTime(standardTime);  // takes into account DST

  Serial.println(F("Time adjusted for Daylight Saving Time"));
  printTheTime(theTime);

  int currentTime = theTime.hour() * 60UL + theTime.minute();

  //--------------------Timed heating setting-----------------------//
  if (isTimeControlOn)
    //; // xxLu
  {
    Serial.println(F("Something time controlled is happening here!"));
    if (theTime.dayOfTheWeek() != SUNDAY) {
      // Monday to Saturday so use normal times
      if (currentTime < On_Normal_Range || currentTime > Off_Normal_Range) {
        // this is outside normal range heating time
        isRangeHeatOn = false;
      }
      else {
        // this is within normal range heating time
        isRangeHeatOn = true;
      }
    }
    else {
      // Sunday times
      if (currentTime < On_Sunday || currentTime > Off_Sunday) {
        // this is outside Sunday range heating time
        isRangeHeatOn = false;
      }
      else {
        // this is within Sunday range heating time
        isRangeHeatOn = true;
      }
    }
    if (theTime.dayOfTheWeek() != SUNDAY) {
      // Monday to Saturday so use normal times
      if (currentTime < On_Normal_Club || currentTime > Off_Normal_Club) {
        // this is outside normal club heating time
        isClubHeatOn = false;
      }
      else {
        // this is within normal club heating time
        isClubHeatOn = true;
      }
    }
    else {
      // Sunday times
      if (currentTime < On_Sunday || currentTime > Off_Sunday) {
        // this is outside Sunday club heating time
        isClubHeatOn = false;
      }
      else {
        // this is within Sunday club heating time
        isClubHeatOn = true;
      }
    }
    if (theTime.dayOfTheWeek() != SUNDAY) {
      // Monday to Saturday so use normal times
      if (currentTime < On_Normal_Airgun || currentTime > Off_Normal_Airgun) {
        // this is outside normal airgun heating time
        isAirgunHeatOn = false;
      }
      else {
        // this is within normal airgun heating time
        isAirgunHeatOn = true;
      }
    }
    else {
      // Sunday times
      if (currentTime < On_Sunday || currentTime > Off_Sunday) {
        // this is outside Sunday airgun heating time
        isAirgunHeatOn = false;
      }
      else {
        // this is within Sunday airgun heating time
        isAirgunHeatOn = true;
      }
    }
  }

  //---------------------Date & Time display----------------------//

  if (isTimeControlOn)
    //; //xxLu
  {
    Serial.println(F("Time & date showing on LCD"));
    lcd.setCursor(0, 0);
    lcd.print(daysOfTheWeek[theTime.dayOfTheWeek()]);
    lcd.setCursor(3, 0);
    lcd.print(F(":"));
    lcd.setCursor(4, 0);
    if (theTime.day() < 10) lcd.print('0');
    lcd.print(theTime.day(), DEC);
    lcd.print(':');
    if (theTime.month() < 10) lcd.print('0');
    lcd.print(theTime.month(), DEC);
    lcd.print(':');
    lcd.print(theTime.year(), DEC);
    lcd.setCursor(15, 0);
    if (theTime.hour() < 10) lcd.print('0');
    lcd.print(theTime.hour(), DEC);
    lcd.print(':');
    if (theTime.minute() < 10) lcd.print('0');
    lcd.print(theTime.minute(), DEC);
  }


}  // End of loop


//-----------------------Initiate Setpoints--------------------------//
void InitiateSetpoints() {

  // EEPROM.put(EEPROM_address_1, range_temperature_setpoint);   // write the float value to EEPROM ONLY used to initially set up setpoint
  // EEPROM.put(EEPROM_address_2, club_temperature_setpoint);    // write the float value to EEPROM ONLY used to initially set up setpoint
  // EEPROM.put(EEPROM_address_3, airgun_temperature_setpoint);  // write the float value to EEPROM ONLY used to initially set up setpoint
  // EEPROM.put(EEPROM_address_4, 16 * 60 + 00);   // write the value to EEPROM ONLY used to initially set up Range Normal On Time
  // EEPROM.put(EEPROM_address_5, 21 * 60 + 30);   // write the value to EEPROM ONLY used to initially set up Range Normal Off Time
  // EEPROM.put(EEPROM_address_6, 16 * 60 + 00);   // write the value to EEPROM ONLY used to initially set up Club Normal On Time
  // EEPROM.put(EEPROM_address_7, 21 * 60 + 30);   // write the value to EEPROM ONLY used to initially set up Club Normal Off Time
  // EEPROM.put(EEPROM_address_8, 16 * 60 + 00);   // write the value to EEPROM ONLY used to initially set up Airgun Normal On Time
  // EEPROM.put(EEPROM_address_9, 21 * 60 + 30);   // write the value to EEPROM ONLY used to initially set up Airgun Normal Off Time
  // EEPROM.put(EEPROM_address_10, 12 * 60 + 00);  // write the value to EEPROM ONLY used to initially set up Sunday On Time
  // EEPROM.put(EEPROM_address_11, 17 * 60 + 30);  // write the value to EEPROM ONLY used to initially set up Sunday Off Time
}

//------------------------My State machine---------------------------//
void myStateMachine() {
  Serial.println( F( "entering myStateMachine()") );

  checkRTC();

  switch (myMode) {
    case NORMAL_MODE:
      Serial.println( F("myStateMachine NORMAL_MODE") );
      NormalModeSelect();
      if (downbutton.isPressed()) {
        myMode = OVERRIDE_MODE;
      } else {
        if (rightbutton.isPressed()) {
          myMode = SETUP_MODE;
        }
      }
      // checkRTC(); // xxLu not nescessary is done above switch
      break;  // skip cases below and jump down to END-OF-SWITCH


    case OVERRIDE_MODE:
      Serial.println( F( "myStateMachine OVERRIDE_MODE") );
      HeatingOverrideSelect();
      if (!isHeatingOverrideOn) {
        Serial.println(F("        Override Cancelled"));
        myMode = NORMAL_MODE;
      }
      // checkRTC(); // xxLu not nescessary is done above switch
      break;  // skip cases below and jump down to END-OF-SWITCH


    case SETUP_MODE:
      Serial.println( F("myStateMachine SETUP_MODE") );
      SetupSelect();
      // check if 15 seconds of time have passed by
      previousMillisMenu = currentMillis;
      if (currentMillis - previousMillisMenu >= menuOnTime) {
        myMode = NORMAL_MODE;
        break;  // skip cases below and jump down to END-OF-SWITCH
      }
      break;  // skip cases below and jump down to END-OF-SWITCH
  }

  Serial.println( F("exiting myStateMachine()") );
}  // END-OF-SWITCH


//-------------------------Normal Mode Select----------------------//
void NormalModeSelect() {
  Serial.println( F("entering NormalModeSelect()") );
  TemperatureDisplay();
  HeatingAvailable();
  (isTimeControlOn == true); // xLu what shall this line do??
  Serial.println( F("exiting NormalModeSelect()") );
}
//------------------------Heating Override Select---------------------//
void HeatingOverrideSelect() {
  Serial.println("entering HeatingOverrideSelect()");

  lcd.clear();
  lcd.print(F(" OVERRIDE MODE"));
  Serial.println(F("Heating override selected"));
  HeatingOverride();
  Buzzer();
  previousMillisOverrideStart = currentMillis;

  if ((downbutton.isPressed() && (isHeatingOverrideOn) && (currentMillis - previousMillisOverrideStart >= 5000)))  // Manually cancels the override
  {
    Serial.println(F("       Manual termination of override"));
    HeatingOverrideCompleted();
    Buzzer();
  } else {

    if ((isHeatingOverrideOn) && (currentMillis - previousMillisOverrideStart >= overrideRunOnTime))  // Automatically cancels the override
    {
      Serial.println(F("      Auto termination of override"));
      HeatingOverrideCompleted();
      Buzzer();
    }
  }
  Serial.println( F("exiting HeatingOverrideSelect()"));
}
//------------------------Heating Override---------------------------//
void HeatingOverride() {
  Serial.println( F("entering HeatingOverride()") );

  Serial.println(F("      Heating Override is On"));
  Serial.println(F("Timed Control is OFF"));
  TemperatureDisplay();
  HeatingAvailable();
  isRangeHeatOn = true;
  isClubHeatOn = true;
  isAirgunHeatOn = true;
  isHeatingOverrideOn = true;
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print(F("   OVERRIDE IS ON   "));
  Serial.println( F("exiting HeatingOverride()") );
}

//--------------------Heating Override Completed----------------------//
void HeatingOverrideCompleted() {
  Serial.println( F("entering HeatingOverrideCompleted()") );

  Serial.println(F("     Heating Override is complete"));
  Serial.println(F("Timed Control is ON"));
  isRangeHeatOn = false;
  isClubHeatOn = false;
  isAirgunHeatOn = false;
  isHeatingOverrideOn = false;
  lcd.setCursor(0, 0);
  lcd.print(F("   OVERRIDE IS OFF   "));
  delay(1000);
  lcd.clear();
  Serial.println( F("exiting HeatingOverrideCompleted()") );
}

//---------------------------Setup Mode-----------------------------//
void SetupSelect() {
  Serial.println( F("entering SetupSelect()") );

  (isTimeControlOn == false);
  lcd.clear();
  lcd.print(F("   SETTING MODE    "));
  Serial.println( F("exiting SetupSelect()") );
}

//--------------------------Menu Selection-------------------------//
void MenuSelection() {
  Serial.println( F("entering MenuSelection()") );

  if (rightbutton.isPressed() && (!isMenuSelectOn))  // Initiates the setup menu
  {
    Serial.println(F("              Temperature setting activated"));
    isMenuSelectOn = true;
    isTemperatureSettingOn = true;  // Initiates the temperature setup menu
    lcd.clear();
    lcd.print(F("TEMPERATURE SETTING"));
    Buzzer();
    previousMillisTimedStart1 = currentMillis;
  }

  if (rightbutton.isPressed() && (isTemperatureSettingOn)) {
    if (currentMillis - previousMillisTimedStart1 >= OffTimed1)  // Initiates the time setup menu
    {
      Serial.println(F("              Time setting activated"));
      isTimeSettingOn = true;
      isTemperatureSettingOn = false;
      lcd.clear();
      lcd.print(F("  TIME SETTING"));
      Buzzer();
      previousMillisTimedStart2 = currentMillis;
    }
  }

  if (rightbutton.isPressed() && (isTimeSettingOn)) {
    if (currentMillis - previousMillisTimedStart2 >= OffTimed2)  // Deactivates the set up menu
    {
      Serial.println(F("              Settings deactivated"));
      lcd.clear();
      lcd.print(F("   MENU EXITED"));
      isMenuSelectOn = false;
      isTimeSettingOn = false;
      Buzzer();
    }
  }
  Serial.println( F("exiting MenuSelection()") );
}

//----------------------Temperature Setting Menu----------------------//
void TemperatureSetting() {
  Serial.println( F("entering TemperatureSetting()") );

  if (leftbutton.isPressed() && (isTemperatureSettingOn)) {
    Serial.println(F("              left button pressed - Temp"));
    TemperatureSelector();
    temperatureselector++;  // this is done after TemperatureSettingMenu(), so case 0 will be executed on the first button press
    if (temperatureselector > 5) {
      temperatureselector = 0;
    }
    previousMillisTemperatureMenu = currentMillis;
  }

  if (isTemperatureSettingOn) {
    if (currentMillis - previousMillisTemperatureMenu >= menuOnTime) {
      isTemperatureSettingOn = false;
      //  isMenuSelectOn = false;
      temperatureselector = 6;
    }
  }
  Serial.println( F("exiting TemperatureSetting()") );
}

//----------------------------Pin Modes------------------------------//
void setPinModes() {

  pinMode(range_relay, OUTPUT);
  pinMode(club_relay, OUTPUT);
  pinMode(airgun_relay, OUTPUT);
  pinMode(boiler_relay, OUTPUT);
  pinMode(buzzer_pin, OUTPUT);

  pinMode(heart_beat_pin, OUTPUT);
}

//--------------------------------LCD--------------------------------//
void initLCD() {

  lcd.init();
  lcd.backlight();
  lcd.createChar(0, char_temp);
  lcd.setCursor(2, 0);
  lcd.print(F("G0RJM Three Zone"));
  lcd.setCursor(1, 1);
  lcd.print(F("Temperature Control"));
  lcd.setCursor(4, 2);
  lcd.print(F("Take it easy!"));
  lcd.setCursor(4, 3);
  lcd.print(F("Working on it"));
}

//-----------------------------Debounce------------------------------//
void setDebounceTimes() {

  leftbutton.setDebounceTime(50);   // set debounce time to 50 milliseconds
  upbutton.setDebounceTime(50);     // set debounce time to 50 milliseconds
  downbutton.setDebounceTime(50);   // set debounce time to 50 milliseconds
  rightbutton.setDebounceTime(50);  // set debounce time to 50 milliseconds
  enterbutton.setDebounceTime(50);  // set debounce time to 50 milliseconds
}

//------------------------OneWire Sensors----------------------------//
void setupOneWireSensors() {

  range_sensor.begin();
  club_sensor.begin();
  airgun_sensor.begin();

  range_sensor.setResolution(TEMPERATURE_PRECISION);
  club_sensor.setResolution(TEMPERATURE_PRECISION);
  airgun_sensor.setResolution(TEMPERATURE_PRECISION);
}

//----------------------------Check RTC------------------------------//
void checkRTC() {
  Serial.println( F("entering checkRTC()") );

  if (rtc.lostPower()) {
    Serial.println(F("RTC is NOT running!"));
    // Uncomment the following line to set the RTC to the date & time this sketch was compiled
    // rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // rtc.adjust(DateTime(2024,4,24,21,49,00));
    /* DST? If we're in it, let's subtract an hour from the RTC time to keep our DST calculation correct. This gives us
      Standard Time which our DST check will add an hour back to if we're in DST.
    */
    DateTime standardTime = rtc.now();
    if (dst_rtc.checkDST(standardTime) == true) {  // check whether we're in DST right now. If we are, subtract an hour.
      standardTime = standardTime.unixtime() - 3600;
    }
    rtc.adjust(standardTime);
  }
  Serial.println( F("exiting checkRTC()") );
}

//----------------------Print time to serial-------------------------//
void printTheTime(DateTime theTimeP) {

  Serial.print(theTimeP.year(), DEC);
  Serial.print('/');
  Serial.print(theTimeP.month(), DEC);
  Serial.print('/');
  Serial.print(theTimeP.day(), DEC);
  Serial.print(' ');
  Serial.print(theTimeP.hour(), DEC);
  Serial.print(':');
  Serial.print(theTimeP.minute(), DEC);
  Serial.print(':');
  Serial.print(theTimeP.second(), DEC);
  Serial.println();
}

//------------------------Retrieve setpoint--------------------------//
void RetrieveSetpoint() {
  /*
    int On_Normal_Range;    // 16:00 Normal ON time
    int Off_Normal_Range;   // 21:30 Normal OFF time

    int On_Normal_Club;     // 16:00 Normal ON time
    int Off_Normal_Club;    // 21:30 Normal OFF time

    int On_Normal_Airgun;   // 16:00 Normal ON time
    int Off_Normal_Airgun;  // 21:30 Normal OFF time
    int On_Sunday;          // 12:00 Sunday ON time
    int Off_Sunday;         // 17:30 Sunday OFF time
  */
  //xxLu
  EEPROM.get(EEPROM_address_1, range_temperature_setpoint);   //retrieve the range setpoint from EEPROM
  if (range_temperature_setpoint < 0); {
    range_temperature_setpoint = 20;
  }


  EEPROM.get(EEPROM_address_2, club_temperature_setpoint);    //retrieve the club setpoint from EEPROM
  if (club_temperature_setpoint < 0); {
    club_temperature_setpoint = 20;
  }
  EEPROM.get(EEPROM_address_3, airgun_temperature_setpoint);  //retrieve the airgun setpoint from EEPROM
  if (airgun_temperature_setpoint < 0); {
    airgun_temperature_setpoint = 20;
  }

  EEPROM.get(EEPROM_address_4, On_Normal_Range);              //retrieve the Normal Range On Time from EEPROM
  if (On_Normal_Range < 0) {
    On_Normal_Range = 16;
  }

  EEPROM.get(EEPROM_address_5, Off_Normal_Range);             //retrieve the Normal Range Off Time from EEPROM
  if (Off_Normal_Range < 0) {
    Off_Normal_Range = 21;
  }

  EEPROM.get(EEPROM_address_6, On_Normal_Club);               //retrieve the Normal Club On Time from EEPROM
  if (On_Normal_Club < 0) {
    On_Normal_Club = 16;
  }

  EEPROM.get(EEPROM_address_7, Off_Normal_Club);              //retrieve the Normal Club Off Time from EEPROM
  if (Off_Normal_Club < 0) {
    Off_Normal_Club = 21;
  }
  EEPROM.get(EEPROM_address_8, On_Normal_Airgun);             //retrieve the Normal Airgun On Time from EEPROM
  if (On_Normal_Airgun < 0) {
    On_Normal_Airgun = 16;
  }
  EEPROM.get(EEPROM_address_9, Off_Normal_Airgun);            //retrieve the Normal Airgun Off Time from EEPROM
  if (Off_Normal_Airgun < 0) {
    Off_Normal_Airgun = 21;
  }
  EEPROM.get(EEPROM_address_10, On_Sunday);                   //retrieve the Sunday On Time from EEPROM
  if (On_Sunday < 0) {
    On_Sunday = 12;
  }
  EEPROM.get(EEPROM_address_11, Off_Sunday);                  //retrieve the Sunday Off Time from EEPROM
  if (Off_Sunday < 0) {
    Off_Sunday = 17;
  }

  Serial.print(F("Range Temperature Setpoint:"));
  Serial.print(range_temperature_setpoint);
  Serial.print(F(" Stored at addr "));
  Serial.println(EEPROM_address_1);
  Serial.print(F("Club Temperature Setpoint:"));
  Serial.print(club_temperature_setpoint);
  Serial.print(F(" Stored at addr "));
  Serial.println(EEPROM_address_2);
  Serial.print(F("Airgun Temperature Setpoint:"));
  Serial.print(airgun_temperature_setpoint);
  Serial.print(F(" Stored at addr "));
  Serial.println(EEPROM_address_3);
  Serial.print(F("Normal Range On Time:"));
  Serial.print(On_Normal_Range);
  Serial.print(F(" Stored at addr "));
  Serial.println(EEPROM_address_4);
  Serial.print(F("Normal Range Off Time:"));
  Serial.print(Off_Normal_Range);
  Serial.print(F(" Stored at addr "));
  Serial.println(EEPROM_address_5);
  Serial.print(F("Normal Club On Time:"));
  Serial.print(On_Normal_Club);
  Serial.print(F(" Stored at addr "));
  Serial.println(EEPROM_address_6);
  Serial.print(F("Normal Club Off Time:"));
  Serial.print(Off_Normal_Club);
  Serial.print(F(" Stored at addr "));
  Serial.println(EEPROM_address_7);
  Serial.print(F("Normal Airgun On Time:"));
  Serial.print(On_Normal_Airgun);
  Serial.print(F(" Stored at addr "));
  Serial.println(EEPROM_address_8);
  Serial.print(F("Normal Airgun Off Time:"));
  Serial.print(Off_Normal_Airgun);
  Serial.print(F(" Stored at addr "));
  Serial.println(EEPROM_address_9);
  Serial.print(F("Sunday On Time:"));
  Serial.print(On_Sunday);
  Serial.print(F(" Stored at addr "));
  Serial.println(EEPROM_address_10);
  Serial.print(F("Sunday Off Time:"));
  Serial.print(Off_Sunday);
  Serial.print(F(" Stored at addr "));
  Serial.println(EEPROM_address_11);
}

//---------------------------Heartbeat-------------------------------//
void Heartbeat() {

  if (millis() - last_heart_beat_time >= heart_beat_on_off_time) {  // time to swap status of the heart beat LED and update it
    last_heart_beat_time = millis();
    isHeartBeatOn = !isHeartBeatOn;               // invert current heart beat status value
    digitalWrite(heart_beat_pin, isHeartBeatOn);  // update LED with new status
  }
}

//------------------------Boiler Interlock--------------------------//
void BoilerInterlock() {
  Serial.println( F("entering BoilerInterlock()") );

  if ((digitalRead(range_relay) == HIGH) || (digitalRead(club_relay) == HIGH) || (digitalRead(airgun_relay) == HIGH)) {
    digitalWrite(boiler_relay, HIGH);
  } else {
    digitalWrite(boiler_relay, LOW);
  }
  Serial.println("exiting BoilerInterlock()");
}

//------------------------Serial print---------------------------//
void SerialPrintTemperature() {

  Serial.print(F("Requesting temperatures..."));
  range_sensor.requestTemperatures();
  club_sensor.requestTemperatures();
  airgun_sensor.requestTemperatures();
  Serial.println(F(" done"));
  Serial.print(F("Range: "));
  Serial.println(range_sensor.getTempCByIndex(0));
  Serial.print(F("Club: "));
  Serial.println(club_sensor.getTempCByIndex(0));
  Serial.print(F("Airgun: "));
  Serial.println(airgun_sensor.getTempCByIndex(0));
}

//---------------------------Menu Select-----------------------------//
void MenuSelect() {
  Serial.println( F("entering MenuSelect()") );

  switch (menuselector) {
    case 0:
      Serial.println(F("Case 0M"));  // General menu
      lcd.clear();
      lcd.print(F("TEMPERATURE SETTING"));
      lcd.print(F("     PRESS ENTER"));
      TemperatureSettingMenu();
      Buzzer();
      break;
    case 1:
      Serial.println(F("Case 1M"));
      lcd.clear();
      lcd.print(F("    TIME SETTING"));
      lcd.print(F("         PRESS ENTER"));
      TimeSettingMenu();
      Buzzer();
      break;
    case 2:
      Serial.println(F("Case 2M"));
      lcd.clear();
      lcd.print(F("     PRESS ENTER"));
      lcd.print(F("           TO CLEAR"));
      Buzzer();
      break;
  }
  Serial.println( F("exiting MenuSelect()") );
}

//-------------------Temperature Setting Menu------------------------//
void TemperatureSettingMenu() {
  Serial.println( F("entering TemperatureSettingMenu()") );

  {
    Serial.println(F("Temp. Menu ON"));
    isTemperatureSettingOn = true;
  }
  Serial.println( F("exiting TemperatureSettingMenu()") );
}
//------------------Temperature Selector---------------------------//
void TemperatureSelector() {
  Serial.println( F("entering TemperatureSelector()") );

  switch (temperatureselector) {
    case 0:
      Serial.println(F("Case 0Te"));  // General menu
      TemperatureMenuScreen();
      break;
    case 1:
      Serial.println(F("Case 1Te"));  // Displays the Range setpoint
      RangeDisplay();
      Buzzer();
      break;
    case 2:
      Serial.println(F("Case 2Te"));  // Displays the Club setpoint
      ClubDisplay();
      Buzzer();
      break;
    case 3:
      Serial.println(F("Case 3Te"));  // Displays the Airgun setpoint
      AirgunDisplay();
      Buzzer();
      break;
    case 4:
      Serial.println(F("Case 4Te"));  // Instructs how to save the new settings
      SaveDisplay();
      Buzzer();
      break;
    case 5:
      Serial.println(F("Case 5Te"));  // Reminds you to save
      lcd.clear();
      lcd.setCursor(3, 1);
      lcd.print(F("Have you saved"));
      lcd.setCursor(4, 2);
      lcd.print(F("the settings?"));
      Buzzer();
  }
  Serial.println( F("exiting TemperatureSelector()") );
}

//----------------------------Up Button-----------------------------//
void UpButton() {
  Serial.println( F("entering UpButton()") );

  if (upbutton.isPressed()) {
    Serial.println(F("           up button pressed"));
    isAdjustSetpointUp = true;  // Setpoint adjustment upwards is available
    previousMillisAdjustSetpointUp = currentMillis;
  }

  if (isAdjustSetpointUp) {
    if (currentMillis - previousMillisAdjustSetpointUp >= upButtonTime) {
      isAdjustSetpointUp = false;
    }
  }

  if (isAdjustSetpointUp && isRangeSetpointAdjustOn)  // If True, this allows the Range setpoint to be adjusted
  {
    range_temperature_setpoint += 0.1;  // Range Setpoint increment
    Serial.println(F("range_temperature_setpoint_up"));
    RangeDisplay();
    Buzzer();
  }

  if (isAdjustSetpointUp && isClubSetpointAdjustOn)  // If True, this allows the Club setpoint to be adjusted
  {
    club_temperature_setpoint += 0.1;  // Club Setpoint increment
    Serial.println(F("club_temperature_setpoint_up"));
    ClubDisplay();
    Buzzer();
  }

  if (isAdjustSetpointUp && isAirgunSetpointAdjustOn)  // If True, this allows the Airgun setpoint to be adjusted
  {
    airgun_temperature_setpoint += 0.1;  // Airgun Setpoint increment
    Serial.println(F("airgun_temperature_setpoint_up"));
    AirgunDisplay();
    Buzzer();
  }
  Serial.println( F("exiting UpButton()") );
}
//----------------------------Down Button---------------------------//
void DownButton() {
  Serial.println( F("entering DownButton()") );

  if (downbutton.isPressed()) {
    Serial.println(F("               down button pressed"));
    isAdjustSetpointDown = true;  // Setpoint adjustment Downwards is available
    previousMillisAdjustSetpointDown = currentMillis;
  }
  if (isAdjustSetpointDown) {
    if (currentMillis - previousMillisAdjustSetpointDown >= downButtonTime) {
      isAdjustSetpointDown = false;
    }
  }

  if (isAdjustSetpointDown && isRangeSetpointAdjustOn)  // If True, this allows the Range setpoint to be adjusted
  {
    range_temperature_setpoint -= 0.1;  // Range Setpoint decrement
    Serial.println(F("range_temperature_setpoint_down"));
    RangeDisplay();
    Buzzer();
  }

  if (isAdjustSetpointDown && isClubSetpointAdjustOn)  // If True, this allows the Club setpoint to be adjusted
  {
    club_temperature_setpoint -= 0.1;  // Club Setpoint decrement
    Serial.println(F("club_temperature_setpoint_down"));
    ClubDisplay();
    Buzzer();
  }

  if (isAdjustSetpointDown && isAirgunSetpointAdjustOn)  // If True, this allows the Airgun setpoint to be adjusted
  {
    airgun_temperature_setpoint -= 0.1;  // Airgun Setpoint decrement
    Serial.println(F("airgun_temperature_setpoint_down"));
    AirgunDisplay();
    Buzzer();
  }
  Serial.println("exiting DownButton()");
}
//----------------------Time Setting Menu----------------------------//
void TimeSettingMenu() {
  isTimeSettingOn = true;
  Serial.println(F("Time Menu ON"));
}

//-----------------------Time Selector------------------------------//
void TimeSelector() {
  Serial.println( F("entering TimeSelector()") );

  switch (timeselector) {
    case 0:
      Serial.println(F("Case 0Ti"));
      TimeMenuScreen();
      break;
  }
  Serial.println( F("exiting TimeSelector()") );
}

//---------------------------Buzzer----------------------------------//
void Buzzer() {
  digitalWrite(buzzer_pin, HIGH);
  delay(100);
  digitalWrite(buzzer_pin, LOW);
}

//-------------------Temperature Menu screen------------------------//
void TemperatureMenuScreen() {

  lcd.clear();
  lcd.print(F(" Setting Menu:      "));
  lcd.setCursor(0, 1);
  lcd.print(F("Range: "));
  lcd.print(range_temperature_setpoint, 1);
  lcd.write((char)223);
  lcd.print('C');
  lcd.setCursor(0, 2);
  lcd.print(F("Club:  "));
  lcd.print(club_temperature_setpoint, 1);
  lcd.write((char)223);
  lcd.print('C');
  lcd.setCursor(0, 3);
  lcd.print(F("Airgun:"));
  lcd.print(airgun_temperature_setpoint, 1);
  lcd.write((char)223);
  lcd.print('C');
  isSetpointSaveOn = false;
}

//---------------------Time Menu screen-----------------------------//
void TimeMenuScreen() {

  lcd.clear();
  lcd.print(F(" Time Menu:      "));
  lcd.setCursor(0, 1);
  lcd.print(F("Range: "));
}

//-----------------------Setting Displays---------------------------//
void RangeDisplay() {

  isRangeSetpointAdjustOn = true;
  isClubSetpointAdjustOn = false;
  isAirgunSetpointAdjustOn = false;
  Serial.println(F("RangeChange"));
  lcd.clear();
  lcd.print(F(" Setting Menu:      "));
  lcd.setCursor(0, 1);
  lcd.print(F("Range: "));
  lcd.print(range_temperature_setpoint, 1);
  lcd.write((char)223);
  lcd.print('C');
}

//-------------------------------------------------------------------//
void ClubDisplay() {

  isClubSetpointAdjustOn = true;
  isRangeSetpointAdjustOn = false;
  isAirgunSetpointAdjustOn = false;
  Serial.println(F("ClubChange"));
  lcd.clear();
  lcd.print(F(" Setting Menu:      "));
  lcd.setCursor(0, 2);
  lcd.print(F("Club:  "));
  lcd.print(club_temperature_setpoint, 1);
  lcd.write((char)223);
  lcd.print('C');
}

//-------------------------------------------------------------------//
void AirgunDisplay() {

  isAirgunSetpointAdjustOn = true;
  isRangeSetpointAdjustOn = false;
  isClubSetpointAdjustOn = false;
  Serial.println(F("AirgunChange"));
  lcd.clear();
  lcd.print(F(" Setting Menu:      "));
  lcd.setCursor(0, 3);
  lcd.print(F("Airgun:"));
  lcd.print(airgun_temperature_setpoint, 1);
  lcd.write((char)223);
  lcd.print('C');
}

//------------------------Save Display-------------------------------//
void SaveDisplay() {

  isRangeSetpointAdjustOn = false;
  isClubSetpointAdjustOn = false;
  isAirgunSetpointAdjustOn = false;
  Serial.println(F("SavingChanges"));
  lcd.clear();
  lcd.print(F("To save the changes"));
  lcd.setCursor(2, 1);
  lcd.print(F("Press UP & DOWN"));
  lcd.setCursor(5, 2);
  lcd.print(F("Together"));
  isSetpointSaveOn = true;
}

//---------------------Temperature display - ------------------------//
void TemperatureDisplay() {

  lcd.setCursor(0, 1);  // Range Temperature
  lcd.print(F("Range: "));
  lcd.print(range_sensor.getTempCByIndex(0), 1);
  lcd.write((char)223);
  lcd.print('C');
  lcd.setCursor(0, 2);  // Club Temperature
  lcd.print(F("Club:  "));
  lcd.print(club_sensor.getTempCByIndex(0), 1);
  lcd.write((char)223);
  lcd.print('C');
  lcd.setCursor(0, 3);  // Airgun Temperature
  lcd.print(F("Airgun:"));
  lcd.print(airgun_sensor.getTempCByIndex(0), 1);
  lcd.write((char)223);
  lcd.print('C');
}

//----------------------------Enter Button----------------------------//
void EnterButton() {
  Serial.println( F("entering EnterButton()") );

  Serial.print(F("            enter button is pressed"));
  SaveSettings();
  Buzzer();
  Serial.println( F("exiting EnterButton()") );
}

//---------------------------Save Settings--------------------------//
void SaveSettings() {
  Serial.println( F("entering SaveSettings()") );

  for (int n = 0; n < 1; n++) {
    Serial.println(F("Changes saved"));
    EEPROM.put(EEPROM_address_1, range_temperature_setpoint);   // write the new range setpoint value to EEPROM, only if it has changed
    EEPROM.put(EEPROM_address_2, club_temperature_setpoint);    // write the new club setpoint value to EEPROM, only if it has changed
    EEPROM.put(EEPROM_address_3, airgun_temperature_setpoint);  // write the new airgun setpoint value to EEPROM, only if it has changed
    EEPROM.put(EEPROM_address_4, On_Normal_Range);              // write the new Range Normal On time to EEPROM, only if it has changed
    EEPROM.put(EEPROM_address_5, Off_Normal_Range);             // write the new Range Normal Off time to EEPROM, only if it has changed
    EEPROM.put(EEPROM_address_6, On_Normal_Club);               // write the new Club Normal On time to EEPROM, only if it has changed
    EEPROM.put(EEPROM_address_7, Off_Normal_Club);              // write the new Club Normal Off time to EEPROM, only if it has changed
    EEPROM.put(EEPROM_address_8, On_Normal_Airgun);             // write the new Airgun Normal On time to EEPROM, only if it has changed
    EEPROM.put(EEPROM_address_9, Off_Normal_Airgun);            // write the new Airgun Normal Off time to EEPROM, only if it has changed
    EEPROM.put(EEPROM_address_10, On_Sunday);                   // write the new Sunday On time to EEPROM, only if it has changed
    EEPROM.put(EEPROM_address_11, Off_Sunday);                  // write the new Sunday Off time to EEPROM, only if it has changed

    delay(2000);
    RetrieveSetpoint();
    lcd.setCursor(3, 3);
    lcd.print(F("SETTINGS SAVED"));
    delay(3000);
    lcd.clear();
    isMenuSelectOn = false;  // Deactivates the set up menu
    isTimeSettingOn = false;
  }
  Serial.println( F("exiting SaveSettings()") );
}

//-----------------------Heating Available---------------------------//
void HeatingAvailable() {
  Serial.println( F("entering HeatingAvailable()") );

  RangeHeatingAvailable();
  ClubHeatingAvailable();
  AirgunHeatingAvailable();
  Serial.println( F("exiting HeatingAvailable()") );
}

//-------------------------------------------------------------------//
void RangeHeatingAvailable() {
  Serial.println( F("entering RangeHeatingAvailable()") );

  if (isRangeHeatOn) {
    NormalHeatingRange();
    Serial.println(F("Heating R"));
  }
  else {
    FrostPreventionRange();
    Serial.println(F("Frost Prev. R"));
  }
  Serial.println( F("exiting RangeHeatingAvailable()") );
}

//-------------------------------------------------------------------//
void ClubHeatingAvailable() {
  Serial.println( F("entering ClubHeatingAvailable()") );

  if (isClubHeatOn) {
    NormalHeatingClub();
    Serial.println(F("Heating C"));
  } else {
    FrostPreventionClub();
    Serial.println(F("Frost Prev. C"));
  }
  Serial.println( F("exiting ClubHeatingAvailable()") );
}

//-------------------------------------------------------------------//
void AirgunHeatingAvailable() {
  Serial.println( F("entering AirgunHeatingAvailable()") );

  if (isAirgunHeatOn) {
    NormalHeatingAirgun();
    Serial.println(F("Heating A"));
  } else {
    FrostPreventionAirgun();
    Serial.println(F("Frost Prev. A"));
  }
  Serial.println( F("exiting AirgunHeatingAvailable()") );
}

//-------------------Frost Prevention Range--------------------------//
void FrostPreventionRange() {
  Serial.println( F("entering FrostPreventionRange()") );

  if ((range_sensor.getTempCByIndex(0) <= (frost_setpoint - deadzone))) {
    digitalWrite(range_relay, HIGH);
    Serial.println(F("Range frost Heating"));
    lcd.setCursor(13, 1);
    lcd.print(F("  ON  F"));
  } else {
    if ((range_sensor.getTempCByIndex(0) >= (frost_setpoint + deadzone))) {
      digitalWrite(range_relay, LOW);
      lcd.setCursor(13, 1);
      lcd.print(F("  OFF F"));
    }
  }
  Serial.println( F("exiting FrostPreventionRange()") );
}

//--------------------Frost Prevention Club-------------------------//
void FrostPreventionClub() {
  Serial.println( F("entering FrostPreventionClub()") );

  if ((club_sensor.getTempCByIndex(0) <= (frost_setpoint - deadzone))) {
    digitalWrite(club_relay, HIGH);
    Serial.println(F("Club frost Heating"));
    lcd.setCursor(13, 2);
    lcd.print(F("  ON  F"));
  }
  else {
    if ((club_sensor.getTempCByIndex(0) >= (frost_setpoint + deadzone))) {
      digitalWrite(club_relay, LOW);
      lcd.setCursor(13, 2);
      lcd.print(F("  OFF F"));
    }
  }
  Serial.println( F("exiting FrostPreventionClub()") );
}

//---------------------Frost Prevention Airgun-----------------------//
void FrostPreventionAirgun() {
  Serial.println( F( "entering FrostPreventionAirgun()") );

  if ((airgun_sensor.getTempCByIndex(0) <= (frost_setpoint - deadzone))) {
    digitalWrite(airgun_relay, HIGH);
    Serial.println(F("Air frost Heating"));
    lcd.setCursor(13, 3);
    lcd.print(F("  ON  F"));
  }
  else {
    if ((airgun_sensor.getTempCByIndex(0) >= (frost_setpoint + deadzone))) {
      digitalWrite(airgun_relay, LOW);
      lcd.setCursor(13, 3);
      lcd.print(F("  OFF F"));
    }
  }
  Serial.println( F("exiting FrostPreventionAirgun()") );
}

//-------------------Normal Heating Range----------------------------//
void NormalHeatingRange() {
  Serial.println( F("entering NormalHeatingRange()") );

  if ((range_sensor.getTempCByIndex(0) <= (range_temperature_setpoint - deadzone))) {
    digitalWrite(range_relay, HIGH);
    Serial.println(F("Normal Heating R"));
    lcd.setCursor(13, 1);
    lcd.print(F("  ON  T"));
  } else {
    if ((range_sensor.getTempCByIndex(0) >= (range_temperature_setpoint + deadzone))) {
      digitalWrite(range_relay, LOW);
      lcd.setCursor(13, 1);
      lcd.print(F("  OFF T"));
    }
  }
  Serial.println( F("exiting NormalHeatingRange()") );
}

//--------------------Normal Heating Club ---------------------------//
void NormalHeatingClub() {
  Serial.println( F("entering NormalHeatingClub()") );

  if ((club_sensor.getTempCByIndex(0) <= (club_temperature_setpoint - deadzone))) {
    digitalWrite(club_relay, HIGH);
    Serial.println(F("Normal Heating C"));
    lcd.setCursor(13, 2);
    lcd.print(F("  ON  T"));
  } else {
    if ((club_sensor.getTempCByIndex(0) >= (club_temperature_setpoint + deadzone))) {
      digitalWrite(club_relay, LOW);
      lcd.setCursor(13, 2);
      lcd.print(F("  OFF T"));
    }
  }
  Serial.println( F("exiting NormalHeatingClub()") );
}

//---------------------Normal Heating Airgun-------------------------//
void NormalHeatingAirgun() {
  Serial.println( F("entering NormalHeatingAirgun()") );

  if ((airgun_sensor.getTempCByIndex(0) <= (airgun_temperature_setpoint - deadzone))) {
    digitalWrite(airgun_relay, HIGH);
    Serial.println(F("Normal Heating A"));
    lcd.setCursor(13, 3);
    lcd.print(F("  ON  T"));
  } else {
    if ((airgun_sensor.getTempCByIndex(0) >= (airgun_temperature_setpoint + deadzone))) {
      digitalWrite(airgun_relay, LOW);
      lcd.setCursor(13, 3);
      lcd.print(F("  OFF T"));
    }
  }
  Serial.println( F("exiting NormalHeatingAirgun()") );
}
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module
NOCOMNCVCCGNDINLED1PWRRelay Module