// This sketch is for Arduino Uno, with a clock, an LCD screen, a mini sloar panel, an infrared sensor and a relais
// Solar energy is measured by a mini solar panel attached to a window, If solar energy level exceeds a threshold voltage then a relais switches on an electric water heater.
// If by the end of the daylight the duration of the water heating is insufficient,(heating < 2 hours) then the water is further heated with main grid energy
// The IR sensor switches on the light of the LCD display
// Design by Kees Vink
// This software is open source.
//Components:
// Mini solar panel: positive on Analogue in A0
// clock: SCL op Analog in A5, SDA op Analog in A4, VCC op +5V
// LCD display: like clock (parallel to clock, both feeding and I2C)
// Relais: S on pin 10
//
//DS3231-AT24C32-IIC-High-Precision-Real-Time-Clock-Module-p-81066.html?akmClientCountry=NL&utm_design=41&utm_source=emarsys&utm_medium=Neworder171109&utm_campaign=trigger-emarsys&utm_content=winna&sc_src=email_2675773&sc_eh=5e919a3f442cad831&sc_llid=6449160&sc_lid=105229698&sc_uid=CdRKDGHiw9&cur_warehouse=CN
//IIC-I2C-2004-204-20-x-4-Character-LCD-Display-Module-Blue-p-908616.html?utm_design=41&utm_source=emarsys&utm_medium=Neworder171109&utm_campaign=trigger-emarsys&utm_content=winna&sc_src=email_2675773&sc_eh=5e919a3f442cad831&sc_llid=6449160&sc_lid=105229698&sc_uid=CdRKDGHiw9&cur_warehouse=UK
//UNO-R3-ATmega328P-Development-Board-For-No-Cable-p-964163.html?akmClientCountry=NL&utm_design=41&utm_source=emarsys&utm_medium=Neworder171109&utm_campaign=trigger-emarsys&utm_content=winna&sc_src=email_2675773&sc_eh=5e919a3f442cad831&sc_llid=6449160&sc_lid=105229698&sc_uid=CdRKDGHiw9&cur_warehouse=UK
//5V-PIR-Motion-Sensor-Adjustable-Time-Delay-Sensitive-Module-p-1244536.html?akmClientCountry=NL&utm_design=41&utm_source=emarsys&utm_medium=Neworder171109&utm_campaign=trigger-emarsys&utm_content=winna&sc_src=email_2675773&sc_eh=5e919a3f442cad831&sc_llid=15735979&sc_lid=105229698&sc_uid=CdRKDGHiw9&cur_warehouse=CN
//Portable-Mini-5V-60mA-0_3W-Solar-Epoxy-Panel-p-1144421.html?gmcCountry=NL¤cy=EUR&createTmp=1&utm_source=googleshopping&utm_medium=cpc_bgcs&utm_content=frank&utm_campaign=pla-nlg-rm-all-purchase-pc&gclid=Cj0KCQiAr8bwBRD4ARIsAHa4YyK8nkgjRuT2EZHUMS5KNWzDH5LIH1HWJv7SQh2aNpPYdD7o40G5GuQaAgu1EALw_wcB&cur_warehouse=CN
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define DS3231_I2C_ADDRESS 0x68
#include <SPI.h>
#include <DS3231.h>
DS3231 Clock;
RTClib RTC;
byte Year;
byte Month;
byte Day;
byte DoW;
byte Hour;
byte Minute;
byte Second;
bool Century=false;
bool h12;
bool PM;
byte ADay, AHour, AMinute, ASecond, ABits;
bool ADy, A12h, Apm;
bool Daltarief,Boiler_on,grid_time_window;
int minontime = 300; // minimal time (s) boiler_on before it will be turned off because of too low solar light to avoid too many swaps (pendelen)
long lastswitchtime,lastIRtime;
float V_threshold=2.35;
long starttime,sumtime,diftime,ontime,onLighttime;
int pinOut = 10;
int nswitchtimes = 0;
int solarpin = 0; // pin number of solar
// IR sensor:
int sensor = 2; // the pin that the sensor is atteched to
int state = LOW; // by default, no motion detected
int val = 0; // variable to store the sensor status (value)
#define BACKLIGHT_PIN 13
LiquidCrystal_I2C lcd(0x27, 2,1,0,4,5,6,7,3, POSITIVE); // Set the LCD I2C address
const uint8_t charBitmap[][8] = {
{ 0xc, 0x12, 0x12, 0xc, 0, 0, 0, 0 },
{ 0x6, 0x9, 0x9, 0x6, 0, 0, 0, 0 },
{ 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0, 0x0 },
{ 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0, 0x0 },
{ 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0, 0x0 },
{ 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0, 0x0 },
{ 0x0, 0x0, 0x0, 0x6, 0x9, 0x9, 0x6, 0x0 },
{ 0x0, 0x0, 0x0, 0xc, 0x12, 0x12, 0xc, 0x0 }
};
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val){
return( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers---------------------------------------------------------------------------------
byte bcdToDec(byte val){
return( (val/16*10) + (val%16) );
}
//-----------------------------------------------------------------------------------------------------------------------------------
void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year){
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // set DS3231 register pointer to 00h
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
// request seven bytes of data from DS3231 starting from register 00h
*second = bcdToDec(Wire.read() & 0x7f);
*minute = bcdToDec(Wire.read());
*hour = bcdToDec(Wire.read() & 0x3f);
*dayOfWeek = bcdToDec(Wire.read());
*dayOfMonth = bcdToDec(Wire.read());
*month = bcdToDec(Wire.read());
*year = bcdToDec(Wire.read());
}
//-----------------------------------------------------------------------------------------------------------------------------------
void displayTime(){
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
// retrieve data from DS3231
readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
&year);
// send it to the serial monitor
lcd.setCursor (0 ,0 );
lcd.print(dayOfMonth, DEC);
lcd.print("/");
lcd.print(month, DEC);
lcd.print("/");
lcd.print(year, DEC);
lcd.print(" ");
lcd.print(hour, DEC);
if (hour == 0){
sumtime = 0.;
nswitchtimes = 0; }
// convert the byte variable to a decimal number when displayed
lcd.print(":");
if (minute<10){
lcd.print("0");
}
lcd.print(minute, DEC);
lcd.print(":");
if (second<10){
lcd.print("0");
}
lcd.print(second, DEC);
lcd.setCursor (0 ,1 );
// lcd.print(" Day of week: ");
if ((hour>17) and (hour<20)) { //opwarmen op netstroom supplementair
grid_time_window=true;}
else{
grid_time_window=false;}
Daltarief=false;
if (hour>22){
Daltarief=true;}
if (hour<7){
Daltarief=true;}
//lcd.print("hour:");
//lcd.print(hour,DEC);
switch(dayOfWeek){
case 1:
lcd.print("Sunday");
Daltarief=true;
break;
case 2:
lcd.print("Monday");
break;
case 3:
lcd.print("Tuesday");
break;
case 4:
lcd.print("Wednesday");
break;
case 5:
lcd.print("Thursday");
break;
case 6:
lcd.print("Friday");
break;
case 7:
lcd.print("Saturday");
Daltarief=true;
break;
}
}
//-----------------------------------------------------------------------------------------------------------------------------------
void setup()
{
Wire.begin();
Serial.begin(9600);
pinMode(10, OUTPUT);
int charBitmapSize = (sizeof(charBitmap ) / sizeof (charBitmap[0]));
// Switch on the backlight
pinMode ( BACKLIGHT_PIN, OUTPUT );
digitalWrite ( BACKLIGHT_PIN, HIGH );
lcd.begin(19,4); // initialize the lcd
//pinMode(led, OUTPUT); // initalize LED as an output
pinMode(sensor, INPUT); // initialize IR sensor as an input
delay ( 1000 );
}
//-----------------------------------------------------------------------------------------------------------------------------------
void loop()
{
val = digitalRead(sensor); // read sensor value
if (val == HIGH) { // check if the sensor is HIGH
delay(100); // delay 100 milliseconds
if (state == LOW) {
DateTime now = RTC.now();
lastIRtime = now.unixtime();
lcd.backlight(); // set lcd light on
state = HIGH; // update variable state to HIGH
}
}
else {
delay(200); // delay 200 milliseconds
if (state == HIGH){
state = LOW; // update variable state to LOW
}
}
int solarvalue = analogRead(solarpin);
float solarvoltage = solarvalue*5.0/1024.0; //between 0 and 5 volts into integer values between 0 and 1023.
lcd.home (); // go home
lcd.clear ();
displayTime(); // display the real-time clock data on the Serial Monitor // set dal/piek en timewindow grid charge
lcd.setCursor ( 0, 2 );
if (grid_time_window)
{ lcd.print("Tijdraam Grid");}
else
{lcd.print("Tijdraam Solar"); }
lcd.setCursor ( 0, 3 ); // go to the next line lcd.setCursor(col, row)
if (Daltarief){
lcd.print("Low tariff");}
else{
lcd.print("Normal tariff"); }
delay(5000); // every second
lcd.home (); // go home
lcd.clear ();
lcd.setCursor ( 0, 0 ); // go to the next line lcd.setCursor(col, row)
if (solarvoltage>V_threshold)
lcd.print ("Sunlight sufficient");
else
lcd.print ("Sunlight insufficient");
DateTime now = RTC.now();
diftime = (now.unixtime()-starttime);
ontime = now.unixtime()-lastswitchtime;
onLighttime = now.unixtime()-lastIRtime;
if(float(onLighttime/60)>1.) // after 1 minute light out
lcd.noBacklight();
if ((grid_time_window) and (!Boiler_on) and ((float(sumtime/3600.)<2.))){
digitalWrite(pinOut, HIGH); // switch the heater on
Boiler_on = true;
DateTime now = RTC.now();
starttime=now.unixtime();
lastswitchtime=starttime;
nswitchtimes=nswitchtimes+1;
}
if (!grid_time_window){
if((ontime>minontime) and (Boiler_on) and (solarvoltage<V_threshold)){ // Boiler is on and will be turned off provided it has been on for longer than minontime (to avoid oscillation/pendelen in time of 5 min.)
digitalWrite(pinOut, LOW);
Boiler_on = false;
sumtime=sumtime+diftime;
nswitchtimes=nswitchtimes+1;}
else
if(Boiler_on){
sumtime=sumtime+diftime;
starttime=now.unixtime();
}
if((!Boiler_on)and(solarvoltage>=V_threshold)){ // Boiler was off and is now set on
digitalWrite(pinOut, HIGH);
Boiler_on = true;
DateTime now = RTC.now();
starttime=now.unixtime();
lastswitchtime=starttime;
nswitchtimes=nswitchtimes+1;
}}
lcd.setCursor (0 ,1 ); // go to the next line
if(Boiler_on)
lcd.print ("Boiler aan");
else
lcd.print ("Boiler uit");
lcd.print (" Nsw: ");
lcd.print (nswitchtimes);
lcd.setCursor (0 ,2 ); // go to the next line
lcd.print ("Laadduur dag: ");
lcd.print (float(sumtime/3600.));
//lcd.print (sumtime);
lcd.print (" u");
lcd.setCursor (0 ,3 ); // go to the next line
lcd.print ("V: ");
lcd.print (solarvoltage);
lcd.print (" Vt: ");
lcd.print (V_threshold);
delay ( 5000 );
}
Comments
Please log in or sign up to comment.