//This project switch ON the relay when the current
//temperature exceeds the default temperature selected
//with the potentiometer (last t° value is saved in EEPROM).
//If the potentiometer is at position zero, then the 2 pushbuttons
//are active and replace the potentiometer (selected t° value
//is saved in EEPROM).
//The other switch allows to force the relay ON. In this case,
//changes in the value of the potentiometer are no longer saved
//in the EEPROM and the 2 pushbuttons are active (last t° value
//is saved in EEPROM).
//The idea of this project is to start up a circulator
//and circulate the heating water in the radiators of a house.
//This project uses either a 1602 LCD or a 1602 I2C LCD screen.
//This is to compare the operating speed of the whole project.
//The LCD 1602 option turns out to be faster, so it's the
//preferred choice if you don't need to use the inputs/outputs
//required for this screen for other purposes.
//This project is also a test for various interfaces, some of
//which will not be used in the real project (ex : 7 segments display or the potentiometer)!
// include the library code:
#include <IRremote.h>
//For WOKWI Simulator
#include <TM1637TinyDisplay.h>
// Define Digital Pins
#define CLK 0
#define DIO 1
// Instantiate TM1637TinyDisplay Class
TM1637TinyDisplay display(CLK, DIO);
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 7, 6, 5, 4);
//#include <Adafruit_LiquidCrystal.h>
//Adafruit_LiquidCrystal lcd_1(0);
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR 0x27
//For WOKWI Simulator
#define LCD_COLUMNS 16
#define LCD_LINES 4
//For real Hardware
//#define LCD_COLUMNS 16
//#define LCD_LINES 2
LiquidCrystal_I2C lcd_1(I2C_ADDR, LCD_COLUMNS, LCD_LINES);
#include <EEPROM.h>
#define EEPROM_SIZE 512
float requestedTemp = 0; // variable to be updated by the interrupt
float requestedTempDefault = 30;
float lastTemp = 0;
float aValue = 0;
float offsetTemp = 0;
float tempPin = A0;
float potPin = A1;
float potValue = 0;
float lastTempValue = 0;
float voltage = 0;
float lastvoltage = 0;
float reading = 0;
int runningPin = 13;
int relayPin = 8;
int switchPin = 9;
int switchValue = 0;
int lcd_1_backlight = 10;
int lcd_1_backlightValue = 0;
int aInt = 0;
int relayKey = 0;
int lightKey = 1;
int lightDelay_Default = 60;
int lightDelay = lightDelay_Default;
int stayKey = 0;
//int celsius = 0;
//int farenheit = 0;
int lcd_I2C = 1;
int WOKWI_Simulator = 1;
//For WOKWI Simulator
int IRPin = A2;
//For real Hardware
//int IRPin = 11;
#define PIN_RECEIVER IRPin // Signal Pin of IR receiver
IRrecv receiver(PIN_RECEIVER);
char c = 0;
String str_temp = "";
String str_temp_1 = "";
const float BETA = 3950; // should match the Beta Coefficient of the thermistor
/////////////////////////////////////////
void setup()
{
receiver.enableIRIn(); // Start the receiver
if (WOKWI_Simulator == 1) {
display.begin();
}
//Serial.begin(9600); //turn on serial communication
//Serial.begin(115200);
// set up the LCD's number of columns and rows:
if (lcd_I2C == 0)
{
lcd.begin(16, 2);
} else {
lcd_1.setBacklight(0);
lcd_1.begin(16, 2);
}
requestedTemp = requestedTempDefault;
EEPROM.get(lastTemp, aValue);
if (aValue > 0 && aValue < 255)
{
requestedTemp = aValue;
}
pinMode(relayPin, OUTPUT);
digitalWrite(relayPin, HIGH);
pinMode(runningPin, OUTPUT);
pinMode(tempPin, INPUT);
pinMode(potPin, INPUT);
pinMode(switchPin, INPUT);
pinMode(lcd_1_backlight, INPUT);
//enable interrupt 0 (pin 2) which is connected to a button
//jump to the increment function on falling edge
attachInterrupt(0, tempDown, RISING);
attachInterrupt(1, tempUp, RISING);
// Print a message to the LCD.
/*
lcd.setCursor(0, 0);
lcd.print("Min T""\xb2"":");
//lcd.print("Min T");
//lcd.print(char(178));
//lcd.print(":");
lcd.setCursor(0, 1);
lcd.print("Cur T""\xb2"":");
lcd.setCursor(15, 0);
lcd.print("C");
lcd.setCursor(15, 1);
lcd.print("C");
*/
/*
disp_pos(0, 0);
disp_text("Min T""\xb2"":");
disp_pos(0, 1);
disp_text("Cur T""\xb2"":");
*/
disp_pos(0, 0);
disp_text("Min Te:");
disp_pos(0, 1);
disp_text("Cur Te:");
disp_pos(15, 0);
disp_text("C");
disp_pos(15, 1);
disp_text("C");
}
void loop()
{
if (stayKey == 1) {
lightDelay = lightDelay_Default;
lightKey = 1;
} else {
if (lightDelay > 0) {lightDelay--;}
}
// Checks received an IR signal
if (receiver.decode()) {
if (receiver.decodedIRData.command == 9 || receiver.decodedIRData.command == 226) {
if (stayKey == 1) {
stayKey = 0;
} else {
stayKey = 1;
}
}
translateIR();
aInt = receiver.decodedIRData.command;
if (WOKWI_Simulator == 1) {
display.showNumber(aInt);
}
if (receiver.decodedIRData.command == 2 || receiver.decodedIRData.command == 21) {
lightDelay = lightDelay_Default;
lightKey = 1;
tempUp();
}
if (receiver.decodedIRData.command == 152 || receiver.decodedIRData.command == 7) {
lightDelay = lightDelay_Default;
lightKey = 1;
tempDown();
}
if (receiver.decodedIRData.command == 67 || receiver.decodedIRData.command == 194) {
if (lightKey == 1) {
stayKey = 0;
disp_pos(8, 1);
disp_text("D* -- C");
lightDelay = 0;
lightKey = 0;
} else {
lightDelay = lightDelay_Default;
lightKey = 1;
}
}
if (receiver.decodedIRData.command == 71 || receiver.decodedIRData.command == 34) {
lightDelay = lightDelay_Default;
lightKey = 1;
if (relayKey == 1) {
relayKey = 0;
} else {
relayKey = 1;
}
}
receiver.resume(); // Receive the next value
}
/////////////////////
delay(1000); //Slow down Loop
if (lcd_I2C == 1)
{
if (lightDelay > 0) {
lightKey = 1;
} else {
lightKey = 0;
}
if (lightKey == 0) {
lcd_1.setBacklight(0);
lcd_1_backlightValue = digitalRead(lcd_1_backlight);
if (lcd_1_backlightValue == 0)
{
lcd_1.setBacklight(1);
} else {
lcd_1.setBacklight(0);
}
} else {
lcd_1.setBacklight(1);
}
}
//lcd_1.setBacklight(1);
switchValue = digitalRead(switchPin);
//switchValue = 1;
if (switchValue == 1 || relayKey == 1)
{
lightDelay = lightDelay_Default;
lightKey = 1;
digitalWrite(runningPin, HIGH);
if (WOKWI_Simulator == 0) {
digitalWrite(relayPin, LOW);
} else {
digitalWrite(relayPin, HIGH);
}
disp_pos(8, 0);
disp_text("Rel ON");
disp_pos(8, 1);
disp_text("Rel ON");
delay(1000);
disp_pos(8, 0);
disp_text(" ");
disp_pos(8, 1);
disp_text(" ");
delay(1000);
}
reading = analogRead(potPin);
// converting reading to voltage, for 3.3v arduino use 3.3
voltage = reading * (5.0 / 1023.0);
potValue = ( (voltage - 0.5) * 10) - 10 ;
//For WOKWI Simulator
if (WOKWI_Simulator == 1) {
//display.showNumber(int(voltage * 1000));
//display.showNumberDec(int(voltage * 1000), (0x80 >> 0), true);
display.showNumberDec(int(voltage * 1000), (0x80 >> 5), true); //This will avoid the double dot (if display does not allow single dot)
disp_pos(0, 2);
disp_text("volt=");
disp_float(voltage);
}
///////////////////////////////////////////////////
///////////////////////////////////////////////////
///////////////////////////////////////////////////
//if (voltage > 0 && (voltage != lastvoltage) && (switchValue != 1 && relayKey != 1) ) {
if (voltage > 0 && (voltage != lastvoltage) && (switchValue != 1 && relayKey != 1) ) {
requestedTemp = potValue + requestedTempDefault;
lastvoltage = voltage;
}
if (requestedTemp < 100)
{
clearspot(13,0);
}
disp_pos(8, 0);
disp_float(requestedTemp);
lastTempValue = getTemp();
if (lastTempValue < 100)
{
clearspot(13,1);
}
disp_pos(8, 1);
//disp_text(lastTempValue);
if (lastTempValue >= (requestedTemp - offsetTemp) && (switchValue != 1 && relayKey != 1) )
{
delay(1000);
disp_text("Rel ON ");
digitalWrite(runningPin, LOW);
delay(1000);
disp_pos(8, 1);
disp_text(" ");
disp_pos(8, 1);
disp_float(lastTempValue);
digitalWrite(runningPin, HIGH);
if (WOKWI_Simulator == 0) {
digitalWrite(relayPin, LOW);
} else {
digitalWrite(relayPin, HIGH);
}
}
else if (lastTempValue < (requestedTemp + offsetTemp) && (switchValue != 1 && relayKey != 1) )
{
disp_float(lastTempValue);
digitalWrite(runningPin, LOW);
//delay(2000);
//digitalWrite(runningPin, HIGH);
//delay(2000);
if (WOKWI_Simulator == 0) {
digitalWrite(relayPin, HIGH);
} else {
digitalWrite(relayPin, LOW);
}
//delay(1000);
} /* else {
digitalWrite(runningPin, LOW);
delay(1000);
digitalWrite(runningPin, HIGH);
delay(1000);
} */
/*
//Serial.println(requestedTemp, DEC); //print x to serial monitor
Serial.print("REQ Temperature: ");
Serial.print(requestedTemp);
Serial.println(" ?");
*/
}
void translateIR()
{
disp_pos(8, 1);
if (WOKWI_Simulator == 0) {
// Takes command based on IR code received
switch (receiver.decodedIRData.command) {
case 7:
disp_text("MINUS");
break;
case 9:
if (stayKey == 1) {
disp_text("L* ++ *");
} else {
disp_text("L* -- C");
}
break;
case 21:
disp_text("PLUS ");
break;
case 67:
disp_text("LIGHT");
break;
case 71:
disp_text("RELAY");
break;
default:
disp_text("K:");
disp_int(receiver.decodedIRData.command);
disp_text(" ");
}
} else {
// Takes command based on IR code received
switch (receiver.decodedIRData.command) {
case 162:
disp_text("POWER");
break;
case 226:
//disp_text("MENU ");
if (stayKey == 1) {
disp_text("L* ++ *");
} else {
disp_text("L* -- C");
}
break;
case 34:
//disp_text("TEST ");
disp_text("RELAY");
break;
case 2:
disp_text("PLUS ");
break;
case 194:
//disp_text("BACK ");
disp_text("LIGHT");
break;
case 224:
disp_text("PREV.");
break;
case 168:
disp_text("PLAY ");
break;
case 144:
disp_text("NEXT ");
break;
case 104:
disp_text("k: 0 ");
break;
case 152:
disp_text("MINUS");
break;
case 176:
disp_text("k: C ");
break;
case 48:
disp_text("k: 1 ");
break;
case 24:
disp_text("k: 2 ");
break;
case 122:
disp_text("k: 3 ");
break;
case 16:
disp_text("k: 4 ");
break;
case 56:
disp_text("k: 5 ");
break;
case 90:
disp_text("k: 6 ");
break;
case 66:
disp_text("k: 7 ");
break;
case 74:
disp_text("k: 8 ");
break;
case 82:
disp_text("k: 9 ");
break;
default:
disp_text("K:");
disp_int(receiver.decodedIRData.command);
disp_text(" ");
}
}
}
// Interrupt service routine for interrupt 0
void tempUp()
{
lightDelay = lightDelay_Default;
lightKey = 1;
//if (voltage <= 0.5) {
requestedTemp = round( (requestedTemp + 0.5) * 10) / 10.0;
EEPROM.put(lastTemp, requestedTemp);
//}
/*
if (WOKWI_Simulator == 1) {
disp_pos(10, 2);
disp_text("v=");
disp_float(voltage);
}
*/
}
void tempDown()
{
lightDelay = lightDelay_Default;
lightKey = 1;
//if (voltage <= 0.5) {
requestedTemp = round( (requestedTemp - 0.5) * 10) / 10.0;
EEPROM.put(lastTemp, requestedTemp);
//}
/*
if (WOKWI_Simulator == 1) {
disp_pos(10, 2);
disp_text("v=");
disp_float(voltage);
}
*/
}
float getTemp()
{
//For WOKWI Simulator
int analogValue = analogRead(tempPin);
//float analogValue = analogRead(tempPin);
float celsius = 1 / (log(1 / (1023. / analogValue - 1)) / BETA + 1.0 / 298.15) - 273.15;
/*
//For Tinkercad Simulator
reading = analogRead(tempPin);
// converting that reading to voltage, for 3.3v arduino use 3.3
voltage = reading * (5.0 / 1023.0);
// now print out the temperature
float temperatureC = ( (voltage - 0.5) * 100 ) - 255;
//float temperatureC = ( (voltage - 0.5) * 100 ) - 255 + 4.44; //OK
*/
/*
celsius = map(((analogRead(tempPin) - 20) * 3.04), 0, 1023, -40, 125);
celsius = celsius - 170;
farenheit = ((celsius * 9) / 5 + 32);
*/
//For WOKWI Simulator
//temperatureC = celsius;
//temperatureC = 30;
/*
Serial.print("Temperature: ");
Serial.print(temperatureC);
//Serial.print(str_temp);
Serial.println(" ?");
*/
//return temperatureC;
return celsius;
//return farenheit;
}
void disp_pos(int x,int y)
{
if (lcd_I2C == 0)
{
lcd.setCursor(x,y);
} else {
lcd_1.setCursor(x,y);
}
}
void disp_int(int i)
{
if (lcd_I2C == 0)
{
lcd.print(i);
} else {
lcd_1.print(i);
}
}
void disp_float(float f)
{
if (lcd_I2C == 0)
{
lcd.print(f,2);
} else {
lcd_1.print(f,2);
}
}
/*
//CRASH AT INITIALISATION TIME WITH Tinkercad IF str_temp = String(...) is used!
void disp_float(float fl)
{
//float Loc_v = fl;
//str_temp = String(Loc_v, 2); //CRASH WITH Tinkercad
//str_temp = String(Loc_v); //CRASH WITH Tinkercad
str_temp = String(fl, 2);
if (lcd_I2C == 0)
{
lcd.print(str_temp);
} else {
lcd_1.print(str_temp);
}
}
*/
void disp_text(String s)
{
if (lcd_I2C == 0)
{
lcd.print(s);
} else {
lcd_1.print(s);
}
}
void clearspot(int x,int y)
{
disp_pos(x,y);
disp_text(" ");
}