KeesVink
Published © GPL3+

Solar Switch for Water Heater

This sketch switches on/off a relais according to the availability of solar energy as measured by a mini solar panel.

BeginnerShowcase (no instructions)2,368
Solar Switch for Water Heater

Things used in this project

Hardware components

Alphanumeric LCD, 20 x 4
Alphanumeric LCD, 20 x 4
×1
Infrared Module (Generic)
Switches on LCD light if a person comes close to the display
×1
Solar Panel, 2.5 W
Solar Panel, 2.5 W
×1
Relay (generic)
Make sure it has sufficient capacity.
×1
DS3231M - ±5ppm, I2C Real-Time Clock
Maxim Integrated DS3231M - ±5ppm, I2C Real-Time Clock
any DS3231 RTC module
×1
Arduino UNO
Arduino UNO
×1

Story

Read more

Code

Solar switch

Arduino
Switches relais on if solar energy is sufficient. Switches also on by the end of the daylight, if water heating duration was yet insufficient.
// 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&currency=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 );

}

Credits

KeesVink
0 projects • 3 followers
Contact

Comments

Please log in or sign up to comment.