Project tutorial

Smart Thermostat, Airing and Lights Control with Bluetooth © CC BY-NC

Just connect your Arduino smart home and control the heater, airing, and lights via Bluetooth!

  • 7,720 views
  • 21 comments
  • 55 respects

Components and supplies

Apps and online services

About this project

Introdution

Simple but useful Arduino project.

An intelligent thermostat routine controls the heater gas boiler, and the system switches my kitchen lights and my bathroom airing fan with relays – can be controlled by buttons and Android device or computer via Bluetooth. Celsius and Fahrenheit version also available!

Developed on Arduino Nano (or higher) board, uses Dallas DS18B20 temperature sensor, HC-05/06 Bluetooth adapter, I2C 128X64 bicolor OLED display– you can choose different LCD/OLED display, the u8glib supports a lot of types.

Video

The video shows all the important working ways, gives you ideas how to build the project from the beginning.

Heater working ways

1: One Time Heating (15 mins) timed mode (useful at spring/autumn evenings)

2: Thermostat mode (higher priority), the adjusted target temperature stored in EEPROM memory

Boiler save algorithm

Frequent, short-term switching would cut short the lifetime of the heater gas boiler, to keep avoid it, the program uses correction values – these declares the degree of overheating and cooling back. Lower temperature demands greater correction values, because the walls are colder and adsorb better the warmth from the freshly heated-up air, so the above described effect would stronger.

Open window detection

The program detects if a window is open, thus the temperature drops at least -0, 2°C (-0, 36F) in one minute – the heater stops or won’t start, and the airing fan will turn on in order to help refresh the air. When the air became warmer at least +0, 12°C (+0, 216F) due to the heat capacity of the environment, the system will switch back to normal mode, and the ‘Window Alert’ event will be dismissed.

Error detection

Measured temperature under 0°C (32F) or above 40°C (104F) will be evaluated as malfunction or other problem (error, broken window, fire, etc.), and all devices will shut down.

Bluetooth communication

The Android GUI app has 8 buttons, sends upper and lower case letters in order to turn on (‘A’), or turn off (‘a’) the timed heater, ‘B’ and ‘b’ turns the airing, ‘C’ and ‘c’ the lights…

The other strength of my project is the geek-friend Bluetooth serial terminal usage. Just chat with the system via Bluetooth using a serial terminal – it can be an Android app, but even a normal PC will do – for example the Serial Monitor of the Arduino IDE.

The controller sends temperature reports in every minutes automatically, and instant reports about all events, such as an attached device has been turned on/off, the thermostat routine activated, and so on.

Control codes

It accepts control codes and sends confirmation messages. My command structure based on two digit numbers like ‘XY’ – where;

‘X’ is the device code, and ‘Y’ is the opcode

30, 31, 32: lighting Off / On / flip logical state

40, 41, 42: airing Off / On / flip logical state

50, 51, 52: one time heater program Off / On / flip logical state

10 – 24 numbers will be accepted as target temperature for the thermostat function

‘r’ – report about working state of controlled devices

‘w’ – manually disables the “window alert” event, if you don’t want to wait for its automated dismission

‘A, a… H, h’ – letters are accepted as the GUI app would have sent

Fahrenheit version

I was converted all the correction variables, reference and ratio values, so the system kept its calculation and working particularities.

Only a few modification. The new device codes of the Fahrenheit version:

1 - Lighting (10: off, 11: on, 12: flip state)

2 - Airing

3 - Heater

50 - 76 numbers are target temperature values

DallasTemperature, elapsedMillis, OneWire, SoftwareSerial, olikraus/u8glib

If you use different button resistors, or need to check A0 readings, I suggest to check this out:

http://blog.codebender.cc/2015/07/20/tutorial-multiple-buttons-on-1-analog-pin/

Code

Thermostat - Celsius version.inoArduino
The program code explains itself, useful for beginners. Well commented, describes every important steps; what, why and how. Divided into modules by functions, that’s why easy to overview.
// Celsius version
// Program code of an intelligent Arduino smarthome thermostat solution, 
// based on Arduino Nano (or higher) board, DS18B20 thermo sensor, HC-05 Bluetooth adapter, I2C 128X64 bicolor OLED display.
// The system can be controlled by buttons and Android smartphone via bluetooth.
//
// It handles the HEATER gas boiler, the bathroom AIRING ventilator and the kitchen LIGHTING - swithed with relays.
// The heater has two working ways. 1: One Time Heating (15 mins) timed mode, 2: Thermostat mode (higher priority). The adjusted target tempr.
// stored in EEPROM. The program detects hardware errors and window opening - in these cases the heater stops and/or will not start.
//
// Designed and programmed by Gyula Osi.
// All rights reserved.
// ------------------------------------------------------------------------------------------------------------------------------------

// ---- Display                               I2C Bus, SDA(TX) -> A4, SCL(RX) -> A5
#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);  // display constructor
byte frame = 0;                               // start logo pointer

// ---- Ports and related declarations
const byte buzzer = 9;   // buzzer to D9
int btnVal;              // stores analog values from buttons
byte relayA = 11;        // airing
bool aStateByCmd;        // if "window alert" is gone, the airing control goes back to the original state
byte relayL = 13;        // lighting
byte relayH = 10;        // heater
const byte ledA = 5;     // PWM ports allow output level adjustment used to change brightness
const byte ledL = 3;
const byte ledH = 6;
int brightness = 10;
#define ledInterval 1000 // heater led blinking interval
unsigned long prev = 0;

// ---- Strings for display and bluetooth reports 
char str0[] = "on.";     // device state indicator strings for outputs
char str1[] = "off.";
char str2[] = "auto.";
char heaterState[5] ;    // str spaces to copy
char airingState[5] ;
char lightingState[5] ;
#define FUNCT_ITEMS 11
char *funct_str[FUNCT_ITEMS] = {"Heater is ", "Airing is ", "Lighting is ", "Window Alert!", "Hardware Error!", "Hit a Key >>", "or send a Code!", "Target tempr = ", "Temperature = ", " * ", " -"};

// ---- Temperature and heater related features
#include <elapsedMillis.h>        
elapsedMillis timer0;              // 8-bit, PWM timer, used by function elapsedMillis()
#define sftyTmrInterval 15 * 60000 // one Time Heating (15 mins) timed mode interval [ms]
boolean sftyTmrEnded;              // boolean startup, the timer0 has ended
#include <EEPROM.h>
byte tTarget;                      // adjusted target tempr
int addr = 0;                      // the current address of the tTarget variable in the EEPROM memory
bool hState = 0;                   // heater boolean state
bool hThermostat = 0;              // thermostat boolean state
#include "OneWire.h" 
#include "DallasTemperature.h"
#define DS18B20 2                  // setup the OneWire bus on D2
OneWire temprWire(DS18B20);        // setup DS18B20 to work on the OneWire bus
DallasTemperature sensors(&temprWire);
float tempr;                       // measured value
float temprPrev;                   // copy of measured value for trend analysis
bool windowAlrt = 0;               // specified degree of tempr drop
bool measError = 0;                // measured tempr value is out of the range specified as normal
const long temprInterval = 60000;  // cyclic tempr measurement interval [ms]
unsigned long temprTmrPrev = 0;    // the elapsed will be the previous when temprMeas() called
float heatCorrVal;                 // declares the degree of overheating and cooling back, see tempMeas() function

// ---- Configuration of serial communication on virtual RXD/TXD on D8/D4
#include <SoftwareSerial.h>        // SW serial RX & TX pins for HC-05
const int RX1 = 8;
const int TX1 = 4;
SoftwareSerial SoftSerialOne(RX1,TX1); 
char one;                          // store received serial data
char two;

const uint8_t frame1[] U8G_PROGMEM = {  // XBM start logo frame map
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x3F, 0x30, 0xE0, 0x03, 0xFE, 0x07, 0xFC, 0x81, 0x81, 0x07, 
  0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x70, 0xE0, 0x00, 0xF8, 0x01, 
  0xF0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x70, 
  0x70, 0x20, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x7F, 0x30, 0x70, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x20, 0x78, 0x70, 0xF0, 0xC0, 
  0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x20, 
  0x78, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x20, 0x78, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7C, 0x70, 0xF0, 0xC0, 
  0xE3, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 
  0x7C, 0x70, 0xF0, 0x80, 0xE7, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x01, 0x7C, 0x70, 0xF0, 0x01, 0xFE, 0x81, 0x81, 0x07, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x7E, 0x70, 0xF0, 0x07, 
  0xF8, 0x01, 0x80, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 
  0x7E, 0x70, 0xF0, 0x1F, 0xF0, 0x01, 0x80, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x03, 0x7E, 0x70, 0xF0, 0x7C, 0xE0, 0x01, 0x80, 0x07, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x7F, 0x70, 0xF0, 0xE0, 
  0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 
  0x7F, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x07, 0x7F, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x7F, 0x70, 0xF0, 0xC0, 
  0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 
  0x7F, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x07, 0x7F, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x7F, 0x70, 0xF0, 0xC0, 
  0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 
  0x7F, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0x00, 0xF8, 0x01, 0xF0, 0x81, 0x81, 0x07, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFE, 0x03, 0xFC, 0x07, 
  0xF8, 0x81, 0x81, 0x07, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xE0, 0xBF, 0xC7, 0xF3, 0x7F, 0xFE, 0xF3, 0x87, 0x3F, 0xFC, 0xE1, 0xF1, 
  0xC3, 0x7F, 0xFC, 0x00, 0xE0, 0x3F, 0xC7, 0x31, 0x67, 0xFE, 0xF3, 0x8F, 
  0x7F, 0xFC, 0xE3, 0x3C, 0xC7, 0x7F, 0xCF, 0x01, 0xE0, 0x00, 0xC7, 0x01, 
  0x07, 0x0E, 0x70, 0x8E, 0x73, 0x9C, 0xE3, 0x1C, 0xC7, 0x01, 0xC7, 0x01, 
  0xE0, 0x00, 0xCF, 0x01, 0x07, 0x0E, 0x70, 0x8E, 0x73, 0x9C, 0xE3, 0x1C, 
  0xC7, 0x01, 0xC7, 0x01, 0xE0, 0x00, 0xCF, 0x01, 0x07, 0x0E, 0x70, 0x8E, 
  0x73, 0x9C, 0xE3, 0x1C, 0xC7, 0x01, 0xC7, 0x01, 0xE0, 0x00, 0xDF, 0x01, 
  0x07, 0x0E, 0x70, 0x8E, 0x73, 0x9C, 0xE3, 0x3C, 0xC4, 0x01, 0x0F, 0x01, 
  0xE0, 0x18, 0xDF, 0x01, 0x07, 0x8E, 0xF1, 0x8F, 0x73, 0xFC, 0xE3, 0xF8, 
  0xC0, 0x31, 0x3E, 0x00, 0xE0, 0x1F, 0xDF, 0x01, 0x07, 0xFE, 0xF1, 0x87, 
  0x73, 0xFC, 0xE1, 0xF0, 0xC3, 0x3F, 0xFC, 0x00, 0xE0, 0x1F, 0xFF, 0x01, 
  0x07, 0xFE, 0xF1, 0x8F, 0x7F, 0xFC, 0xE3, 0x84, 0xC7, 0x3F, 0xE1, 0x01, 
  0xE0, 0x00, 0xF7, 0x01, 0x07, 0x0E, 0x70, 0x8E, 0x3F, 0x9C, 0xE3, 0x1C, 
  0xC7, 0x01, 0xC7, 0x01, 0xE0, 0x00, 0xF7, 0x01, 0x07, 0x0E, 0x70, 0x8E, 
  0x03, 0x9C, 0xE3, 0x1C, 0xC7, 0x01, 0xC7, 0x01, 0xE0, 0x00, 0xF7, 0x01, 
  0x07, 0x0E, 0x70, 0x8E, 0x03, 0x9C, 0xE3, 0x1C, 0xC7, 0x01, 0xC7, 0x01, 
  0xE0, 0x00, 0xE7, 0x01, 0x07, 0x0E, 0x70, 0x8E, 0x03, 0x9C, 0xE3, 0x1C, 
  0xC7, 0x01, 0xC7, 0x01, 0xE0, 0x00, 0xE7, 0x01, 0x07, 0x0E, 0x70, 0x8E, 
  0x03, 0x9C, 0xE3, 0x1C, 0xC7, 0x01, 0xC7, 0x01, 0xE0, 0x3F, 0xC7, 0x01, 
  0x07, 0xFE, 0x73, 0x8E, 0x03, 0x9C, 0xE3, 0xBC, 0xC7, 0x7F, 0xEF, 0x01, 
  0xE0, 0xBF, 0xC7, 0x03, 0x0F, 0xFE, 0x73, 0x8E, 0x07, 0x9C, 0xE3, 0xF1, 
  0xC3, 0x7F, 0xFC, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x1C, 
  0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00,
};

void setup() {  
pinMode(relayH, OUTPUT);      // set relayH - D10 as an output
pinMode(relayA, OUTPUT);
pinMode(relayL, OUTPUT);
pinMode(buzzer, OUTPUT);
pinMode(ledA, OUTPUT);
pinMode(ledL, OUTPUT);
pinMode(ledH, OUTPUT);
sensors.begin();              // start DS18B20
temprMeas();                  // do not wait for the meas.timer, call the function once at startup
tTarget = EEPROM.read(addr);  // read the previously stored tTarget value from the current address of the EEPROM at startup
reportMsg(8);                 // call for instant report of working states after startup
}

void loop() { 
  hState = digitalRead(relayH);
  temprTimer();
  ledHandler();
  btnReadings();
  btRecv();
  safetyTmr();
  
  u8g.firstPage();  // display loop
    do {
      draw();
    } while( u8g.nextPage() );
    if (frame == 0) { 
    delay(3000);
    frame = 1;
    clrScr(); 
    }
}

void btnReadings() {                 // --------- btn readings
  btnVal = analogRead(A0);                     // read analog val from A0
  if (btnVal >= 510 && btnVal <= 516) {        // btn Lighting
    delay(100);                                // btn debounce
    buzz(3, 1);
    relayHandlerL(2);                          // call proper function with logical state flip opcode as parameter
  }
  else if (btnVal >= 849 && btnVal <= 855){    // btn Airing
    if (windowAlrt == 1) {                     // if the system is in Window Alert mode, disable it
      windowAlrt = 0;                                                        
      buzz(4, 3);                                                            
      relayHandlerA(3);
    }
    else {                                     // else turn on/off the airing ventilator
    delay(100);
    buzz(3, 1);
    relayHandlerA(2);
    }
  }
  else if (btnVal >= 927  && btnVal <= 933){   // btn One Time Heating (15 mins) timed mode
    delay(100);
    buzz(3, 1);
    relayHandlerH(2);
  }
  else if (btnVal >= 767 && btnVal <= 777) {   // btn decrease tTarget
    delay(100);
    tTargetHandler(0);
  }
  else if (btnVal >= 687 && btnVal <= 697) {   // btn increase tTarget
    delay(100);
    tTargetHandler(1);
  }
  else if (btnVal >= 856 && btnVal <= 862) {   // inc & dec btns at the same time
    tTarget = 14;                              // <==== initial value - press these buttons at the very first powerup!
  }
}

void btRecv() {           // ------------- receive serial data
  SoftSerialOne.begin(9600);
  while (SoftSerialOne.available()>0) { // if data is available to read
    one = SoftSerialOne.read();         // read & store it in serialVal
    two = SoftSerialOne.read();
  }   

  switch (one) {          // ------------ accept SINGLE ALPHABETICAL control codes
    case 'A':
      relayHandlerH(1);   // 1=on
      break;
    case 'a':
      relayHandlerH(0);   // 0=off
      break;                           // Received serial data can be a single alphabetical letter from "Arduino 
    case 'B':                          // Bluetooth Control Device" Android app. If a proper alphabetical
      relayHandlerA(1);                // character arrives, the program code will not wait for the second one,
      break;                           // but calls the applicable function with a proper operation code.
    case 'b':                          // Cases of combined numeric data can be seen below.
      relayHandlerA(0);    
      break;
    case 'C':
      relayHandlerL(1);
      break;
    case 'c':
      relayHandlerL(0);
      break;
    case 'D':
    case 'd':
      tTarget = 21;                           
      tTargetEEPROM();
      buzz(3, 1);
      break; 
    case 'E':
    case 'e':
      tTarget = 19;                           
      tTargetEEPROM();
      buzz(3, 1);
      break;
    case 'F':
    case 'f':
      tTarget = 14;                          
      tTargetEEPROM();
      buzz(3, 1);
      break;
    case 'R':             // call for an overview report about controlled devices
    case 'r':
      reportMsg(8);
      break;
    case 'W':             // disable Window Alert state
    case 'w':
      windowAlrt = 0;                                                        
      buzz(4, 3);                                                            
      relayHandlerA(3);
      break;
  }
                          // ----------------------- accept COMBINED NUMERIC control codes
  char cb0 = one;                                 // In this case a two-digit numeric control code arrives in char format,
  int b0;                                         // from an Android bluetooth serial app for instance. After a char to integer
  b0 = cb0 - '0';                                 // conversion (only if the first char is '1' or '2') a merge-process will follow, 
  char cb1 = two;                                 // and the system of conditions and statements will make a decision and execute it.
  int b1;                                         // Appropriate numeric codes are:
  b1 = cb1 - '0';                                 
                                                  // ---------------- Target Temperature:
  if (one == '3') {                               // 10 - 24 values will be accepted as a target temperature for the thermostat function.
    relayHandlerL(b1);                            
  }                                               // ---------------- Device Control Codes:  
  if (one == '4') {                               // First = device code, Second = operator code
    relayHandlerA(b1);                            // 30, 31, 32 turns the lighting: 30=off, 31=on
  }                                               //                                32=flip logical state (on -> off / off -> on)
  if (one == '5') {                               // 40, 41, 42 will do the same to the airing ventilator
    relayHandlerH(b1);                            // 50, 51, 52 handles the One Time Heating (15 mins) timed heater program as above
  }
                                                  // ---------------- Classified Operator Codes:
                                                  // X3, X4 are classified, used only for function calls by inner program sequences

  if ((b0 * 10 + b1 <= 24) && (b0 * 10 + b1 >= 10)) {         // accept only numeric values between 10 & 24
    tTarget = b0 * 10 + b1;                                   // merge two integers and set tTarget
    tTargetEEPROM();                                          // after set, call the EEPROM handler function, and
    buzz(3, 1);                                               // write the tTarget value to the appropriate byte of the EEPROM
  }
  if (one =='0') {                    // test
    int i;
    for (i = 1; i < 5; i++) {
      buzz(5, 2);
    }
  }
  one = two = 'Z';                    // empty all message receiver and conversion variables
  b0 = b1 = 9;
}

void relayHandlerL(byte lOperator) {  // lighting handler sequence
  buzz(2, 1);                         // operators are: 0=off, 1=on, 2=flip the state, 4=fill/refill the lighting state char var.
  bool a;
  a = digitalRead(relayL);
  if ((lOperator == 2) || (lOperator == 0) && (a == 1) || (lOperator == 1) && (a == 0)) {
    a = !a;
    digitalWrite(relayL, a);
  }  

  if (lOperator >= 0) {               // fill up the working state char with the proper state indicator string
    if (digitalRead(relayL) == HIGH) {
      strcpy(lightingState, str0);
    }
    else  {
      strcpy(lightingState, str1);
    }
  reportMsg(7);
  }
}

void relayHandlerA(byte aOperator) {  // airing handler sequence
  bool a;                             // operators are: 0=off, 1=on, 2=flip the state, 
  a = digitalRead(relayA);            // 3=called by temprMeas() funct., 4=fill/refill the airing state char var.
  if (windowAlrt == 0) {
    if ((aOperator == 2) || (a == 1) && (aOperator == 0) || (a == 0) && (aOperator == 1)) {
      buzz(2, 1);
      a = !a;
      digitalWrite(relayA, a);
      aStateByCmd = digitalRead(relayA);
    } 
  } 
  if (aOperator == 3) {               // called by the temprMeas() function, 'windowAlrt' ended or started
    if ((a == 0) && (windowAlrt == 1) || (a == 1) && (windowAlrt == 0) && (aStateByCmd == 0)) {
      digitalWrite(relayA, windowAlrt);
    }
  }
  if (aOperator >= 0) {
    if (digitalRead(relayA) == HIGH) {
      if (windowAlrt == 1) {
        strcpy(airingState, str2);
      }
      else  {
        strcpy(airingState, str0);
      }
    }
    else {
      strcpy(airingState, str1);
    }
  }
  reportMsg(6);
}
 
void relayHandlerH(byte hOperator) {  // heater handler sequence 
                                      // operators are: 0=off, 1=on, 2=flip the state, 
                                      // 3=called by temprMeas() funct., 4=fill/refill the heater state char var.
                                      
  if ((hThermostat == 0) && (windowAlrt == 0) && (measError == 0)) {  // turn on/off the One Time Heating (15 mins) timed mode
    if ((hOperator == 2) || (hOperator == 1) && (hState == 0) || (hOperator == 0) && (hState == 1)) {
      buzz(2, 1);
      hState = !hState;
      sftyTmrEnded = 0;
      timer0 = 0;   
      digitalWrite(relayH, hState);
    }
  }
      
  if (windowAlrt == 1) {
    reportMsg(3);
  }
  
  if (hOperator == 3) {               // this function called by the temprMeas() function (op 3) 
                                      // in order to examine windowAlrt & measError booleans                                      
    if (measError == 1) {             // extreme tempr values
      digitalWrite(relayH, 0);
      digitalWrite(relayA, 0);
      digitalWrite(relayL, 0);
    }                                                                                          
    if ((windowAlrt == 1) && (hState == 1)) {  // a window is open and the heater is running
      digitalWrite(relayH, 0);
      buzz(5, 3);
      }
    if ((windowAlrt == 0) && (measError == 0)) {
      if ((hThermostat == 1) || (hThermostat == 0) && (hState == 1) && (sftyTmrEnded == 1)) { 
        digitalWrite(relayH, hThermostat);     // proceed the command of the thermostat routine
      }
    }
  }

  if (hOperator >= 0) {
    if (digitalRead(relayH) == HIGH) {
      if (hThermostat == 1) {
        strcpy(heaterState, str2) ;
      }
      else  {
        strcpy(heaterState, str0) ;
      }
    }
    else {
      strcpy(heaterState, str1) ;
    }
    if (((windowAlrt == 0) && (hOperator != 3)) || (digitalRead(relayH) == HIGH)) {
      reportMsg(5);
    }
  }
}

void safetyTmr () {    // timer for the One Time Heating (15 mins) timed mode
  if ((digitalRead(relayH) == HIGH) && (sftyTmrEnded == 0) && (timer0 > sftyTmrInterval) && (hThermostat == 0)) {
  sftyTmrEnded = 1;
  digitalWrite(relayH, LOW);
    int i;
    for (i = 1; i < 5; i++) {
      buzz(i, 2);
    }
  }
}

void temprTimer() {    // cyclic timer for temprMeas()
  unsigned long temprTmrCurr = millis();
  if (temprInterval <= temprTmrCurr - temprTmrPrev) {
    temprTmrPrev = temprTmrCurr;
    temprMeas();
  } 
}

void temprMeas() {          // ----------- tempr measurement & comparison sequence
  temprPrev = tempr;                    // save the value for next comparison
  sensors.requestTemperatures();        // update sensor readings
  tempr = sensors.getTempCByIndex(0);   // read remperature

  if ((tempr >= 40) || (tempr <= 0)) {  // extreme meas values:
    measError = 1;                      // -127 is HW error, +85 is tipically SW error, but
    int i;                              // can be fire, or a broken window
    for (i = 1; i < 10; i++) {
      buzz(4, 1);
      delay(50);
    } 
  }                                                       
  else {
    measError = 0;
  }

  if (measError == 0) {      // ------------ Start of temperature analysis sequence
    if (tempr <= 17) {                    // Frequent, short-term switching of the heater gas boiler would cut short its lifetime, the
      heatCorrVal = 0.5;                  // heatCorrVal value helps to keep avoid it. Declares the degree of overheating and cooling back.
    }                                     // Lower temperature demands greater heatCorrVal, because the walls are colder and adsorb better the
    if ((tempr > 17) && (tempr < 19)) {   // warmth from the freshly heated-up air, so the above described effect would more effective.
      heatCorrVal = 0.4;
    }
    if (tempr >= 19) {
      heatCorrVal = 0.3;
    }
    
    if (tTarget - tempr >= heatCorrVal) { // subtract measured value from target, if the difference equals or greater than heatCorrVal
      sftyTmrEnded = 1;                   // deactivate the One Time Heating (15 mins) timed program if it is running
      hThermostat = 1;                    // turn on the thermostat
      buzz(1, 1);                      
    }
    if ((tTarget - tempr <= -1 * heatCorrVal) && (hThermostat == 1)) {  
      hThermostat = 0;
    }
    
    if ((temprPrev - tempr >= 0.2) && (windowAlrt == 0) && (tempr <= 20)) {   // in a measurement cycle and in heating season the temperature
      windowAlrt = 1;                                                         // drops, it will evaluate as a window is open
      sftyTmrEnded = 1;                                    
      int i;
        for (i = 1; i < 5; i++) {
          buzz(4, 1);
          delay(50);
        }
      relayHandlerA(3);                                                       // call airing function (opcode = 3), to help refresh the air
    }
    if ((temprPrev - tempr <= -0.12) && (windowAlrt == 1)) {                  // the tempr. falling is over, the air became warmer 
      windowAlrt = 0;                                                         // due to the heat capacity of the environment, 
      buzz(4, 3);                                                             // so switch back to normal mode
      relayHandlerA(3);
    }
    relayHandlerH(3);             // the function will examine caller param(3) & windowAlrt & measError booleans
                                                            
    if (windowAlrt == 0) {
      reportMsg(1);
    }
  }
  else {
    reportMsg(4);
  }
}

void tTargetHandler (byte set) {  // set the needed tempr by increasing or decreasing
  if (set == 0) {                 // incr
    if (tTarget < 24) {           // until it reaches the upper limit
      tTarget++ ;
      buzz(3, 1);
      }
    else {
      buzz(2, 3);
    }
  }
  if (set == 1) {                 // decr
    if (tTarget > 10) {
      tTarget-- ;
      buzz(3, 1); 
    }
    else {
      buzz(2, 3);
    }
  }
  tTargetEEPROM();
}

void tTargetEEPROM() {
  EEPROM.write(addr, tTarget);    // after incr/decr/set, write the tTarget value to the appropriate byte of the EEPROM
  reportMsg(2);
}

void draw(void) {                 // logo handler
  if (frame == 0) 
    u8g.drawXBMP( 0, 0, 128, 64, frame1);
  else if (frame == 1)
    screenFunctState(); 
}
      
void screenFunctState(void) {     // function state screen
  temprWriteOut(0, 64);
  u8g.drawHLine(0, 46, 128);
  u8g.setFont(u8g_font_unifont);
  if (windowAlrt == 0) {
    u8g.drawStr( 0, 14, funct_str[0]);
    u8g.drawStr(84, 14, heaterState);
  }
  else {
    u8g.drawStr( 0, 14, funct_str[3]);
  }
  u8g.drawStr( 0, 28, funct_str[1]);
  u8g.drawStr(88, 28, airingState);
  u8g.drawStr( 0, 42, funct_str[2]);
  u8g.drawStr(95, 42, lightingState);

  if ((digitalRead(relayH) == LOW) && (digitalRead(relayA) == LOW) && (digitalRead(relayL) == LOW)) {
    screenStndby();               // if all of controlled devices are in off, call standby screen
  }
}

void screenStndby() {             // standby scr
  u8g.firstPage(); 
    do {
      u8g.setFontRefHeightText();
      u8g.setFont(u8g_font_unifont);
      if (measError == 0) {
        u8g.drawStr(33, 52, funct_str[5]);
        u8g.drawStr( 8, 64, funct_str[6]);
      }
      if (measError == 1) {
        u8g.drawStr( 4, 48, funct_str[4]);
      }
      temprWriteOut(0, 16) ;
    } while( u8g.nextPage() );
}

void temprWriteOut (int tX, int tY) {   // draw tempr & tTarget variables onto different coordinates
  u8g.setPrintPos(tX, tY);
//u8g.setFont(u8g_font_unifont);
//u8g.setFont(u8g_font_10x20);
  u8g.setFont(u8g_font_courB14);
//u8g.setFont(u8g_font_6x12);           // you can save ~10% of prog.memory using this font with 2x2 scale
  char buftTarget[9];                   
  sprintf (buftTarget, "%d", tTarget);  // int to char conversion
//u8g.setScale2x2();
//tY = tY / 2;
  u8g.drawStr(tX, tY, buftTarget);
  u8g.drawStr(tX+18, tY, funct_str[9]); // tX+18 
  u8g.setPrintPos(tX+50, tY);           // tX+32
  u8g.print(tempr);                     // printing temp. 
  u8g.print(char(176)); 
  u8g.print("C");
//u8g.undoScale();
}

void clrScr(){
  u8g.firstPage(); 
    do {
    } while( u8g.nextPage() );
}

void ledHandler() {                     // the brightness of a led is low, if the indicated device is off, and high, if its on
  if (digitalRead(relayA) == HIGH) {
    analogWrite(ledA, 100); 
    }
    else {
      analogWrite(ledA, 10); 
      }
  
  if (digitalRead(relayL) == HIGH) {
    analogWrite(ledL, 100); 
    }
    else {
      analogWrite(ledL, 10); 
      }
  
  if (digitalRead(relayH) == HIGH) {
    if (hThermostat == 0) {
      ledBlnk() ;                       // the heater led blinks when the One Time Heating (15 mins) timed mode is activated,
    }
    else {
      brightness = 100 ;                // and constant bright, if the thermostat routine is active
    }
  }  
  else {
    brightness = 10 ; 
  }
  analogWrite(ledH, brightness);
}

void ledBlnk() {
  unsigned long curr = millis();
  if (ledInterval <= curr - prev) {     // subtract prev value from current, if the difference equals or greater than ledInterval const.
    prev = curr;                        // overwrite the earlier value with the current
    if (brightness == 10) {             // and flip brightness level
      brightness = 100;
    } 
    else {
      brightness = 10;
    }
  }
  analogWrite(ledH, brightness);
}

void buzz (int b, int d) {              // call with frequency and delay parameters
  tone(buzzer, b * 1000); 
  delay(d * 100);        
  noTone(buzzer);
}

void reportMsg(byte cmdBCN) {              // sending serial reports
  SoftSerialOne.begin(9600);
  switch (cmdBCN) {
    case 0:
      int i;
      for (i = 0; i < 9; i++) {
        SoftSerialOne.print(funct_str[10]);
      }
      SoftSerialOne.println(funct_str[10]);
      break;
    case 1: 
      SoftSerialOne.print(funct_str[8]);   // Tempr.
      SoftSerialOne.print(tempr); 
      SoftSerialOne.print(char(176)); 
      SoftSerialOne.println("C");           
      break;
    case 2:
      SoftSerialOne.print(funct_str[7]);   // TTemp
      SoftSerialOne.print(tTarget); 
      SoftSerialOne.print(char(176)); 
      SoftSerialOne.println("C");  
      break;
    case 3:
      SoftSerialOne.print(funct_str[3]);   // Window Alert
      SoftSerialOne.print(funct_str[9]);  
      SoftSerialOne.print(tempr); 
      SoftSerialOne.print(char(176)); 
      SoftSerialOne.println("C");      
      break;
    case 4:
      SoftSerialOne.println(funct_str[4]); // Error report        
      break;
    case 5:
      SoftSerialOne.print(funct_str[0]);   // Working state of devices
      SoftSerialOne.println(heaterState);      
      break;
    case 6:
      SoftSerialOne.print(funct_str[1]); 
      SoftSerialOne.println(airingState);         
      break;
    case 7:
      SoftSerialOne.print(funct_str[2]);
      SoftSerialOne.println(lightingState);         
      break;
    case 8:                                // Overview report
      reportMsg(0);
      relayHandlerH(4);            
      relayHandlerA(4);
      relayHandlerL(4);
      reportMsg(2);
      break;
  }
}
Thermostat - Fahrenheit version.inoArduino
The program code explains itself, useful for beginners. Well commented, describes every important steps; what, why and how. Divided into modules by functions, that’s why easy to overview.
Works in Fahrenheit, I changed only the Target temperature values (50-76), and the device codes (1, 2 and 3).
// Fahrenheit version
// Program code of an intelligent Arduino smarthome thermostat solution, 
// based on Arduino Nano (or higher) board, DS18B20 thermo sensor, HC-05 Bluetooth adapter, I2C 128X64 bicolor OLED display.
// The system can be controlled by buttons and Android smartphone via bluetooth.
//
// It handles the HEATER gas boiler, the bathroom AIRING ventilator and the kitchen LIGHTING - swithed with relays.
// The heater has two working ways. 1: One Time Heating (15 mins) timed mode, 2: Thermostat mode (higher priority). The adjusted target tempr.
// stored in EEPROM. The program detects hardware errors and window opening - in these cases the heater stops and/or will not start.
//
// Designed and programmed by Gyula Osi.
// All rights reserved.
// ------------------------------------------------------------------------------------------------------------------------------------

// ---- Display                               I2C Bus, SDA(TX) -> A4, SCL(RX) -> A5
#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);  // display constructor
byte frame = 0;                               // start logo pointer

// ---- Ports and related declarations
const byte buzzer = 9;   // buzzer to D9
int btnVal;              // stores analog values from buttons
byte relayA = 11;        // airing
bool aStateByCmd;        // if "window alert" is gone, the airing control goes back to the original state
byte relayL = 13;        // lighting
byte relayH = 10;        // heater
const byte ledA = 5;     // PWM ports allow output level adjustment used to change brightness
const byte ledL = 3;
const byte ledH = 6;
int brightness = 10;
#define ledInterval 1000 // heater led blinking interval
unsigned long prev = 0;

// ---- Strings for display and bluetooth reports 
char str0[] = "on.";     // device state indicator strings for outputs
char str1[] = "off.";
char str2[] = "auto.";
char heaterState[5] ;    // str spaces to copy
char airingState[5] ;
char lightingState[5] ;
#define FUNCT_ITEMS 11
char *funct_str[FUNCT_ITEMS] = {"Heater is ", "Airing is ", "Lighting is ", "Window Alert!", "Hardware Error!", "Hit a Key >>", "or send a Code!", "Target tempr = ", "Temperature = ", " * ", " -"};

// ---- Temperature and heater related features
#include <elapsedMillis.h>        
elapsedMillis timer0;              // 8-bit, PWM timer, used by function elapsedMillis()
#define sftyTmrInterval 15 * 60000 // one Time Heating (15 mins) timed mode interval [ms]
boolean sftyTmrEnded;              // boolean startup, the timer0 has ended
#include <EEPROM.h>
byte tTarget;                      // adjusted target tempr
int addr = 0;                      // the current address of the tTarget variable in the EEPROM memory
bool hState = 0;                   // heater boolean state
bool hThermostat = 0;              // thermostat boolean state
#include "OneWire.h" 
#include "DallasTemperature.h"
#define DS18B20 2                  // setup the OneWire bus on D2
OneWire temprWire(DS18B20);        // setup DS18B20 to work on the OneWire bus
DallasTemperature sensors(&temprWire);
float tempr;                       // measured value
float temprPrev;                   // copy of measured value for trend analysis
bool windowAlrt = 0;               // specified degree of tempr drop
bool measError = 0;                // measured tempr value is out of the range specified as normal
const long temprInterval = 60000;  // cyclic tempr measurement interval [ms]
unsigned long temprTmrPrev = 0;    // the elapsed will be the previous when temprMeas() called
float heatCorrVal;                 // declares the degree of overheating and cooling back, see tempMeas() function

// ---- Configuration of serial communication on virtual RXD/TXD on D8/D4
#include <SoftwareSerial.h>        // SW serial RX & TX pins for HC-05
const int RX1 = 8;
const int TX1 = 4;
SoftwareSerial SoftSerialOne(RX1,TX1); 
char one;                          // store received serial data
char two;

const uint8_t frame1[] U8G_PROGMEM = {  // XBM frame map
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x3F, 0x30, 0xE0, 0x03, 0xFE, 0x07, 0xFC, 0x81, 0x81, 0x07, 
  0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x70, 0xE0, 0x00, 0xF8, 0x01, 
  0xF0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x70, 
  0x70, 0x20, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x7F, 0x30, 0x70, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x20, 0x78, 0x70, 0xF0, 0xC0, 
  0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x20, 
  0x78, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x20, 0x78, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7C, 0x70, 0xF0, 0xC0, 
  0xE3, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 
  0x7C, 0x70, 0xF0, 0x80, 0xE7, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x01, 0x7C, 0x70, 0xF0, 0x01, 0xFE, 0x81, 0x81, 0x07, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x7E, 0x70, 0xF0, 0x07, 
  0xF8, 0x01, 0x80, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 
  0x7E, 0x70, 0xF0, 0x1F, 0xF0, 0x01, 0x80, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x03, 0x7E, 0x70, 0xF0, 0x7C, 0xE0, 0x01, 0x80, 0x07, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0x7F, 0x70, 0xF0, 0xE0, 
  0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 
  0x7F, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x07, 0x7F, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x7F, 0x70, 0xF0, 0xC0, 
  0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 
  0x7F, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x07, 0x7F, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0x7F, 0x70, 0xF0, 0xC0, 
  0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 
  0x7F, 0x70, 0xF0, 0xC0, 0xE0, 0x81, 0x81, 0x07, 0xFE, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x03, 0xFF, 0x00, 0xF8, 0x01, 0xF0, 0x81, 0x81, 0x07, 
  0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xFE, 0x03, 0xFC, 0x07, 
  0xF8, 0x81, 0x81, 0x07, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x81, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE1, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0xE0, 0xBF, 0xC7, 0xF3, 0x7F, 0xFE, 0xF3, 0x87, 0x3F, 0xFC, 0xE1, 0xF1, 
  0xC3, 0x7F, 0xFC, 0x00, 0xE0, 0x3F, 0xC7, 0x31, 0x67, 0xFE, 0xF3, 0x8F, 
  0x7F, 0xFC, 0xE3, 0x3C, 0xC7, 0x7F, 0xCF, 0x01, 0xE0, 0x00, 0xC7, 0x01, 
  0x07, 0x0E, 0x70, 0x8E, 0x73, 0x9C, 0xE3, 0x1C, 0xC7, 0x01, 0xC7, 0x01, 
  0xE0, 0x00, 0xCF, 0x01, 0x07, 0x0E, 0x70, 0x8E, 0x73, 0x9C, 0xE3, 0x1C, 
  0xC7, 0x01, 0xC7, 0x01, 0xE0, 0x00, 0xCF, 0x01, 0x07, 0x0E, 0x70, 0x8E, 
  0x73, 0x9C, 0xE3, 0x1C, 0xC7, 0x01, 0xC7, 0x01, 0xE0, 0x00, 0xDF, 0x01, 
  0x07, 0x0E, 0x70, 0x8E, 0x73, 0x9C, 0xE3, 0x3C, 0xC4, 0x01, 0x0F, 0x01, 
  0xE0, 0x18, 0xDF, 0x01, 0x07, 0x8E, 0xF1, 0x8F, 0x73, 0xFC, 0xE3, 0xF8, 
  0xC0, 0x31, 0x3E, 0x00, 0xE0, 0x1F, 0xDF, 0x01, 0x07, 0xFE, 0xF1, 0x87, 
  0x73, 0xFC, 0xE1, 0xF0, 0xC3, 0x3F, 0xFC, 0x00, 0xE0, 0x1F, 0xFF, 0x01, 
  0x07, 0xFE, 0xF1, 0x8F, 0x7F, 0xFC, 0xE3, 0x84, 0xC7, 0x3F, 0xE1, 0x01, 
  0xE0, 0x00, 0xF7, 0x01, 0x07, 0x0E, 0x70, 0x8E, 0x3F, 0x9C, 0xE3, 0x1C, 
  0xC7, 0x01, 0xC7, 0x01, 0xE0, 0x00, 0xF7, 0x01, 0x07, 0x0E, 0x70, 0x8E, 
  0x03, 0x9C, 0xE3, 0x1C, 0xC7, 0x01, 0xC7, 0x01, 0xE0, 0x00, 0xF7, 0x01, 
  0x07, 0x0E, 0x70, 0x8E, 0x03, 0x9C, 0xE3, 0x1C, 0xC7, 0x01, 0xC7, 0x01, 
  0xE0, 0x00, 0xE7, 0x01, 0x07, 0x0E, 0x70, 0x8E, 0x03, 0x9C, 0xE3, 0x1C, 
  0xC7, 0x01, 0xC7, 0x01, 0xE0, 0x00, 0xE7, 0x01, 0x07, 0x0E, 0x70, 0x8E, 
  0x03, 0x9C, 0xE3, 0x1C, 0xC7, 0x01, 0xC7, 0x01, 0xE0, 0x3F, 0xC7, 0x01, 
  0x07, 0xFE, 0x73, 0x8E, 0x03, 0x9C, 0xE3, 0xBC, 0xC7, 0x7F, 0xEF, 0x01, 
  0xE0, 0xBF, 0xC7, 0x03, 0x0F, 0xFE, 0x73, 0x8E, 0x07, 0x9C, 0xE3, 0xF1, 
  0xC3, 0x7F, 0xFC, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x00, 0x1C, 
  0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00,
};

void setup() {  
pinMode(relayH, OUTPUT);      // set relayH - D10 as an output
pinMode(relayA, OUTPUT);
pinMode(relayL, OUTPUT);
pinMode(buzzer, OUTPUT);
pinMode(ledA, OUTPUT);
pinMode(ledL, OUTPUT);
pinMode(ledH, OUTPUT);
sensors.begin();              // start DS18B20
temprMeas();                  // do not wait for the meas.timer, call the function once at startup
tTarget = EEPROM.read(addr);  // read the previously stored tTarget value from the current address of the EEPROM at startup
reportMsg(8);                 // call for instant report of working states after startup
}

void loop() { 
  hState = digitalRead(relayH);
  temprTimer();
  ledHandler();
  btnReadings();
  btRecv();
  safetyTmr();
  
  u8g.firstPage();  // display loop
    do {
      draw();
    } while( u8g.nextPage() );
    if (frame == 0) { 
    delay(3000);
    frame = 1;
    clrScr(); 
    }
}

void btnReadings() {                 // --------- btn readings
  btnVal = analogRead(A0);                     // read analog val from A0
  if (btnVal >= 510 && btnVal <= 516) {        // btn Lighting
    delay(100);                                // btn debounce
    buzz(3, 1);
    relayHandlerL(2);                          // call proper function with logical state flip opcode as parameter
  }
  else if (btnVal >= 849 && btnVal <= 855){    // btn Airing
    if (windowAlrt == 1) {                     // if the system is in Window Alert mode, disable it
      windowAlrt = 0;                                                        
      buzz(4, 3);                                                            
      relayHandlerA(3);
    }
    else {                                     // else turn on/off the airing ventilator
    delay(100);
    buzz(3, 1);
    relayHandlerA(2);
    }
  }
  else if (btnVal >= 927  && btnVal <= 933){   // btn One Time Heating (15 mins) timed mode
    delay(100);
    buzz(3, 1);
    relayHandlerH(2);
  }
  else if (btnVal >= 767 && btnVal <= 777) {   // btn decrease tTarget
    delay(100);
    tTargetHandler(0);
  }
  else if (btnVal >= 687 && btnVal <= 697) {   // btn increase tTarget
    delay(100);
    tTargetHandler(1);
  }
  else if (btnVal >= 856 && btnVal <= 862) {   // inc & dec btns at the same time
    tTarget = 57;                              // <==== initial value - press these buttons at the very first powerup!
  }
}

void btRecv() {           // ------------- receive serial data
  SoftSerialOne.begin(9600);
  while (SoftSerialOne.available()>0) { // if data is available to read
    one = SoftSerialOne.read();         // read & store it in serialVal
    two = SoftSerialOne.read();
  }   

  switch (one) {          // ------------ accept SINGLE ALPHABETICAL control codes
    case 'A':
      relayHandlerH(1);   // 1=on
      break;
    case 'a':
      relayHandlerH(0);   // 0=off
      break;                           // Received serial data can be a single alphabetical letter from "Arduino 
    case 'B':                          // Bluetooth Control Device" Android app. If a proper alphabetical
      relayHandlerA(1);                // character arrives, the program code will not wait for the second one,
      break;                           // but calls the applicable function with a proper operation code.
    case 'b':                          // Cases of combined numeric data can be seen below.
      relayHandlerA(0);    
      break;
    case 'C':
      relayHandlerL(1);
      break;
    case 'c':
      relayHandlerL(0);
      break;
    case 'D':
    case 'd':
      tTarget = 70;                           
      tTargetEEPROM();
      buzz(3, 1);
      break; 
    case 'E':
    case 'e':
      tTarget = 66;                           
      tTargetEEPROM();
      buzz(3, 1);
      break;
    case 'F':
    case 'f':
      tTarget = 57;                          
      tTargetEEPROM();
      buzz(3, 1);
      break;
    case 'R':             // call for an overview report about controlled devices
    case 'r':
      reportMsg(8);
      break;
    case 'W':             // disable Window Alert state
    case 'w':
      windowAlrt = 0;                                                        
      buzz(4, 3);                                                            
      relayHandlerA(3);
      break;
  }
                          // ----------------------- accept COMBINED NUMERIC control codes
  char cb0 = one;                                 // In this case a two-digit numeric control code arrives in char format,
  int b0;                                         // from an Android bluetooth serial app for instance. After a char to integer
  b0 = cb0 - '0';                                 // conversion (only if the first char is between '5' and '7') a merge-process will follow, 
  char cb1 = two;                                 // and the system of conditions and statements will make a decision and execute it.
  int b1;                                         // Appropriate numeric codes are:
  b1 = cb1 - '0';                                 
                                                  // ---------------- Target Temperature:
  if (one == '1') {                               // 50 - 76 values will be accepted as a target temperature for the thermostat function.
    relayHandlerL(b1);                            
  }                                               // ---------------- Device Control Codes:  
  if (one == '2') {                               // First = device code, Second = operator code
    relayHandlerA(b1);                            // 10, 11, 12 turns the lighting: 10=off, 11=on
  }                                               //                                12=flip logical state (on -> off / off -> on)
  if (one == '3') {                               // 20, 21, 22 will do the same to the airing ventilator
    relayHandlerH(b1);                            // 30, 31, 32 handles the One Time Heating (15 mins) timed heater program as above
  }
                                                  // ---------------- Classified Operator Codes:
                                                  // X3, X4 are classified, used only for function calls by inner program sequences

  if ((b0 * 10 + b1 <= 76) && (b0 * 10 + b1 >= 50)) {         // accept only numeric values between 50 & 76
    tTarget = b0 * 10 + b1;                                   // merge two integers and set tTarget
    tTargetEEPROM();                                          // after set, call the EEPROM handler function, and
    buzz(3, 1);                                               // write the tTarget value to the appropriate byte of the EEPROM
  }
  if (one =='0') {                    // test
    int i;
    for (i = 1; i < 5; i++) {
      buzz(5, 2);
    }
  }
  one = two = 'Z';                    // empty all message receiver and conversion variables
  b0 = b1 = 9;
}

void relayHandlerL(byte lOperator) {  // lighting handler sequence
  buzz(2, 1);                         // operators are: 0=off, 1=on, 2=flip the state, 4=fill/refill the lighting state char var.
  bool a;
  a = digitalRead(relayL);
  if ((lOperator == 2) || (lOperator == 0) && (a == 1) || (lOperator == 1) && (a == 0)) {
    a = !a;
    digitalWrite(relayL, a);
  }  

  if (lOperator >= 0) {               // fill up the working state char with the proper state indicator string
    if (digitalRead(relayL) == HIGH) {
      strcpy(lightingState, str0);
    }
    else  {
      strcpy(lightingState, str1);
    }
  reportMsg(7);
  }
}

void relayHandlerA(byte aOperator) {  // airing handler sequence
  bool a;                             // operators are: 0=off, 1=on, 2=flip the state, 
  a = digitalRead(relayA);            // 3=called by temprMeas() funct., 4=fill/refill the airing state char var.
  if (windowAlrt == 0) {
    if ((aOperator == 2) || (a == 1) && (aOperator == 0) || (a == 0) && (aOperator == 1)) {
      buzz(2, 1);
      a = !a;
      digitalWrite(relayA, a);
      aStateByCmd = digitalRead(relayA);
    } 
  } 
  if (aOperator == 3) {               // called by the temprMeas() function, 'windowAlrt' ended or started
    if ((a == 0) && (windowAlrt == 1) || (a == 1) && (windowAlrt == 0) && (aStateByCmd == 0)) {
      digitalWrite(relayA, windowAlrt);
    }
  }
  if (aOperator >= 0) {
    if (digitalRead(relayA) == HIGH) {
      if (windowAlrt == 1) {
        strcpy(airingState, str2);
      }
      else  {
        strcpy(airingState, str0);
      }
    }
    else {
      strcpy(airingState, str1);
    }
  }
  reportMsg(6);
}
 
void relayHandlerH(byte hOperator) {  // heater handler sequence 
                                      // operators are: 0=off, 1=on, 2=flip the state, 
                                      // 3=called by temprMeas() funct., 4=fill/refill the heater state char var.
                                      
  if ((hThermostat == 0) && (windowAlrt == 0) && (measError == 0)) {  // turn on/off the One Time Heating (15 mins) timed mode
    if ((hOperator == 2) || (hOperator == 1) && (hState == 0) || (hOperator == 0) && (hState == 1)) {
      buzz(2, 1);
      hState = !hState;
      sftyTmrEnded = 0;
      timer0 = 0;   
      digitalWrite(relayH, hState);
    }
  }
      
  if (windowAlrt == 1) {
    reportMsg(3);
  }
  
  if (hOperator == 3) {               // this function called by the temprMeas() function (op 3) 
                                      // in order to examine windowAlrt & measError booleans                                      
    if (measError == 1) {             // extreme tempr values
      digitalWrite(relayH, 0);
      digitalWrite(relayA, 0);
      digitalWrite(relayL, 0);
    }                                                                                          
    if ((windowAlrt == 1) && (hState == 1)) {  // a window is open and the heater is running
      digitalWrite(relayH, 0);
      buzz(5, 3);
      }
    if ((windowAlrt == 0) && (measError == 0)) {
      if ((hThermostat == 1) || (hThermostat == 0) && (hState == 1) && (sftyTmrEnded == 1)) { 
        digitalWrite(relayH, hThermostat);     // proceed the command of the thermostat routine
      }
    }
  }

  if (hOperator >= 0) {
    if (digitalRead(relayH) == HIGH) {
      if (hThermostat == 1) {
        strcpy(heaterState, str2) ;
      }
      else  {
        strcpy(heaterState, str0) ;
      }
    }
    else {
      strcpy(heaterState, str1) ;
    }
    if (((windowAlrt == 0) && (hOperator != 3)) || (digitalRead(relayH) == HIGH)) {
      reportMsg(5);
    }
  }
}

void safetyTmr () {    // timer for the One Time Heating (15 mins) timed mode
  if ((digitalRead(relayH) == HIGH) && (sftyTmrEnded == 0) && (timer0 > sftyTmrInterval) && (hThermostat == 0)) {
  sftyTmrEnded = 1;
  digitalWrite(relayH, LOW);
    int i;
    for (i = 1; i < 5; i++) {
      buzz(i, 2);
    }
  }
}

void temprTimer() {    // cyclic timer for temprMeas()
  unsigned long temprTmrCurr = millis();
  if (temprInterval <= temprTmrCurr - temprTmrPrev) {
    temprTmrPrev = temprTmrCurr;
    temprMeas();
  } 
}

void temprMeas() {          // ------------- tempr measurement & comparison sequence
  temprPrev = tempr;                      // save the value for next comparison
  sensors.requestTemperatures();          // update sensor readings
  tempr = sensors.getTempFByIndex(0);     // read remperature

  if ((tempr >= 104) || (tempr <= 32)) {  // extreme meas values:
    measError = 1;                        // can be HW / SW error, fire or a broken window
    int i;                              
    for (i = 1; i < 10; i++) {
      buzz(4, 1);
      delay(50);
    } 
  }                                                       
  else {
    measError = 0;
  }

  if (measError == 0) {      // ---------------- Start of temperature analysis sequence
    if (tempr <= 62.6) {                      // Frequent, short-term switching of the heater gas boiler would cut short its lifetime, the
      heatCorrVal = 0.9;                     // heatCorrVal value helps to keep avoid it. Declares the degree of overheating and cooling back.
    }                                         // Lower temperature demands greater heatCorrVal, because the walls are colder and adsorb better the
    if ((tempr > 62.6) && (tempr < 66.2)) {   // warmth from the freshly heated-up air, so the above described effect would more effective.
      heatCorrVal = 0.72;
    }
    if (tempr >= 66.2) {
      heatCorrVal = 0.54;
    }
    
    if (tTarget - tempr >= heatCorrVal) { // subtract measured value from target, if the difference equals or greater than heatCorrVal
      sftyTmrEnded = 1;                   // deactivate the One Time Heating (15 mins) timed program if it is running
      hThermostat = 1;                    // turn on the thermostat
      buzz(1, 1);                      
    }
    if ((tTarget - tempr <= -1 * heatCorrVal) && (hThermostat == 1)) {  
      hThermostat = 0;
    }
    
    if ((temprPrev - tempr >= 0.36) && (windowAlrt == 0) && (tempr <= 68)) {   // in a measurement cycle and in heating season the temperature
      windowAlrt = 1;                                                           // drops, it will evaluate as a window is open
      sftyTmrEnded = 1;                                    
      int i;
        for (i = 1; i < 5; i++) {
          buzz(4, 1);
          delay(50);
        }
      relayHandlerA(3);                                                       // call airing function (opcode = 3), to help refresh the air
    }
    if ((temprPrev - tempr <= -0.216) && (windowAlrt == 1)) {                 // the tempr. falling is over, the air became warmer 
      windowAlrt = 0;                                                         // due to the heat capacity of the environment, 
      buzz(4, 3);                                                             // so switch back to normal mode
      relayHandlerA(3);
    }
    relayHandlerH(3);             // the function will examine caller param(3) & windowAlrt & measError booleans
                                                            
    if (windowAlrt == 0) {
      reportMsg(1);
    }
  }
  else {
    reportMsg(4);
  }
}

void tTargetHandler (byte set) {  // set the needed tempr by increasing or decreasing
  if (set == 0) {                 // incr
    if (tTarget < 76) {           // until it reaches the upper limit
      tTarget++ ;
      buzz(3, 1);
      }
    else {
      buzz(2, 3);
    }
  }
  if (set == 1) {                 // decr
    if (tTarget > 50) {
      tTarget-- ;
      buzz(3, 1); 
    }
    else {
      buzz(2, 3);
    }
  }
  tTargetEEPROM();
}

void tTargetEEPROM() {
  EEPROM.write(addr, tTarget);    // after incr/decr/set, write the tTarget value to the appropriate byte of the EEPROM
  reportMsg(2);
}

void draw(void) {                 // logo handler
  if (frame == 0) 
    u8g.drawXBMP( 0, 0, 128, 64, frame1);
  else if (frame == 1)
    screenFunctState(); 
}
      
void screenFunctState(void) {     // function state screen
  temprWriteOut(0, 64);
  u8g.drawHLine(0, 46, 128);
  u8g.setFont(u8g_font_unifont);
  if (windowAlrt == 0) {
    u8g.drawStr( 0, 14, funct_str[0]);
    u8g.drawStr(84, 14, heaterState);
  }
  else {
    u8g.drawStr( 0, 14, funct_str[3]);
  }
  u8g.drawStr( 0, 28, funct_str[1]);
  u8g.drawStr(88, 28, airingState);
  u8g.drawStr( 0, 42, funct_str[2]);
  u8g.drawStr(95, 42, lightingState);

  if ((digitalRead(relayH) == LOW) && (digitalRead(relayA) == LOW) && (digitalRead(relayL) == LOW)) {
    screenStndby();               // if all of controlled devices are in off, call standby screen
  }
}

void screenStndby() {             // standby scr
  u8g.firstPage(); 
    do {
      u8g.setFontRefHeightText();
      u8g.setFont(u8g_font_unifont);
      if (measError == 0) {
        u8g.drawStr(33, 52, funct_str[5]);
        u8g.drawStr( 8, 64, funct_str[6]);
      }
      if (measError == 1) {
        u8g.drawStr( 4, 48, funct_str[4]);
      }
      temprWriteOut(0, 16) ;
    } while( u8g.nextPage() );
}

void temprWriteOut (int tX, int tY) {   // draw tempr & tTarget variables onto different coordinates
  u8g.setPrintPos(tX, tY);
//u8g.setFont(u8g_font_unifont);
//u8g.setFont(u8g_font_10x20);
  u8g.setFont(u8g_font_courB14);
//u8g.setFont(u8g_font_6x12);           // you can save ~10% of prog.memory using this font with 2x2 scale
  char buftTarget[9];                   
  sprintf (buftTarget, "%d", tTarget);  // int to char conversion
//u8g.setScale2x2();
//tY = tY / 2;
  u8g.drawStr(tX, tY, buftTarget);
  u8g.drawStr(tX+18, tY, funct_str[9]); // tX+18 
  u8g.setPrintPos(tX+50, tY);           // tX+32
  u8g.print(tempr);                     // printing temp. 
//u8g.print(char(176)); 
  u8g.print("F");
//u8g.undoScale();
}

void clrScr(){
  u8g.firstPage(); 
    do {
    } while( u8g.nextPage() );
}

void ledHandler() {                     // the brightness of a led is low, if the indicated device is off, and high, if its on
  if (digitalRead(relayA) == HIGH) {
    analogWrite(ledA, 100); 
    }
    else {
      analogWrite(ledA, 10); 
      }
  
  if (digitalRead(relayL) == HIGH) {
    analogWrite(ledL, 100); 
    }
    else {
      analogWrite(ledL, 10); 
      }
  
  if (digitalRead(relayH) == HIGH) {
    if (hThermostat == 0) {
      ledBlnk() ;                       // the heater led blinks when the One Time Heating (15 mins) timed mode is activated,
    }
    else {
      brightness = 100 ;                // and constant bright, if the thermostat routine is active
    }
  }  
  else {
    brightness = 10 ; 
  }
  analogWrite(ledH, brightness);
}

void ledBlnk() {
  unsigned long curr = millis();
  if (ledInterval <= curr - prev) {     // subtract prev value from current, if the difference equals or greater than ledInterval const.
    prev = curr;                        // overwrite the earlier value with the current
    if (brightness == 10) {             // and flip brightness level
      brightness = 100;
    } 
    else {
      brightness = 10;
    }
  }
  analogWrite(ledH, brightness);
}

void buzz (int b, int d) {              // call with frequency and delay parameters
  tone(buzzer, b * 1000); 
  delay(d * 100);        
  noTone(buzzer);
}

void reportMsg(byte cmdBCN) {              // sending serial reports
  SoftSerialOne.begin(9600);
  switch (cmdBCN) {
    case 0:
      int i;
      for (i = 0; i < 9; i++) {
        SoftSerialOne.print(funct_str[10]);
      }
      SoftSerialOne.println(funct_str[10]);
      break;
    case 1: 
      SoftSerialOne.print(funct_str[8]);   // Tempr.
      SoftSerialOne.print(tempr); 
      SoftSerialOne.print(char(176)); 
      SoftSerialOne.println("F");           
      break;
    case 2:
      SoftSerialOne.print(funct_str[7]);   // TTemp
      SoftSerialOne.print(tTarget); 
      SoftSerialOne.print(char(176)); 
      SoftSerialOne.println("F");  
      break;
    case 3:
      SoftSerialOne.print(funct_str[3]);   // Window Alert
      SoftSerialOne.print(funct_str[9]);  
      SoftSerialOne.print(tempr); 
      SoftSerialOne.print(char(176)); 
      SoftSerialOne.println("F");      
      break;
    case 4:
      SoftSerialOne.println(funct_str[4]); // Error report        
      break;
    case 5:
      SoftSerialOne.print(funct_str[0]);   // Working state of devices
      SoftSerialOne.println(heaterState);      
      break;
    case 6:
      SoftSerialOne.print(funct_str[1]); 
      SoftSerialOne.println(airingState);         
      break;
    case 7:
      SoftSerialOne.print(funct_str[2]);
      SoftSerialOne.println(lightingState);         
      break;
    case 8:                                // Overview report
      reportMsg(0);
      relayHandlerH(4);            
      relayHandlerA(4);
      relayHandlerL(4);
      reportMsg(2);
      break;
  }
}

Schematics

Simplified for try out
For jumper wire test...
Bt thermostat   simplified schem wqtdxiplou
Detailed schematics
You have to solder it
Bt thermostat   detailed schem uthyk0gmyv

Comments

Similar projects you might like

Bluetooth Smart phone control with remote arduino

Project tutorial by DFRobot

  • 5,089 views
  • 1 comment
  • 11 respects

Bluetooth control led with lcd led status display real time.

Project tutorial by Youssef Sabaa

  • 19,972 views
  • 4 comments
  • 40 respects

Arduino Controlled Smart Hydroponic Modular System

Project in progress by Luis Antonio Martin Nuez

  • 11,505 views
  • 3 comments
  • 71 respects

The smart thermostat

Project in progress by Daniel Roman

  • 9,066 views
  • 1 comment
  • 13 respects

Zoned Climate Control with MediaTek's LinkIt™ Smart 7688

Project tutorial by BuddyC

  • 7,890 views
  • 5 comments
  • 19 respects

SERENA: Alarm Control Panel

Project tutorial by Michael Marinis

  • 7,195 views
  • 0 comments
  • 16 respects
Add projectSign up / Login