Project tutorial
Arduino Uno Water Heater Thermostat for PWM Pumps

Arduino Uno Water Heater Thermostat for PWM Pumps © GPL3+

This thermostat can be used with any kind of water boiler and any kind of pump.

  • 997 views
  • 0 comments
  • 2 respects

Components and supplies

Necessary tools and machines

Apps and online services

About this project

There are hundreds of homemade thermostats with various MCU and sensors. Some are very simple, others are very sophisticated. However I decided to build my own thermostat especially for a solar panel and a new generation high efficiency PWM pumps. Moreover this thermostat offers:

  • Cost less than €20, all included, by the use of very low cost components like the Arduino Uno R3, and two waterproof DS18B20, and an SSR.
  • Can be use with any kind of water boiler and any kind of pump:

o Regular pump or Pressure regulated high-efficiency pump

o High-efficiency pump with a PWM profile for a rising characteristic curve

o High-efficiency pump with a PWM profile for a falling characteristic curve

  • All parameters can be easily set and recovered after a restart.
  • Can be built by any beginner in soldering some electronic components.

The manual explains step by step how to build this device, with an Arduino Uno Rev.3.

Code

Thermostat codeArduino
Updated version can be found here : https://github.com/philippedc/Arduino-Uno-Water-Heater-Thermostat-for-PWM-pumps
/*

Water Heater Thermostat is a device that controls any kind of pump in a solar system 
or in a classical boiler

The operating principle is as follows:
- a DS18B20 probe at the heat source compares the temperature with a 
second DS18B20 probe placed in hot water tank.
- beyond a deltaTon threshold the pump is started, stops below deltaToff
- pump starts when Tmini freezes
- an alarm system reports the Tmaxi temperature exceedance
- the thresholds - deltaTon, deltaToff, Tmaxi and Tmini - as well as the pump model are 
configurable and backed up without power
- support of the PWM control for externally controlled pumps.
  Following the measurements made on the Steca TR 503 regulator, the PWM signal has the 
  the following characteristics:
  - 250Hz with variable cyclic ratio from 0 (stop) to 100% (total pump operation) under 10V,
  - the pump is continuously supplied by the 230V,
  - 50% at start-up, the ratio gradually increases to 100%,
  - when Tcumulus reaches deltaTpwm, the cyclic ratio may decrease down to 25%.

The programme provides for:
- 1 Arduino Uno R3
- 2 DS18B20 temperature sensor 
- 1 resistor of 4.7k between data bus and +5V of DS18B20 sensors
- 1 SRG
- 1 16x2 LCD display for Arduino with I2C extension for serial mode,
- 3 push buttons

_________________________________________________________________
|                                                               |
|       author : Philippe de Craene <dcphilippe@yahoo.fr>       |
|           any feedback is welcome                             |
_________________________________________________________________

Hardware pinup:
---------------

numeric output  2   => SSR 		= logic I active SSR drive
numeric output  3   => PWM 		= drives the 250Hz PWM signal, output 3 required for Timer2
numeric output  4   => ALARM 	= red LED
numeric output  5   => SSR_INV  = logic 0 active SSR drive
numeric output  7   => DS18B20 	= 1-Wire data bus for DS18B20
numeric output  8   => ENTRY 	= push-button
numeric output  9   => PLUS 	= push-button
numeric output 10   => MINUS	= bouton poussoir
analog input   A4   => SDA for display
analog input   A5   => SCL for display


Versions history:
-----------------

version 1    - 18 aot 2018       - transformation pour sondes numriques et le LCD avec I2C
version 1.11 - 20 aot 2018       - correction  + optimisation 
version 1.2  - 28 aot 2018       - corrections de bugs
version 1.3  - 25 nov. 2018       - adaptation pour SSR actif  LOW
version 1.4  - 20 mai  2019       - mise  jour des liens pour tlcharger les bibliothques
version 1.41 - 22 aout 2019       - mises  jour diverses
version 2.0  - 5 april 2020       - update for boiler driven by SSR + ALARM management + English translation
 
*/

#include <EEPROM.h>
#include <Wire.h>  
#include <OneWire.h>             // https://github.com/PaulStoffregen/OneWire
#include <LiquidCrystal_I2C.h>   // https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library

// Inputs/outputs:
// A4 => SDA for display
// A5 => SCL for display
const byte ENTRYpin   = 8;    // 3 push-buttons
const byte MINUSpin   = 9;
const byte PLUSpin    = 10;
const byte DS18B20    = 7;    // 1-Wire data for DS18B20
const byte SSRpin     = 2;    // SSR drive + yellow LED
const byte SSR_INVpin = 5;    // inverted SSR drive
const byte PWMpin     = 3;    // 244Hz PWM signal + blue LED
const byte ALARMpin   = 4;    // red LED for ALARM

// default parameters:
int Tmaxi_d      = 85;        // first use maximum temperature = 85C
int Tmini_d      = -1;        // first use frost temperature = -1C
int deltaTon_d   =  5;        // first use starting threshold = 5K
int deltaToff_d  =  2;        // first use stoping threshold = 2K
int deltaTpwm_d  =  1;        // first use PWM ration management threshold = 1K
byte pump_model_d = 0;        // pump model, first use = 0
                              // 0: non-PWM pump, 1: rising PWM , 2: falling PWM
byte ssr_rule_d   = 0;        // SSR usage drive, first use =0
                              // 0: pump, 1: boiler, 2: Tmini alarm, 3: Tmaxi alarm

// LCD with I2C declaration :
LiquidCrystal_I2C lcd(0x27, 16, 2);

// specific symbols to display:
byte degree[8] =        { 0b11100,  0b10100,  0b11100,  0b00000,  0b00000,  0b00000,  0b00000,  0b00000};
byte fleche_bas[8] =    { 0b00100,  0b00100,  0b00100,  0b00100,  0b00100,  0b11111,  0b01110,  0b00100};
byte fleche_haut[8] =   { 0b00100,  0b01110,  0b11111,  0b00100,  0b00100,  0b00100,  0b00100,  0b00100};
byte fleche_stable[8] = { 0b00100,  0b01110,  0b11111,  0b00100,  0b00100,  0b11111,  0b01110,  0b00100};

// DS18B20 declaration:
OneWire sondeDS(DS18B20);

// variables for temperature management:
float Tsource, Tcumulus, memo_Tcumulus;  // past value for tendency calculation
int deltaTon, deltaToff, deltaTpwm;
int Tmaxi, Tmini;
byte tendency = 4;             // tendency 2=increase, 3=decrese, 4=stable

// variables for process management:
byte pump_model;               // 0: non PWM, 1: rising PWM, 2: falling PWM
byte ssr_rule;                 // 0: pump, 1: boiler, 2: Tmini alarm, 3: Tmaxi alarm
byte state, memo_state = 0;    // give the overoll state of the device:
                               // 0: off, 1: on, 2: Tmini, 3: Tmaxi, 4: forced, 5: boiler
bool mforce = LOW;             // flag if pump always ON
bool boiler = LOW;             // flag if a boiler is driven
unsigned long memo_tempo = 0;  // flag for time count

// variables for PWM:
byte ratio = 0;                // initial PWM duty cycle
byte PWM;                      // final PWM (take in account if Rising or Falling PWM)
const byte PWMmini = 25;       // minimum ratio when pup is active

// variables for push-buttons & menus
const char label_pump[] = {'A', 'M', 'G', 'T', 'F', 'S' };
       // label displayed : A: off, M: on, G: Tmini, T: Tmaxi, F: forced, S: boiler
byte ret_push_button, memo_ret_push_button = 0;   // function return value when a push-button is pushed
String label;
byte window = 0;               // index of window to display
byte windowsTotal = 11;        // total number of windows (including window 0)
byte count_before_timeout = 0;
byte timeout = 60;             // display switch off delay
bool eeprom = false;           // flag a backup needed

//
// SETUP
//_____________________________________________________________________________________________

void setup() {

  lcd.begin();

  pinMode (ENTRYpin,   INPUT_PULLUP);
  pinMode (PLUSpin,    INPUT_PULLUP);
  pinMode (MINUSpin,   INPUT_PULLUP);
  pinMode (ALARMpin,   OUTPUT);
  pinMode (SSRpin,     OUTPUT);
  pinMode (SSR_INVpin, OUTPUT);
  pinMode (PWMpin,     OUTPUT);

// Timer2 set for PWM at 244Hz
  TCCR2A = 0b00100011;  // Fast PWM Mode
  TCCR2B = 0b00000110;  // formula => binary = 62500 / (F * 256)
  OCR2B = 0;            // duty ration is 0 at startup
  
// LCD => special homemade characters are assigned
  lcd.createChar(1, degree );        // =1, etc...
  lcd.createChar(2, fleche_haut );
  lcd.createChar(3, fleche_stable );
  lcd.createChar(4, fleche_bas );

// get data from the EEPROM, type byte. So offset of 50 for negative temperature values :
// defaut EEPROM content is 255 at very first usage.
  if(EEPROM.read(0) < 70) { deltaTon = EEPROM.read(0) - 50; }
  else { EEPROM.write(0, deltaTon_d + 50); deltaTon = deltaTon_d; }
  if(EEPROM.read(1) < 60) { deltaToff = EEPROM.read(1) - 50; }
  else { EEPROM.write(1, deltaToff_d + 50); deltaToff = deltaToff_d; }
  if(EEPROM.read(2) < 60) { deltaTpwm = EEPROM.read(2) - 50; }
  else { EEPROM.write(2, deltaTpwm_d + 50); deltaTpwm = deltaTpwm_d; }
  if(EEPROM.read(3) < 150) { Tmaxi = EEPROM.read(3) - 50; }
  else { EEPROM.write(3, Tmaxi_d + 50); Tmaxi = Tmaxi_d; }
  if(EEPROM.read(4) < 60) { Tmini = EEPROM.read(4) - 50; }
  else { EEPROM.write(4, Tmini_d + 50); Tmini = Tmini_d; }
  if(EEPROM.read(5) < 3) { pump_model = EEPROM.read(5); }
  else { EEPROM.write(5, pump_model_d); pump_model = pump_model_d; }
  if(EEPROM.read(6) < 4) { ssr_rule = EEPROM.read(6); }
  else { EEPROM.write(6, ssr_rule_d); ssr_rule = ssr_rule_d; }

// console and LCD initialisation
  Serial.begin(9600);
  Serial.println("ready ...");
  Serial.println ();
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Thermostat by");
  lcd.setCursor(0, 1);
  lcd.print("PhilippeDC");
  delay(500); 
}      // end of setup

//
// LOOP
//____________________________________________________________________________________________

void loop() {

  unsigned long tempo = millis()/800;       // time count a littke less than one seconds
  if( memo_tempo == tempo ) return;         // everything after is done every second
  memo_tempo = tempo;
  static unsigned int heatTimeOut = 0;      // counter for boiler offline alarm

// STEP 1: get the temperature values
//____________________________________________________________________________________________

// as it is needed 1.6s to get the temperature for both sensors, this is done 
// only when we are out of the parameters setting
  if(window== 0) { 
     GetTemperature(&Tsource, true);         // true only for the first reading
     GetTemperature(&Tcumulus, false); }

// STEP 2: compare temperature with the thresholds
//____________________________________________________________________________________________

// deltaTonn is reached : the pump is starting
  memo_state = state;                        // remaind the past state
  if( Tsource-Tcumulus-deltaTon >= 0 ) {
     state = 1;
     if(memo_state == 0) ratio = 50; }        // duty cycle 50% when pump is starting

// the pump is running, PWM increases until 100%
  if((state==1)&&(Tsource-Tcumulus-deltaToff-deltaTpwm >0)&&(ratio < 100)) 
    ratio++;

// deltaTpwm is reached so PWM is starting to decrease
  if((state==1)&&(Tsource-Tcumulus-deltaToff-deltaTpwm <=0)&&(tendency==2)&&(ratio > PWMmini)) 
    ratio--;

// deltaToff is reached so the pump stops
  if(Tsource-Tcumulus-deltaToff <=0) { 
    state = 0;
    ratio = 0; }

// Tmini reached : the pump starts + ALARM
  if(Tsource <= Tmini) {
    state = 2;
    ratio = 50;
    Alarm(3); }                               // red LED blinks 3 times/second

// pump is always on
  if(mforce == HIGH) {
    state = 4;
    ratio = 50;
    Alarm(1); }                              // red LED blinks 1 time/second

// drive a boiler
  if(ssr_rule == 1) {
    state = 5;                               // start the boiler
    if(Tsource < 40) {                       // check the heat of the source   
      PWM = 0;                               // pump stop if no heat
      heatTimeOut++;                         // count seconds
      if( heatTimeOut > 375 ) Alarm(2); }    // after 375 count = 10 minutes
    else heatTimeOut = 0; }
      
// Tmaxi reached : the pump is stopped + ALARM
  if(Tcumulus >= Tmaxi || Tsource > Tmaxi ) {
    state = 3;
    ratio = 0;
    Alarm(5); }                               // red LED blinks 5 times/second

//  Step 3: outputs management
//____________________________________________________________________________________________

// PWM management:
// pump_model == 0 for NON-PWM pump
// pump_model == 1 for Rising PWM pump
// pump_model == 2 for Falling PWM pump

  if(pump_model == 1)      PWM = map(ratio, 0, 100, 0, 255);
  else if(pump_model == 2) PWM = map(ratio, 0, 100, 255, 0);
  else                     PWM = 0;

  analogWrite(PWMpin, PWM);              // commande du PWM / mli

// SSR management
// ssr_rule == 0 to drive pump (require if pump_model =0)
// ssr_rule == 1 to drive the boiler,
// ssr_rule == 2 to drive Tmini alarm,
// ssr_rule == 3 to drive Tmaxi alarm
  if( ssr_rule == 0 ) {                  // case NON-PWM pump
    if((state == 1)||(state==2)||(state==4)) {
      digitalWrite(SSRpin, HIGH); digitalWrite(SSR_INVpin, LOW); }
    else {
      digitalWrite(SSRpin, LOW); digitalWrite(SSR_INVpin, HIGH); }
  }    // end of ssr_rule == 0

  else if( ssr_rule == 1 ) {             // case boiler
    if( state == 5 ) {
      digitalWrite(SSRpin, HIGH); digitalWrite(SSR_INVpin, LOW); }
    else {
      digitalWrite(SSRpin, LOW); digitalWrite(SSR_INVpin, HIGH); }
  }    // end of ssr_rule == 1

  else if( ssr_rule == 2 ) {             // case alarm Tmini
    if( state == 2 ) {
      digitalWrite(SSRpin, HIGH); digitalWrite(SSR_INVpin, LOW); }
    else {
      digitalWrite(SSRpin, LOW); digitalWrite(SSR_INVpin, HIGH); }
  }    // end of ssr_rule == 2

  else if( ssr_rule == 3 ) {             // case alarm Tmaxi
    if( state == 3 ) {
      digitalWrite(SSRpin, HIGH); digitalWrite(SSR_INVpin, LOW); }
    else {
      digitalWrite(SSRpin, LOW); digitalWrite(SSR_INVpin, HIGH); }
  }    // end of ssr_rule == 2

// Step 4 : tendency calculation
//____________________________________________________________________________________________

  static unsigned int cycleCounter = 0;     // counter for tendencies
  if(++cycleCounter > 5) {
    cycleCounter = 0;
    if( Tcumulus >  memo_Tcumulus ) tendency = 2;    // draw rising arrow on display
    if( Tcumulus == memo_Tcumulus ) tendency = 3;    // draw stable arrow on display
    if( Tcumulus <  memo_Tcumulus ) tendency = 4;    // draw falling arrow on display
    memo_Tcumulus = Tcumulus;                        // keep past measure
  }    // end of test cycleCounter

// Step 5: display & parameters management
//____________________________________________________________________________________________

// check push-buttons & display ON / OFF 
//____________________________________________________________________________________________

  memo_ret_push_button = ret_push_button; // memorize past value
  ret_push_button = push_button();        // reading push-button status 
                                          // 0: nothing, 1: ENTRY, 2: PLUS, 3: MINUS
  count_before_timeout++;                 // timeout before switch off the display
  if( count_before_timeout > timeout ) {  // timeout reached
      window = 0;                         // return to first display
      lcd.clear();
      lcd.noBacklight();                  // light off display
  }

  if((memo_ret_push_button == 1)&&(ret_push_button == 1)) next_window();

// regular case: no push-buttonactivity
//____________________________________________________________________________________________

  if( window== 0 ) {
    lcd.setCursor(0, 0);
    lcd.print("SOURCE:");  
    if( Tsource < 100 ) lcd.print(" ");
    lcd.print(String(Tsource, 1));  
    lcd.write(1);                             // display character ''
    lcd.print("C ");  
    lcd.setCursor(15, 0);   
    lcd.write(label_pump[state]);
    lcd.setCursor(0, 1);
    lcd.print("BALLON: ");
    lcd.print(String(Tcumulus, 1));
    lcd.write(1);
    lcd.print("C ");  
    lcd.setCursor(15, 1);
    lcd.write(tendency);                      // dram the arrow
  }    // end of windows == 0

// ENTRY button pushed
//____________________________________________________________________________________________

  if( window == 1 ) { 
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("LISTE DES");
    lcd.setCursor(0, 1);
    lcd.print("PARAMETRES :");
    delay(800);
    next_window();
  }    // end of windows == 1

// parameters setting

  if( window == 2 ) {  
    if(ret_push_button == 2) {
      deltaTon++;
      deltaTon = constrain(deltaTon, 0, 9); }    // limit value between 0 to 9
    if(ret_push_button == 3) {
      deltaTon--;
      deltaTon = constrain(deltaTon, deltaToff, 9); } 
    lcd.setCursor(0, 0);
    lcd.print("DELTA T MARCHE :");
    lcd.setCursor(0, 1);
    lcd.print(deltaTon);
    lcd.write(1);
    lcd.print("K  "); 
  }    // end of window == 2

  if( window == 3 ) {  
    if(ret_push_button == 2) {
      deltaToff++; 
      deltaToff = constrain(deltaToff, 0, deltaTon); } 
    if(ret_push_button == 3) {
      deltaToff--;
      deltaToff = constrain(deltaToff, 0, 9); } 
    lcd.setCursor(0, 0);
    lcd.print("DELTA T ARRET :");
    lcd.setCursor(0, 1);           
    lcd.print(deltaToff);                   
    lcd.write(1);
    lcd.print("K"); 
  }    // end of window == 3

  if( window == 4 ) {  
    if(ret_push_button == 2) {
      deltaTpwm++;
      deltaTpwm = constrain(deltaTpwm, 0, 9); }
    if(ret_push_button == 3) {
      deltaTpwm--;
      deltaTpwm = constrain(deltaTpwm, 0, 9); }
    lcd.setCursor(0, 0);
    lcd.print("DELTA T PWM :");
    lcd.setCursor(0, 1);
    lcd.print(deltaTpwm);
    lcd.write(1);
    lcd.print("K  "); 
  }    // end of window == 4

  if( window == 5 ) {  
    if(ret_push_button == 2) {
      Tmaxi++;
      Tmaxi = constrain(Tmaxi, 40, 100); }
    if(ret_push_button == 3) {
      Tmaxi--;
      Tmaxi = constrain(Tmaxi, 40, 100); }
    lcd.setCursor(0, 0);
    lcd.print("T MAXI ALARME :");
    lcd.setCursor(0, 1);
    lcd.print(Tmaxi);
    lcd.write(1);
    lcd.print("C  "); 
  }    // end of windows == 5

  if( window == 6 ) {  
    if(ret_push_button == 2) {
      Tmini++;
      Tmini = constrain(Tmini, -9, 9); }
    if(ret_push_button == 3) {
      Tmini--;
      Tmini = constrain(Tmini, -9, 9); }
    lcd.setCursor(0, 0);
    lcd.print("T HORS GEL :");
    lcd.setCursor(0, 1);
    lcd.print(Tmini);
    lcd.write(1);
    lcd.print("C  "); 
  }    // end of window == 6

  if( window == 7 ) {
    if(ret_push_button == 2) pump_model = (pump_model +1)%3;
    if(ret_push_button == 3) pump_model = (pump_model -1)%3;
    if(pump_model == 0)      label = "NON-PWM        ";
    else if(pump_model == 1) label = "PWM CROISSANT  ";
    else if(pump_model == 2) label = "PWM DECROISSANT";
    lcd.setCursor(0, 0);
    lcd.print("MODELE DE POMPE:");
    lcd.setCursor(0, 1);
    lcd.print(label);
  }    // end of window == 7

  if( window == 8 ) {
    if( pump_model == 0 ) label = "POMPE NON-PWM   ";
    else {
      if(ret_push_button == 2) ssr_rule = (ssr_rule +1)%4;
      if(ret_push_button == 3) ssr_rule = (ssr_rule -1)%4;
      if(ssr_rule == 0)      label = "POMPE NON-PWM   ";
      else if(ssr_rule == 1) label = "CHAUDIERE       ";
      else if(ssr_rule == 2) label = "PROTECTION GEL  ";
      else if(ssr_rule == 3) label = "PROT. EBULLITION";
    }
    lcd.setCursor(0, 0);
    lcd.print("USAGE COMMANDE :");
    lcd.setCursor(0, 1);
    lcd.print(label);
  }    // end of window == 8

  if( window == 9 ) {
    lcd.setCursor(0, 0);
    lcd.print("REINITIALISATION");
    lcd.setCursor(0, 1);
    lcd.print("POUR VALIDER : +");
    if(ret_push_button == 2) {
       lcd.setCursor(0, 0);
       lcd.print("REINITIALISATION");
       lcd.setCursor(0, 1);
       lcd.print("FAITE           ");
       deltaTon = deltaTon_d;    // default value to all parameters
       deltaToff = deltaToff_d;
       deltaTpwm = deltaTpwm_d;
       Tmaxi = Tmaxi_d;
       Tmini = Tmini_d;
       pump_model = pump_model_d;
       ssr_rule = ssr_rule_d;
       mforce = LOW;             // stop always ON capability
       window= 0; }
  }    // end of windows == 9

  if(  window == 10 ) {
    lcd.setCursor(0, 0);
    lcd.print("MARCHE FORCEE ? ");
    lcd.setCursor(0, 1);
    lcd.print("OUI= + / NON= - ");
    if(ret_push_button == 2) {
      mforce = HIGH;
      lcd.setCursor(0, 0);
      lcd.print("MARCHE FORCEE   ");
      lcd.setCursor(0, 1);
      lcd.print("CONFIRMEE       "); 
      window = 0; }
    if(ret_push_button == 3) {
      mforce = LOW;
      lcd.setCursor(0, 0);
      lcd.print("MARCHE FORCEE   ");
      lcd.setCursor(0, 1);
      lcd.print("ARRETEE         ");
      window = 0; }
  }    // end of windows == 10

// EEPROM backup
//____________________________________________________________________________________________

  if( eeprom = true ) {                // EEPROM backup only if needed
    EEPROM.update(0, deltaTon + 50);
    EEPROM.update(1, deltaToff + 50);
    EEPROM.update(2, deltaTpwm + 50);
    EEPROM.update(3, Tmaxi + 50);
    EEPROM.update(4, Tmini + 50);
    EEPROM.update(5, pump_model);
    EEPROM.update(6, ssr_rule);
  }

// for debugging
//____________________________________________________________________________________________

   Serial.print("ssr_rule: "); Serial.print(ssr_rule);
   Serial.print("  state: "); Serial.print(state);
   Serial.print("  ratio: "); Serial.print(ratio);
   Serial.print("  PWM: "); Serial.print(PWM);
   Serial.print("  Ts: "); Serial.print(Tsource);
   Serial.print("  Tc: "); Serial.print(Tcumulus);
   Serial.print("  Ts-Tc-deltaToff: "); Serial.print(Tsource-Tcumulus-deltaToff);
   Serial.println();
 
}    // end of loop

//============================================================================================
// list of functions
//============================================================================================

//
// next_window() : procedure to change the window display
//____________________________________________________________________________________________

void next_window() {
  window = (window+1) % windowsTotal;    // next window
  lcd.clear();
}      // end of next_window()

//
// push_button() : return value depending of the state of the 3 push-buttons
//____________________________________________________________________________________________

byte push_button() {
  if ( digitalRead(ENTRYpin) == LOW ) {
    count_before_timeout = 0;         // reset the timeout counter
    lcd.backlight();                  // switch on display
    lcd.clear();
    return 1;
  }
  if ( digitalRead(PLUSpin) == LOW ) {
    count_before_timeout = 0;
    lcd.backlight();
    eeprom = true;
    return 2;
  }
  if ( digitalRead(MINUSpin) == LOW ) {
    count_before_timeout = 0;
    lcd.backlight();
    eeprom = true;
    return 3;
  }
  return 0;
}     // end of push_button()

//
// GetTemperature() : reading measures of DS18B20
//____________________________________________________________________________________________

byte GetTemperature(float *temperature, byte reset_search) {
  byte data[9], addr[8];           // data[] : data read from scratchpad
                                   // addr[] : Address of detected 1-Wire device
  
// reset the list of adresses for the first sensor
// char argument = "true" or "false"
  if(reset_search) sondeDS.reset_search();
  sondeDS.search(addr);
  sondeDS.reset();
  sondeDS.select(addr);
  sondeDS.write(0x44, 1);          // getting the temperature takes as long as 1/2 second for each sensor
  delay(800);                      // required, see above comment
  sondeDS.reset();
  sondeDS.select(addr);
  sondeDS.write(0xBE);             // send request from scratchpad
 
// the scratchpad content makes 9 bytes:
  for (byte i = 0; i < 9; i++) { data[i] = sondeDS.read(); }

// miraculous formula to get the temperature in C with a 12 bits resolution, accurancy of 0,06K:
// it is possible to modify this formula to get F
  *temperature = ((data[1] << 8) | data[0]) * 0.0625; 
}      // end of getTemperature()

//
// Alarm() red LED lighting management
//____________________________________________________________________________________________

void Alarm(byte c) {
  for( byte i=0; i<c; i++ ) {
    digitalWrite(ALARMpin, HIGH); delay(10);
    digitalWrite(ALARMpin, LOW); delay(200);
  }
}      // end of Alarm()

Custom parts and enclosures

Thermostat repositery
Please read the manual pdf file for all details

Schematics

Thermostat diagram
Thermostat diagram ezhvnbdril

Comments

Similar projects you might like

A Wind Turbine MPPT Regulator with an Arduino Uno

Project in progress by philippedc

  • 9,906 views
  • 33 comments
  • 46 respects

Arduino / ATtiny85 Delta AC 3-Phase Checker

Project in progress by philippedc

  • 2,455 views
  • 4 comments
  • 11 respects

Arduino Control AC Water Heater temperature

Project tutorial by Mohannad Rawashdeh

  • 16,526 views
  • 0 comments
  • 11 respects

Arduino / ESP8266 RS485 MODBUS Anemometer

Project in progress by philippedc

  • 9,987 views
  • 8 comments
  • 13 respects

A Power Router to Optimize Homemade Electricity with Arduino

Project in progress by philippedc

  • 1,810 views
  • 1 comment
  • 7 respects

Measure LUX with Arduino Using BH1750

Project tutorial by afsh_ad

  • 14,022 views
  • 0 comments
  • 4 respects
Add projectSign up / Login