faball
Published © GPL3+

CronoThermostat PRO

Heating system control with system section solenoid valves.

IntermediateProtip432
CronoThermostat PRO

Things used in this project

Hardware components

Arduino UNO
Arduino UNO
×1
RGB LCD Shield Kit, 16x2 Character Display
RGB LCD Shield Kit, 16x2 Character Display
×1
Arduino Proto Shield
Arduino Proto Shield
×1
MCP9808
×1
Relay 4 channel 5V/220V
×1
DS3231
×1

Software apps and online services

Arduino IDE
Arduino IDE

Story

Read more

Schematics

Schema CRTPRO

Code

MAIN program

C/C++
general entry point
/*
 * programma CronoTermostato_FA
 * by Fabrizio Allevi
 * fabrizio . allevi @ tiscali . it
 */
#include <LiquidCrystal.h>
#include <Wire.h>
#include "Adafruit_MCP9808.h"
#include "Sodaq_DS3231.h"

//#define DEBUG true
#define DEBUG false

// initialize the library with the numbers of the interface pins (4-5-6-7-8-9-10dimmer)
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
Adafruit_MCP9808 tempsensor = Adafruit_MCP9808();

// menu principali
#define MAX_MENU 7
String sMenu[MAX_MENU] = {"                ",
                          "Programs        ",
                          "Days            ",
                          "Date   &   Time ",
                          "OfsTemp         ",
                          "Force           ",
                          "SwitchPlant     "};
#define LEVEL_ZERO 0
#define LEVEL_PROGRAMS 1
#define LEVEL_DAYS 2
#define LEVEL_DATETIME 3
#define LEVEL_OFSTEMP 4
#define LEVEL_FORCE 5
#define LEVEL_OFF 6
int mLevel = LEVEL_ZERO;
// sottomenu programmi
#define MAX_PROGS 4
String sPrograms[MAX_PROGS] = {"AllDay          ",
              							   "Morning+Evening ",
              							   "Early+Evening   ",
              							   "maiNtenance     " };
char cProgram[MAX_PROGS] = { 'A', 'M', 'E', 'N' };

int smLevel = 0;
// giorni settimana
#define MAX_DAYS 7
String sDays[MAX_DAYS] = { "Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab" };
String sMonth[12] = { "Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic" };

#define MAX_SEQ 6
////////////////////////////////////////////////////////////////////////////////
#define EEPROM_OFSP 0
// crono programmi
struct stProgram {
	int T[MAX_SEQ];  // in decimi di grado
	int HM[MAX_SEQ]; // hhmm nei 16bit hh=partealta mm=partebassa
} progs[MAX_PROGS] = {{{ 210, 195, 210, 195, 210, 195 }, { 0x071E, 0x091E, 0x0B00, 0x0D00, 0x0F00, 0x1700 }},
                      {{ 210, 195, 210, 195, 195, 195 }, { 0x071E, 0x091E, 0x0F00, 0x1700, 0x0000, 0x0000 }},
                      {{ 210, 195, 210, 195, 195, 195 }, { 0x051E, 0x0800, 0x0F00, 0x1700, 0x0000, 0x0000 }},
                      {{ 170, 170, 170, 170, 170, 170 }, { 0x0000, 0x173B, 0x0000, 0x0000, 0x0000, 0x0000 }}};
////////////////////////////////////////////////////////////////////////////////
#define EEPROM_OFSD (sizeof(progs))
// assegnazione programmi/giorni
int dayProg[MAX_DAYS] = { 0, 2, 2, 2, 2, 2, 1 };
////////////////////////////////////////////////////////////////////////////////
#define EEPROM_OFSF (sizeof(progs)+sizeof(dayProg))
// forzatura programmi a tempo e offset temperatura
bool bForce=false;
struct stForce {
	int hForce;
	unsigned long tFin;
	int ofsTemp;
  bool bOFF;
} forceData = { 0, 0, 0, false};
////////////////////////////////////////////////////////////////////////////////
int smValue = 0;
bool bProgram = false;
bool bFire = false;
int nProg = 0;
int arrayDT[5];
void showDateTimePage(bool bGet = false);
int smCursor = 0;

// define the button
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5
int lastBtn = btnNONE;

//read the button value
int read_buttons() {
	int adc_key_in = analogRead(0);          // read analog A0 value
	if (adc_key_in > 1000)
		return btnNONE;
	if (adc_key_in < 50)
		return btnRIGHT;
	if (adc_key_in < 250)
		return btnUP;
	if (adc_key_in < 450)
		return btnDOWN;
	if (adc_key_in < 650)
		return btnLEFT;
	if (adc_key_in < 850)
		return btnSELECT;
	return btnNONE;
}

byte cFire = 1;
byte fire[8] = { B00100, B00100, B01000, B10010, B10101, B10001, B01110, };
byte cNoFire = 2;
byte noFire[8] = { B00000, B00000, B00000, B00000, B00000, B10101, B11111, };

#define CALDAIA 11 // digital pin out 11
#define DIMMER 10 // pin 10 dimmer lcd
#define D_LOW 50 //50
#define D_MIDDLE 150  //100
#define D_HIGH 250  // 200

void setup() {
	if (DEBUG) {
		Serial.begin(57600);
		Serial.println("Cronotermostato Debug:");
	}
	// wire
	Wire.begin();
	pinMode(CALDAIA, OUTPUT);
	digitalWrite(CALDAIA, HIGH);  // spengo rele
	// RTC DS3231
	rtc.begin();
	// MCP9808
	if (!tempsensor.begin(0x18) && DEBUG)
		Serial.println("Couldn't find MCP9808! Check your connections and verify the address is correct.");
	tempsensor.setResolution(3); // sets the resolution 0-0.5C-30ms | 1-0.25C-65ms | 2-0.125C-130ms | 3-0.0625C-250ms
	// LCD
	lcd.begin(16, 2); // set up the LCD's number of columns and rows:
	lcd.createChar(cFire, fire);
	lcd.createChar(cNoFire, noFire);
  // force data for update init progs in flash
  //saveData((byte*) progs, sizeof(progs), EEPROM_OFSP);
  //saveData((byte*) dayProg, sizeof(dayProg), EEPROM_OFSD);
  //saveData((byte*) &forceData, sizeof(forceData), EEPROM_OFSF);
	// load from eeprom data
	loadData((byte*) progs, sizeof(progs), EEPROM_OFSP);
	loadData((byte*) dayProg, sizeof(dayProg), EEPROM_OFSD);
	loadData((byte*) &forceData, sizeof(forceData), EEPROM_OFSF);
	//showMainPage(readTemp());
	analogWrite(DIMMER, D_LOW);
	idlePage(readTemp(), true);
}

unsigned long msIdle = millis();
unsigned long msTemp = millis();
unsigned long msScheduler = millis();
unsigned long msLast = millis();
unsigned long msDimmer = millis();
bool bIdleState = true;
float lastTemp;

/**************************************************************/
void loop() {
	unsigned long msNow = millis();
	if (msNow < msLast) {  // gestione overflow
		msLast = msNow;
		if (msDimmer)
			msDimmer = msNow;
		if (msScheduler > msNow)
			msScheduler = msNow;
		if (msIdle > msNow)
			msIdle = msNow;
		if (msTemp > msNow)
			msTemp = msNow;
	}
	int newBtn = read_buttons();
	if (newBtn != btnNONE) {
		if (lastBtn == btnNONE) {
			if (DEBUG)
				Serial.println(newBtn);
			lastBtn = newBtn;
			//lcd.display();
			analogWrite(DIMMER, D_HIGH);
			handleMenus();  // gestione menus
			msDimmer = millis() + 5000;
			bIdleState = false;
		}
	} else {
		lastBtn = btnNONE;
		if (msDimmer) {
			if (msNow >= msDimmer + 5000) {
				analogWrite(DIMMER, D_LOW);
				if (!bProgram) {
					//showMainPage(readTemp());
					mLevel = LEVEL_ZERO;
					smLevel = 0;
					smValue = 0;
					msDimmer = 0;
					bIdleState = true;
					idlePage(readTemp(), true);
				}
			} else if (msNow >= msDimmer)
				analogWrite(DIMMER, D_MIDDLE);
		}
	}
	if (bForce || (msNow > msScheduler + 60000)) { // ogni 60sec
		float t = readTemp();
		scheduler(t);
		handleCaldaia();
		msScheduler = msNow;
    bForce=false;
	}
	if (msNow > msTemp + 12000) { // ogni 12sec
		lastTemp = readTemp();
		msTemp = msNow;
	}
	if (bIdleState) {
		if (msNow > msIdle + 1000) { // ogni 1sec
			idlePage(lastTemp, false);
			msIdle = msNow;
		}
	}
	msLast = msNow;
}
/*
 * Buttons:
 *    #up/page
 * #sx/- #dx/+      #enter
 *    #down/page
 */

Save parameters

C/C++
to store programs and settings
/*
 * gestione salvataggio parametri per programma CronoTermostato_FA
 * by Fabrizio Allevi
 * fabrizio . allevi @ tiscali . it
 */

// functions imported
void i2c_eeprom_write_byte( int deviceaddress, unsigned int eeaddress, byte data ) {
	int rdata = data;
	Wire.beginTransmission(deviceaddress);
	Wire.write((int)(eeaddress >> 8)); // MSB
	Wire.write((int)(eeaddress & 0xFF)); // LSB
	Wire.write(rdata);
	Wire.endTransmission();
}

// WARNING: address is a page address, 6-bit end will wrap around
// also, data can be maximum of about 30 bytes, because the Wire library has a buffer of 32 bytes
void i2c_eeprom_write_page( int deviceaddress, unsigned int eeaddresspage, byte* data, byte length ) {
	Wire.beginTransmission(deviceaddress);
	Wire.write((int)(eeaddresspage >> 8)); // MSB
	Wire.write((int)(eeaddresspage & 0xFF)); // LSB
	byte c;
	for ( c = 0; c < length; c++)
		Wire.write(data[c]);
	Wire.endTransmission();
}

byte i2c_eeprom_read_byte( int deviceaddress, unsigned int eeaddress ) {
	byte rdata = 0xFF;
	Wire.beginTransmission(deviceaddress);
	Wire.write((int)(eeaddress >> 8)); // MSB
	Wire.write((int)(eeaddress & 0xFF)); // LSB
	Wire.endTransmission();
	Wire.requestFrom(deviceaddress,1);
	if (Wire.available()) rdata = Wire.read();
	return rdata;
}

// maybe let's not read more than 30 or 32 bytes at a time!
void i2c_eeprom_read_buffer( int deviceaddress, unsigned int eeaddress, byte *buffer, int length ) {
	Wire.beginTransmission(deviceaddress);
	Wire.write((int)(eeaddress >> 8)); // MSB
	Wire.write((int)(eeaddress & 0xFF)); // LSB
	Wire.endTransmission();
	Wire.requestFrom(deviceaddress,length);
	int c = 0;
	for ( c = 0; c < length; c++ )
		if (Wire.available()) buffer[c] = Wire.read();
}

void saveData(byte *pb, int sizeTot, int addr) {
	// save data array ////////////////////////////////
	if(DEBUG) {
		Serial.print("sizeTot=");
		Serial.println(sizeTot);
	}
	int size=(sizeTot<16)?sizeTot:16;
	while(size) {
		i2c_eeprom_write_page(0x57, addr, pb, size);
		delay(100); //add a small delay
		if(DEBUG) {
			byte tmp[16];
			i2c_eeprom_read_buffer(0x57, addr, tmp, size);
			for(int c=0;c<size;c++) {
				Serial.print(tmp[c]);
				Serial.print('-');
			}
			Serial.print('\n');
		}
		pb+=size; addr+=size;
		sizeTot-=size;
		if(sizeTot<size)
			size=sizeTot;
	}
}

void loadData(byte *pb, int sizeTot, int addr) {
	// save data array ////////////////////////////////
	if(DEBUG) {
		Serial.print("sizeTot=");
		Serial.println(sizeTot);
	}
	int size=(sizeTot<16)?sizeTot:16;
	while(size) {
		i2c_eeprom_read_buffer(0x57, addr, pb, size);
		delay(100); //add a small delay
		if(DEBUG) {
			for(int c=0;c<size;c++) {
				Serial.print(pb[c]);
				Serial.print('-');
			}
			Serial.print('\n');
		}
		pb+=size; addr+=size;
		sizeTot-=size;
		if(sizeTot<size)
			size=sizeTot;
	}
}

Menu pages

C/C++
display handling
/*
 * gestione menus per programma CronoTermostato_FA
 * by Fabrizio Allevi
 * fabrizio . allevi @ tiscali . it
 */
 void changeText(int step, int max, int col, int row, int *idx, String *arr) {
	 if(step>0) {
		 if(*idx==max-1)
			 *idx=-1;
	 }
	 else {
		 if(*idx==0)
			 *idx=max;
	 }
	 *idx+=step;
	 lcd.setCursor(col,row);
	 lcd.print(arr[*idx]);
	 if(DEBUG) {
		 Serial.print("*idx=");
		 Serial.println(*idx);
	 }
 }

 void handleMenus() {
	 int dir=1;
   if(bIdleState) {
     showInfo();
     return;
   }
	 if(lastBtn==btnLEFT || lastBtn==btnRIGHT) {
		 if(lastBtn==btnLEFT)
			 dir=-1;
		 if(bProgram) {
			 if(mLevel==LEVEL_DATETIME) {
				 if(smLevel==4 && dir==1)
					 smLevel=-1;
				 else if(smLevel==0 && dir==-1)
					 smLevel=5;
				 smLevel+=dir;
				 if(smLevel<3)
					 lcd.setCursor(smLevel*3,1);
				 else
					 lcd.setCursor(2+smLevel*3,1);
			 }
			 else if(mLevel==LEVEL_PROGRAMS) {
				 if(smCursor==2 && dir==1) {
					 smCursor=-1;
					 if(smValue==5)
						 smValue=-1;
					 smValue+=dir;
					 printProgEvent();
				 }
				 else if(smCursor==0 && dir==-1) {
					 smCursor=3;
					 if(smValue==0)
						 smValue=MAX_SEQ;
					 smValue+=dir;
					 printProgEvent();
				 }
				 smCursor+=dir;
				 if(smCursor<2)
					 lcd.setCursor(smCursor*3,1);
				 else
					 lcd.setCursor(11,1);
			 }
		 }
		 else {
			 if(mLevel==LEVEL_PROGRAMS) {
					 changeText(dir,MAX_PROGS,0,1, &smLevel, sPrograms);
			 }
			 else if(mLevel==LEVEL_DAYS) {
				 changeText(dir,MAX_DAYS,12,0, &smLevel, sDays);
				 lcd.setCursor(0,1);
				 lcd.print(sPrograms[dayProg[smLevel]]);
			 }
		 }
	 }
	 else if(lastBtn==btnUP || lastBtn==btnDOWN) {
		 if(bProgram) {
      if(mLevel==LEVEL_OFF) {
        forceData.bOFF=!forceData.bOFF;
        updateOFF();
      }
      else if(mLevel==LEVEL_FORCE) {
				 if(lastBtn==btnDOWN)
					 dir=-1;
				 if((forceData.hForce==4 && dir==1) || (forceData.hForce==-4 && dir==-1))
					 forceData.hForce=dir*24;
				 else if((forceData.hForce==-24 && dir==1) || (forceData.hForce==24 && dir==-1))
					 forceData.hForce=dir*4*-1;
				 else if(forceData.hForce>4 || forceData.hForce<-4)
					 forceData.hForce+=dir*24;
				 else
					 forceData.hForce+=dir;
				 updateForce();
			 }
       else if(mLevel==LEVEL_OFSTEMP) {
				 if(lastBtn==btnDOWN)
					 dir=-1;
				 forceData.ofsTemp+=dir;
         updateOfs();
			 }
			 else if(mLevel==LEVEL_DATETIME) {
				 if(lastBtn==btnDOWN)
					 dir=-1;
				 arrayDT[smLevel]+=dir;
				 showDateTimePage();
			 }
			 else if(mLevel==LEVEL_DAYS) {
				 if(lastBtn==btnUP)
					 dir=-1;
				 changeText(dir,MAX_PROGS,0,1, &smValue, sPrograms);
			 }
			 else if(mLevel==LEVEL_PROGRAMS) {
				 if(lastBtn==btnDOWN)
					 dir=-1;
         int hour=progs[smLevel].HM[smValue]>>8;
         int min=progs[smLevel].HM[smValue]&0xFF;  
         if(smCursor==2) { //temp
           progs[smLevel].T[smValue]+=5*dir;
         }
         else {
           if(smCursor==0) {  //hour
             hour+=dir;
             if(hour<0)
              hour=23;
             hour%=24;
           }
           else if(smCursor==1) { //min
             min+=dir*15;
             if(min<0)
              min=45;
             min%=60;
           }
           progs[smLevel].HM[smValue]=(hour<<8)|(min&0xFF);
         }
				 printProgEvent();
			 }
		 }
		 else {
			 lcd.clear();
       if(lastBtn==btnUP)
				 dir=-1;
			 changeText(dir,MAX_MENU,0,0, &mLevel, sMenu);
			 lcd.setCursor(0,1);
       if(mLevel==LEVEL_OFF)
         updateOFF();
       else if(mLevel==LEVEL_FORCE)
         updateForce();
       else if(mLevel==LEVEL_OFSTEMP)
				 updateOfs();
			 else if(mLevel==LEVEL_DATETIME)
				 showDateTimePage(true);
			 else if(mLevel==LEVEL_DAYS) {
				 lcd.print(sPrograms[dayProg[0]]);
				 lcd.setCursor(12,0);
				 lcd.print(sDays[0]);
			 }
			 else if(mLevel==LEVEL_PROGRAMS)
				 lcd.print(sPrograms[0]);
			 else if(mLevel==LEVEL_ZERO)
				 showInfo();
			 smLevel=0;
		 }
	 }
	 else if(lastBtn==btnSELECT) {
		 if(mLevel!=LEVEL_ZERO) {
       if(!bProgram) {
  			 if(mLevel==LEVEL_PROGRAMS) {
  				 smValue=0;
  				 smCursor=0;
  				 printProgEvent();
  			 }
  			 else if(mLevel==LEVEL_DAYS) {
  				 //...
  			 }
  			 else if(mLevel==LEVEL_DATETIME) {
  				 smLevel=0;
  			 }
         else if(mLevel==LEVEL_OFSTEMP) {
  				 //...
  			 }
         else if(mLevel==LEVEL_FORCE) {
           //...
         }
         else if(mLevel==LEVEL_OFF) {
           //...
         }
  			 lcd.setCursor(0,1);
  			 lcd.blink();
  			 bProgram=true;
  		 }
  		 else {
  			 if(mLevel==LEVEL_PROGRAMS) {
  				 smValue=smCursor=0;
  				 mLevel=LEVEL_ZERO;
  				 changeText(1,MAX_MENU,0,0, &mLevel, sMenu);
  				 lcd.setCursor(0,1);
  				 lcd.print(sPrograms[smLevel]);
           saveData((byte*)progs, sizeof(progs), EEPROM_OFSP);
  			 }
  			 else if(mLevel==LEVEL_DAYS) {
  				 dayProg[smLevel]=smValue;
           saveData((byte*)dayProg, sizeof(dayProg), EEPROM_OFSD);
         }
         else if(mLevel==LEVEL_DATETIME)
  				 adjustDateTime();
         else if(mLevel==LEVEL_OFSTEMP) {
           saveData((byte*)&forceData, sizeof(forceData), EEPROM_OFSF);
         }
  			 else if(mLevel==LEVEL_FORCE) {
  				 // calcolo dell'endPoint
  				 if(DEBUG)
  					 Serial.println("setForce");
           int hf=forceData.hForce;
           if(hf==0) {
             forceData.tFin=0;
           }
           else {
             if(hf<0)
               hf*=-1; // date always in the future :)
             DateTime now = rtc.now(); //get the current date-time
    				 unsigned long nt=now.get();
    				 nt+=((unsigned long)hf*3600);
    				 if(DEBUG)
    					 Serial.println(nt);
    				 DateTime tFin(nt);
    				 if(DEBUG) {
    					 char txt[17];
    					 sprintf(txt, "%02d/%02d/%4d %02d:%02d", tFin.date(), tFin.month(), tFin.year(), tFin.hour(), tFin.minute());
    					 Serial.println(txt);
    					 Serial.println("endSetForce");
    				 }
    				 forceData.tFin=tFin.get();
           }
  				 saveData((byte*)&forceData, sizeof(forceData), EEPROM_OFSF);
  			 }
         else if(mLevel==LEVEL_OFF) {
           saveData((byte*)&forceData, sizeof(forceData), EEPROM_OFSF);
         }
  			 bProgram=false;
         bForce=true;
  			 lcd.noBlink();
  		 }
     }
	 }
 }

 void printProgEvent() {
	 lcd.setCursor(0,0);
	 lcd.print(sPrograms[smLevel]);
	 lcd.setCursor(13,0);
	 lcd.print("["+String(smValue)+"]");
	 lcd.setCursor(0,1);
	 char sTemp[5];
   float fTemp=progs[smLevel].T[smValue];
   fTemp/=10.0;
	 dtostrf(fTemp, 2, 1, sTemp);
	 char txt[17];
	 sprintf(txt, "%02d:%02d  ->  %s\xdf", progs[smLevel].HM[smValue]>>8, progs[smLevel].HM[smValue]&0xFF, sTemp);
	 lcd.print(txt);
 }

 void updateForce() {
   lcd.setCursor(0,1);
   if(forceData.hForce>23 || forceData.hForce<-23) {
     lcd.print(forceData.hForce/24);
     lcd.print(" day  ");
   }
   else {
     lcd.print(forceData.hForce);
     lcd.print(" hour ");
   }
   lcd.setCursor(0,1);
 }

 void updateOFF() {
   lcd.setCursor(0,1);
   if(forceData.bOFF) {
     lcd.print(" OFF  ");
   }
   else {
     lcd.print(" ON ");
   }
   lcd.setCursor(0,1);
 }

 void updateOfs() {
	 lcd.setCursor(0,1);
   char sTemp[5];
   float fTemp=forceData.ofsTemp;
   fTemp/=10.0;
	 dtostrf(fTemp, 2, 1, sTemp);
	 lcd.print(sTemp);
	 lcd.print("\xdf    ");
	 lcd.setCursor(0,1);
 }

 void showOnlyTemp(float t) {
	 lcd.clear();
	 char sTemp[6];
	 dtostrf(t, 2, 1, sTemp);
	 lcd.setCursor(6, 1);
	 sTemp[4]='\xdf';
	 sTemp[5]='\x0';
	 lcd.print(sTemp);
   lcd.setCursor(14, 1);
	 if(bFire)
		 lcd.write(byte(cFire));
   else
     lcd.write(byte(cNoFire));
 }

 void showInfo() {
	 char txt[17];
	 DateTime now = rtc.now(); //get the current date-time
	 lcd.clear();
	 lcd.setCursor(0, 0);
	 sprintf(txt, "%s %02d %s %02d:%02d", sDays[now.dayOfWeek()].c_str(), now.date(), sMonth[now.month()-1].c_str(), now.hour(), now.minute());
	 lcd.print(txt);
	 lcd.setCursor(0, 1);
	 char sTemp[6];
	 dtostrf(readTemp(), 2, 1, sTemp);
   sTemp[5]='\x0';
   char c=cNoFire; // no flame
   if(bFire)
     c=cFire;
	 sprintf(txt, "[%c]   %s\xdf  %c%c%c", cProgram[dayProg[now.dayOfWeek()]], sTemp, c,c,c);
   lcd.print(txt);
 }

 void showDateTimePage(bool bGet/*=false*/) {
	 char txt[17];
	 if(bGet) {
		 DateTime now=rtc.now(); //get the current date-time
		 arrayDT[0]=now.date();
		 arrayDT[1]=now.month();
		 arrayDT[2]=now.year();
		 arrayDT[3]=now.hour();
		 arrayDT[4]=now.minute();
	 }
	 lcd.setCursor(0, 1);
	 sprintf(txt, "%02d/%02d/%4d %02d:%02d", arrayDT[0], arrayDT[1], arrayDT[2], arrayDT[3], arrayDT[4]);
	 lcd.print(txt);
	 if(DEBUG)
		 Serial.println(txt);
 }

 void adjustDateTime() {
	 if(DEBUG) {
		 Serial.print(arrayDT[0]);
		 Serial.print(arrayDT[1]);
		 Serial.print(arrayDT[2]);
		 Serial.print(arrayDT[3]);
		 Serial.println(arrayDT[4]);
	 }
	 DateTime dtAdjust(arrayDT[2], arrayDT[1], arrayDT[0], arrayDT[3], arrayDT[4], 0);
	 rtc.setDateTime(dtAdjust);
 }

int pointLCD=0;
int lineLCD=0;
int ds=1;
 void idlePage(float t, bool bReset) {
   if(pointLCD==12 && lineLCD==0 && ds==1) {
     pointLCD=11;
     lineLCD=1;
     ds=-1;
     lcd.clear();
   }
   else if(bReset || (pointLCD==-1 && lineLCD==1 && ds==-1)) {
     pointLCD=0;
     lineLCD=0;
     ds=1;
     lcd.clear();
   }
   else if(ds==1) {
     lcd.scrollDisplayRight();
     pointLCD+=ds;
     return;
   }
   else if(ds==-1) {
     lcd.scrollDisplayLeft();
     pointLCD+=ds;
     return;
   }
   // temp
   char sTemp[6];
   dtostrf(t, 2, 1, sTemp);
   sTemp[4]='\xdf';
   sTemp[5]='\x0';
   lcd.setCursor(pointLCD, lineLCD);
   lcd.print(sTemp);
   // flame
   char sFlame[5];
   if(bFire) {
     sFlame[0]=sFlame[1]=sFlame[2]=sFlame[3]=cFire;
     sFlame[4]='\x0';
   }
   else {
     sFlame[0]=sFlame[1]=sFlame[2]=sFlame[3]=cNoFire;
     sFlame[4]='\x0';
   }
   lcd.setCursor(pointLCD, (lineLCD+1)%2);
   lcd.print(sFlame);
   //lcd.write(byte(cNoFire));
   pointLCD+=ds;
 }

Scheduler

C/C++
time base handling relay
/*
 * scheduler per programma CronoTermostato_FA
 * by Fabrizio Allevi
 * fabrizio . allevi @ tiscali . it
 */

 void handleCaldaia() {
	 if(bFire && !forceData.bOFF)
		 digitalWrite(CALDAIA, LOW);
	 else
		 digitalWrite(CALDAIA, HIGH);
 }

 float readTemp() {
	 tempsensor.wake();   // wake up, ready to read!
	 float c=tempsensor.readTempC();
   float o=forceData.ofsTemp;
   o/=10;
   o+=c;
	 if(DEBUG) {
		 Serial.print("TempRead: ");
     Serial.print(c, 4);
		 Serial.print("C - TempOfs: ");
     Serial.print(o, 4);
		 Serial.println("C");
	 }
	 tempsensor.shutdown_wake(1); // shutdown MSP9808 - power consumption ~0.1 mikro Ampere, stops temperature sampling
	 return o;
 }

void scheduler(float tempNow) {
	DateTime now = rtc.now(); //get the current date-time
  int hh=now.hour();
	int minuteNow=hh*60+now.minute();
	int idProg=dayProg[now.dayOfWeek()];
	if(DEBUG) {
		Serial.print("minuteNow=");
		Serial.print(minuteNow);
		Serial.print(" idProg=");
		Serial.println(idProg);
	}
  // controllo force functionality
  if(forceData.hForce) {
      if(forceData.tFin>now.get()) {
        if(forceData.hForce>0 && hh>7 && hh<23) // forza ma non di notte
          bFire=true;
        else
          bFire=false;
        if(DEBUG) {
      		Serial.print("forceFor=");
      		Serial.print(forceData.hForce);
      		Serial.println(" hour");
      	}
        return;
      }
      else {
        forceData.hForce=0;
        forceData.tFin=0;
        saveData((byte*)&forceData, sizeof(forceData), EEPROM_OFSF);
      }
  }
  // check sequences
	for(int seq=0; seq<MAX_SEQ-1; seq++) {
		int minI=(progs[idProg].HM[seq]>>8)*60+(progs[idProg].HM[seq]&0xFF);
		int minF=(progs[idProg].HM[seq+1]>>8)*60+(progs[idProg].HM[seq+1]&0xFF);
		if(minI<=minuteNow && (minuteNow<minF || minF==0)) { // trovata la seq in corso
      float setPtemp=progs[idProg].T[seq];  // setpoint di temperatura da tenere in questa sequenza
      setPtemp/=10.0;
      if(DEBUG) {
  			Serial.print("seq=");
  			Serial.print(seq);
  			Serial.print(" minI=");
  			Serial.print(minI);
        Serial.print(" minF=");
  			Serial.print(minF);
        Serial.print(" temp=");
  			Serial.println(setPtemp);
  		}
			if((!bFire && tempNow<setPtemp) || (bFire && tempNow<(setPtemp+0.15f)))
				bFire=true;
			else
				bFire=false;
      break;
		}
	}
}

Credits

faball
2 projects • 0 followers
Contact

Comments

Please log in or sign up to comment.