Previous part:
4. Storing data in the Amazon Cloud (HBase)
5. Turning the boiler on and off at the right time (Arduino)
5.1 Six boiler on/off intervals per hour (understanding how a thermostat works part II)
After finishing the previous part, I collected the temperature sensor data and the data from the photo resistor for a couple of weeks (when the normal thermostat would turn the boiler on and off).
The next step was to turn the Arduino into an actuator and let the Arduino turn the boiler on and off, Thus turning the Arduino into a thermostat.
Looking at the collected information I noticed that regardless of the temperature and difference between the set and actual temperature the thermostat would never turn the boiler on and off more than 6 times per hour. Regular intervals can be distinguished between every moment the thermostat turns the boiler on. Looking at the data in more detail I saw that when the temperature difference between the set and the actual temperature was smaller it would turn the boiler on for a fewer number of minutes than with a bigger difference, as can be seen in figure 9.
Figure 9: six boiler on/off intervals per hour
Knowing now what to search for, I searched the Internet for the interval value of a thermostat. And this was exactly how a thermostat worked. For most thermostats the interval per hour is a setting, ranging from 3 to 12 intervals per hour. Unless you have a system that does not have gas fired furnace, for example a heating system that uses excess heat from a power plant (something that is common in Amsterdam), you are supposed to turn your boiler on and off only a couple of times per hour. The first reason is for this is that if you constantly turn your boiler on and off you would break it. The second reason is that it takes a while before the room temperature increases after the boiler turns on the heat. This depends on the distance between the boiler and the thermostat and how long it takes for the room to absorb the heat form the radiators. This also explains why my normal thermostat sometimes overshoots and the room gets a lot warmer than the set temperature. In figure 9 you can see it actually takes 10 minutes before the room gets warmer after the boiler is turned on.
5.2 Thermostat Hardware (final breadboard layout schematic)
The hardware to turn the boiler on and off is the simple relay schematic from the ARDX starter kit http://oomlout.com/a/products/ardx/circ-11/ . The relay was added on a separate breadboard, which was added to the setup explained in part 2 of this blog post. The final breadboard layout and schematic for this project are shown in figure 11 and 12.
5.3 Arduino thermostat code
To control the boiler with the Arduino I used the same interval pattern. I created three run levels and three functions. The run levels are in the main loop()of the arduino.
The first run level (level 0) is the off state. In this level it checks, with the function frunScen(), weather it is necessary to go into on mode. If the temperature difference is more 3,5 degrees Celsius it goes to the second run level.
In the second run level (level 1) the Arduino decides for how long it should turn the boiler on. For this it uses the function fscenLenght() that takes the temperature difference as input. It then proceeds to the third and last run level.
The third run level (level 2) always runs for 10 minutes. This level takes the ‘duration the boiler has to be on’ as input. Every cycle in the third run level, the Arduino checks if the boiler should still be on, using the fboilerStat() function. If the amount of on time or the desired temperature has been reached in turns the boiler off. The fboilerStat() function ads 3.5 degrees Celsius to the set temperature to allow for a temperature decrease when the boiler is turned off. After ten minutes the run level goes back to 0.
To monitor the Arduino thermostat, the set boiler state and the time the Arduino decides the boiler should be on are also send to the Raspberry PI and subsequently forwarded to the Cloud server. Allowing analysis of the workings of the thermostat. The result can be seen in figure 10, showing that the Arduino perfectly mimics my normal Honeywell thermostat.
Thermostat main loop
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
… | |
//variables for calculating avarage temperature at Arduino | |
int avgTotalTemp = 0; | |
int avgTemp = 0; | |
int avgNumSamp = 0; | |
int avgMaxSamp =10; | |
//control variables | |
int startup = 0; //initial delay before temparature is set | |
int controllPin = 9; //pin connected to relay | |
int runScen = 0; //temperature run level 0 ,1 or 2 | |
unsigned long startScen = 0; //scenario started | |
unsigned long scenLength = 0; //minutes on | |
unsigned long maxScen = 600000; //10 minutes | |
int boilerStat = 0; //boiler status | |
//variables of inital check if arduino has been running long enough | |
int vrunl = 0; // | |
unsigned long startArdMillis = 0; //start millis | |
unsigned long nextRunl = 10000; //milisecond arduino has to be running | |
… | |
void loop() { | |
unsigned long currentMillis = millis(); | |
//vrunl is used to see of Arduino has been running for x number of second to make sure a viable actual temperature has been received or measured | |
if (vrunl == 0) { | |
startArdMillis = currentMillis; | |
vrunl = 1; | |
} else if (vrunl == 1) { | |
if (currentMillis – startArdMillis > nextRunl ){ | |
vrunl = 2; | |
} | |
} | |
… | |
// calculating avarage temperature using thermistor 1 value | |
avgNumSamp = avgNumSamp + 1; | |
if(avgNumSamp > avgMaxSamp) { | |
avgNumSamp = 1; | |
avgTotalTemp = 0; | |
} | |
avgTotalTemp = avgTotalTemp + thermistorValue; | |
if(avgNumSamp == avgMaxSamp){ | |
avgTemp = (int) round(avgTotalTemp/avgNumSamp); | |
startup = 1; | |
} | |
.. | |
//main boiler controll loop. | |
//3 run levels. | |
// run level 0 = initial, | |
// run level 1 = determine how many mintues boier shoudl be on, | |
// run level 2 = continuesly check of boier should be on for 10 minutes | |
if(runScen == 0) { //no scenario running | |
if(startup > 0 && vrunl ==2) { //wait for a time delay to make sure there is correctly measured avarage temperature | |
//check if controll should go to runlevel 1 | |
runScen = frunScen(avgTemp,sensorValue); | |
} | |
} else if (runScen == 1) { //start scenario run level 1 | |
startScen = currentMillis; | |
scenLength = fscenLength(avgTemp,sensorValue); //check how many seconds boiler should be on in 10 minute interval | |
runScen = 2; | |
boilerStat = 1; //turn boiler on | |
//sending minutes boiler on time to Rapsberry PI for monitoring purposses | |
unsigned long scenLengthCalc = (scenLength/(1000UL)); | |
int sendScenLength = (int) scenLengthCalc; | |
delay(50); | |
fxbesend("A06_",sendScenLength); | |
delay(50); | |
} else if (runScen == 2) { //runlevel 2 always runs for 10 minutes | |
if (boilerStat == 1 ) { //onley check boiler stat if boiler is on this to prevent on/off fluctuation af ter overshoot | |
boilerStat = fboilerStat(startScen,scenLength,currentMillis,avgTemp,sensorValue); //continuesly check if boiler should be on | |
} | |
if (boilerStat == 1 ) { //turn relay to on of boiler should be on | |
digitalWrite(controllPin, HIGH); | |
} else { | |
digitalWrite(controllPin, LOW); | |
} | |
//after 10 minutes go back to run level 0 | |
if(currentMillis – startScen > maxScen) { | |
runScen = 0; | |
} | |
} | |
… | |
} | |
.. |
Thermostat functions
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//function to determine if boiler controll loop should go to run level 1 | |
int frunScen (int actTemp, int setTemp) { | |
if ( (setTemp*10) – actTemp > 35) { | |
return 1; | |
} else { | |
return 0; | |
} | |
} | |
//function to determine how many seconds boiler should go on within 10 minute interval | |
unsigned long fscenLength(int actTemp, int setTemp) { | |
unsigned long scnel; | |
// int iscnel = 0; | |
if ( (setTemp*10) – actTemp > 260) { | |
scnel = (6UL*60UL*1000UL); | |
} else if ( (setTemp*10) – actTemp > 160) { | |
scnel = (5UL*60UL*1000UL); | |
} else if ( (setTemp*10) – actTemp > 70) { | |
scnel = (4UL*60UL*1000UL); | |
} else if ( (setTemp*10) – actTemp > 40) { | |
scnel = (3UL*60UL*1000UL); | |
} else { | |
scnel = (2UL*60UL*1000UL); | |
} | |
return scnel; | |
} | |
//function to check if boiler should stay on or go off | |
int fboilerStat(unsigned long starts,unsigned long scenl,unsigned long cur ,int actTemp, int setTemp) { | |
if (actTemp – (setTemp*10) < 35){ //criteria 1: only say on if act temperature is below set temperature + margin | |
if (cur – starts < scenl) { //criteria 2: only stay on of boiler has not been on for the number of seconds determined by fscenLength | |
return 1; //stay on | |
} else { | |
return 0; //go off (because boiler was on for number of minues determined by fscenLength | |
} | |
} else { | |
return 2; //go off (2 is used to monitor overflow) | |
} | |
} |
Figure 11: Final breadboard layout
Next part:
6. Using outside temperature and scenarios to control an Arduino from a Raspberry PI
Reblogged this on Dinesh Ram Kali..
Pingback: Enabling technologies: how to build your own NEST | SmartDomus