Gyula Ősi
Published © CC BY-NC

Voice Controlled Full Home Automation - Without Wires

Just say the needed temperature, control your home with voice or Android! Two units on synched Bluetooth link, RFID functions...

BeginnerFull instructions provided6 hours9,519

Things used in this project

Hardware components

Arduino Mega 2560
Arduino Mega 2560
×1
Arduino Nano R3
Arduino Nano R3
×1
RFID IC, 13.56 MHz
RFID IC, 13.56 MHz
×1
HC-05 Bluetooth Module
HC-05 Bluetooth Module
×3
Temperature Sensor
Temperature Sensor
×1
0.96" OLED 64x128 Display Module
ElectroPeak 0.96" OLED 64x128 Display Module
×1
IR receiver (generic)
×1
DS3231M - ±5ppm, I2C Real-Time Clock
Maxim Integrated DS3231M - ±5ppm, I2C Real-Time Clock
Please check schem for more...
×1

Software apps and online services

Morich Serial Bluetooth Terminal for Android

Story

Read more

Schematics

Central Unit - Ősi Gyula

Thermostat Unit - Ősi Gyula

Code

Central Unit

Arduino
// ---- CENTRAL UNIT - Smart Home
// Program code of an intelligent Arduino smarthome system - Central Unit. 
// Based on Arduino / Genuino 2560 board, HC-05 Bluetooth adapters, RF 315/433MHz receiver, IR receiver, MFRC-522 reader and programmer,
// Elechouse VR3 module, TM1637 display drivers, ST9720 (12864) lcd screen, 4x4 matrix keypad, DS3231 RTC chip, 4ch relay board,
// ISD1820PY voice chips with LM386 amplifier, active and NE555 controlled buzzers.
//
// It controls the desk lights and media player (as local devices), and controls the another unit of the system, 
// the Thermostat Unit via Bluetooth. These units connect and synch each oder automatically - so there is no missing or outdated information in the system.
// 
// The Central Unit accepts Bluetooth (Android for instance), Voice (speech), IR and RF remote, and Keypad commands in order to control 
// the local devices, or forwards the command to the Thermostat unit, and receives working state reports from it.
// The whole system can be locked by RFID cards (with a full-function card handler menu). 
// All system settings and informations (RFID cards, locked/unlocked state, device states, alarm clock, etc.) are stored in EEPROM.
//
// The another part of the system is the Thermostat Unit, based on Arduino Nano, DS18B20 thermo sensor, HC-05 Bluetooth, I2C 128X64 OLED display.
// Controls the HEATER gas boiler, the bathroom AIRING ventilator and the kitchen LIGHTING. The program detects hardware errors and window
//  opening - in these cases the heater stops and/or will not start.
// Works in Celsius and Fahrenheit unit (by changing it converts the stored previous temperature values), and calculates natural gas cost.
// ------------------------------------------------------------------------------------------------------------------------------------
//
// Designed, built and programmed 
// by Gyula Osi.
// All rights reserved.
// ------------------------------------------------------------------------------------------------------------------------------------

// ---- MFRC-522 & System Security
#include <SPI.h>
#include <MFRC522.h>
#define SS_PIN 53              // RST: 48, MISO: 50, MOSI: 51, SCK: 52, SDA: 53
#define RST_PIN 48
MFRC522 rfid(SS_PIN, RST_PIN); // instance of the class
MFRC522::MIFARE_Key key; 
String strC;                   // collect and store readings
#define arrNUIDSize 4
String strNUID[arrNUIDSize];
char arrNUID[arrNUIDSize][20];           // number of strings & length of each strings
#define lckItems 2
// i -->                             0   1
const int lock_strings[lckItems] = {98, 97};
bool locked;                   // state of syslock
bool cardManager = 0;   
// i -->                    0  1  2  3  4  5  6  7
bool cardBoolSwitches[8] = {1, 1, 0, 0, 0, 0, 0, 0};   
      // ---- Array of Binary Card Operators & Process State Codes
        //    [i] FUNCT 
        //     0  has been seen (temp=1) 
        //     1  get NUID (call at startup)
        //     2  not stored yet 
        //     3  delete
        //     4  already stored 
        //     5  new NUID 
        //     6  invalid type of card 
        //     7  memory full
// i -->                     0  1  2  3
bool delNUID[arrNUIDSize] = {0, 0, 0, 0}; // marked for delete 

// ---- Receive IR
#include <IRremote.h>
const int RECV_PIN = 8;
IRrecv irrecv(RECV_PIN);
decode_results results; 

// ---- Matrix Hexakeys and Buttons
#include <Keypad.h>
const byte matrixR = 4;  // R
const byte matrixC = 4;  // C
char matrixHEXkeys[matrixR][matrixC] = {  //define the cymbols on the buttons of the keypads
// iR/C --> R0C0 R0C1 R0C2 R0C3   R1C0 R1C1 R1C2 R1C3   R2C0 R2C1 R2C2 R2C3   R3C0 R3C1 R3C2 R3C3
           {'1', '2', '3', 'A'}, {'4', '5', '6', 'B'}, {'7', '8', '9', 'C'}, {'*', '0', '#', 'D'}
  };
byte pinsMatrixR[matrixR] = {40, 42, 44, 46};   //connect to the row pinouts of the keypad
byte pinsMatrixC[matrixC] = {43, 45, 47, 49};   //connect to the column pinouts of the keypad
Keypad customKeypad = Keypad(makeKeymap(matrixHEXkeys), pinsMatrixR, pinsMatrixC, matrixR, matrixC); //initialize an instance of class NewKeypad
int matrixVal;            // stores analog value when button is pressed
int sum = 0;              // to collect Control Codes from Keypad and IR
char sumChar[2];          // to conv in into char for writeout
const byte btnAl = 28;

// ---- RF 315/330/433MHz recv
#include <RCSwitch.h>  
RCSwitch mySwitch = RCSwitch();
const byte pwrRF = 27;
bool rfOn;

// ---- Display TM1637
#include "SevenSegmentTM1637.h"
#include "SevenSegmentExtended.h"
const byte CLK0 = 4; 
const byte DIO0 = 5;
SevenSegmentExtended d0(CLK0, DIO0);
const byte CLK1 = 6;
const byte DIO1 = 7;
SevenSegmentExtended d1(CLK1, DIO1);
char sevenTempr[4];
int sumPrev;

// ---- Display ST7920
#include "U8glib.h"
U8GLIB_ST7920_128X64 u8g(39, 38, 41, U8G_PIN_NONE); // screen constructor13, 12, 9, U8G_PIN_NONE
byte frame = 0;                          
bool prntRTC = 0;

// ---- Internal Serial Communication & State of Remote Appliances                            
bool onlink = 1;                       // 1 in order to send a sync request for binary reports, and try to toggle the Thermostat unit into 
                                       //    onlink mode at startup. After an unsuccesful attempt this bool will turn zero within five seconds. 
const int requestInt = 99;             // request for cyclic binary reports
String recvdStates;                    // store the received report
bool gotReport = 0;                    // the Thermostat unit has been seen since startup of the Central unit
const char expiredReport = 'X';        // the expired report is empty, contains only the preamble
String strTemprRecvd;                  // store the tempr value extracted from the data stream sent by the Thermostat unit

// ---- Memory Management
#include <EEPROM.h>  // memory calls
// i -->                0  1  2  3  4  5  6  7  8  9  10  11  12  13
const byte addr[14] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 22}; 
     // --------  Memory Map  --------
     //
     //     [i] VAL
     //      0  bool locked
     //      1  bool REMOVED FEATURE
     //      2  bool prntRTC
     //      3  bool relayDLState
     //      4  bool relayMPState
     //         ----> byte al[i]  VAL
     //      5  byte al[4]    0   alH0
     //      6  byte al[4]    1   alH1
     //      7  byte al[4]    2   alM0
     //      8  byte al[4]    3   alM1
     //         ----
     //      9  bool alOn
     //     10  bool rfOn
     //     11  bool vrOn
     //     12  byte RFID INIT
     //     13  byte RFID REL
     //
     // ------------------------------
byte pointer = 0;
                                    
// ---- External Serial Communication
#define exRXSize 5
char exRX[exRXSize];             // variable to receive data from the serial port
bool auth = 0;
const byte ledAuth = 26;
bool startup = 1;         // otherwise the self defense routine would run at startup
const byte extBTen = 3;   // ext bt enable

// ---- Local Appliances
const byte relayDL = 9;   // desk lights
bool relayDLState;
const byte relayMP = 12;  // media player
bool relayMPState;

// ---- Strings and Related Features
char inCharFromIntBT;
String strCollectFromIntBT;
#define strSize 6
String str[strSize];
#define functItems 74
// i -->                                0         1                2                    3                   4                   5                     6              7                  8                 9        10                 11               12    13         14                   15                    16                    17                     18               19   20   21                     22                    23        24              25       26   27   28   29   30               31                 32                  33              34                       35                36                37                  38                 39                 40                 41                 42                 43                 44                 45                 46                    47                      48           49       50                 51            52                  53                 54           55           56                    57                  58                 59                 60                 61   62          63                 64                  65                     66                   67                      68              69               70                       71                  72                    73
const String functStr[functItems] = { "READY.", "Voice command", "Bluetooth command", "IR code received", "BT code rejected", "RF signal received", "Key pressed", "Mediaplayer is ", "Desklights is ", "CODE= ", "* DEL | ENTER #", "Central unit ", "un", "locked!", "Desklights is on.", "Desklights is off.", "Mediaplayer is on.", "Mediaplayer is off.", "Temperature= ", ".", "!", "Thermostat Offlink!", "Thermostat Onlink!", "ONLINK", "CARD MANAGER", "del: ", "A", "B", "C", "D", "Card Deleted!", "Already Stored!", "New Card Stored!", "Memory Full!", "Invalid type of Card!", "Card Rejected!", "Card Accepted!", "Authorized User!", "REMOVED FEATURE", "REMOVED FEATURE", "REMOVED FEATURE", "REMOVED FEATURE", "REMOVED FEATURE", "REMOVED FEATURE", "REMOVED FEATURE", "REMOVED FEATURE", "SYSTEM REBOOT SOON", "You may connect now.", "Good bye.", "ERROR", "Clock adjusted.", "Please say", "What temperature", "would you like?", "a system ", "function!", "User disconnected.", "Alarm accepted. ", "Alarm rejected.", "Alarm disabled.", "Alarm enabled. ", ":", "Wake up!", "RF receiver on.", "RF receiver off.", "Target temperature:", "[10]-[24] Celsius", "[50]-[76] Fahrenheit", "VR3 enabled.", "VR3 disabled.", "The system is locked!", "Sending guide...", "No connected user.", "Guide sent." };
#define sevenItems 18
// i -->                               0       1       2       3       4       5       6       7       8       9      10      11      12      13      14      15      16      17
const String sevenStr[sevenItems] = {"    ", "SYS_", "boot", "CArd", "MENU", " dEL", " Add", "A_St", "FULL", "CodE", "----", "LEtS", "PLAY", "Good", " bYE", "Conn", "SCAN", "AL  " };

// ---- System Timers
#include <elapsedMillis.h>         
//                   ----  Countdn tmr for synch request or devalidation of received report            
elapsedMillis timer0;         // 8-bit, PWM timer, used by function elapsedMillis()
#define sysTmrExpired 5000    // timer of cyclic binary report expiration [ms]
//                   ----  Cyclic timers for various system functions as below;
#define cycTmrInterval0 200   // used for RTC call
#define cycTmrInterval1 800   // icon blink tmr
#define cycTmrInterval2 2400  // seven segment timed printouts
#define cycTmrInterval3 5000  // NUID event display
#define cycTmrDim 4
bool cTmrUp[cycTmrDim];               // binary state of each tmrs
unsigned long cTmrPrev[cycTmrDim];    // prev vals for comparison 

// ---- System Management
#include <avr/wdt.h>
uint8_t presc = WDTO_60MS;

// ---- ISD1820PY & Buzz
const byte play0 = 22;
const byte play1 = 23;
const byte LM386 = 25;
// i -->                 0   1
const byte buzzer[2] = {13, 24}; // D13(PWM) & D24

// ---- DS3231
#include <DS3231.h>
DS3231  rtc(SDA, SCL);     // init the DS3231 using the hardware interface
String strTM;
#define RTCArrSize 4
byte tm[RTCArrSize];
byte al[RTCArrSize];
bool alOn;
bool alActivated = 0;      // temp variable, becomes high if al has been turned on, used for serial report
bool alActive = 0;         // temp variable for TM and AL comparison, becomes high if these values match, and
                           //   activates the alarm procedure by turning alCnt into 1.
byte alCnt = 0;            // enables an alarm procedure whitch is longer than one minute, it increases until
                           //   reach the alCntLim limit. One alCnt period equals to cycTmrInterval2, thats why takes 2400ms.
const byte alCntLim = 255;

// ---- VR3
bool vrOn;
const byte ledVrOn = 29;
#include <SoftwareSerial.h>
#include "VoiceRecognitionV3.h" 
VR myVR(10, 11);          // RX, TX
uint8_t record[7];        // save record
uint8_t buf[64]; 
byte group;
#define spkHeater   (0)
#define spkAiring   (1)  
#define spkKitchen  (2)
#define spkMedia    (3)  
#define spkDesklig  (4)
#define spkSys      (5)  
#define spkTempr    (6)
#define spk17       (7) 
#define spk18       (8) 
#define spk19       (9) 
#define spk20      (10) 
#define spk14      (11) 
#define spk58      (12) 
#define spkBack    (13)
#define spkCost    (14) 
#define spkCost0   (15)
#define spkReport  (16) 
#define spkReboot  (17)
#define spkTime    (18) 
#define spkDisc    (19)
#define spkSilence (20)

// ---- Terminators & The Cleanup Crew
const char termCharNull = '0';
const char termChar = 'Z';
const char termCharSpc = ' ';
char termCharEmpty;
const String strTerm;
const int intTerm = 0;
const bool boolTerm = 0;

// ---- Startup
const uint8_t frame1[] U8G_PROGMEM = {
  0xFF, 0x7F, 0x41, 0x10, 0xB8, 0xFF, 0x02, 0xC0, 0x7F, 0x01, 0xC0, 0xBF, 
  0x2F, 0x08, 0x02, 0xFF, 0xFF, 0xBF, 0x40, 0x10, 0xA8, 0xFF, 0x02, 0x80, 
  0x7F, 0x01, 0xE0, 0xBF, 0x17, 0x08, 0x02, 0xFD, 0xFF, 0x7F, 0x41, 0x10, 
  0xB8, 0xFF, 0x02, 0xC0, 0x7F, 0x01, 0xC0, 0xBF, 0x2F, 0x08, 0x02, 0xFF, 
  0xFF, 0xBF, 0x40, 0x10, 0xA8, 0xFF, 0xFE, 0x9F, 0x7F, 0xFF, 0xFF, 0xBF, 
  0x17, 0x08, 0x02, 0xFD, 0xFF, 0x7F, 0x41, 0x10, 0xB8, 0xFF, 0x02, 0xC1, 
  0x7F, 0x81, 0xC0, 0xBF, 0x2F, 0x08, 0x02, 0xFF, 0xFF, 0xBF, 0xFE, 0xFF, 
  0xAF, 0xFF, 0x02, 0x81, 0x7F, 0x81, 0xE0, 0xBF, 0xD7, 0xFF, 0xFF, 0xFD, 
  0xFF, 0x7F, 0x41, 0x10, 0xB8, 0xFF, 0x02, 0xC1, 0x7F, 0x81, 0xC0, 0xBF, 
  0x2F, 0x08, 0x02, 0xFF, 0xFF, 0xBF, 0x40, 0x10, 0xA8, 0xFF, 0x02, 0x81, 
  0x7F, 0x81, 0xE0, 0xBF, 0x17, 0x08, 0x02, 0xFD, 0xFF, 0x7F, 0x41, 0x10, 
  0xB8, 0xFF, 0x02, 0xC1, 0x7F, 0x81, 0xC0, 0xBF, 0x2F, 0x08, 0x02, 0xFF, 
  0xFF, 0xBF, 0x40, 0x10, 0xA8, 0xFF, 0x02, 0x81, 0x7F, 0x81, 0xE0, 0xBF, 
  0x17, 0x08, 0x02, 0xFD, 0xFF, 0x7F, 0x41, 0x10, 0xB8, 0xFF, 0x02, 0xC1, 
  0x7F, 0x81, 0xC0, 0xBF, 0x2F, 0x08, 0x02, 0xFF, 0xFF, 0xBF, 0x40, 0x10, 
  0xA8, 0xFF, 0x02, 0x81, 0x7F, 0x81, 0xE0, 0xBF, 0x17, 0x08, 0x02, 0xFD, 
  0xFF, 0x7F, 0x41, 0x10, 0xB8, 0xFF, 0x02, 0xC1, 0x7F, 0x81, 0xC0, 0xBF, 
  0x2F, 0x08, 0x02, 0xFF, 0xFF, 0xBF, 0x40, 0x10, 0xA8, 0xFF, 0x02, 0x81, 
  0x7F, 0x81, 0xE0, 0xBF, 0x17, 0x08, 0x02, 0xFD, 0xFF, 0x7F, 0x41, 0x10, 
  0xB8, 0xFF, 0xFE, 0xFF, 0x7F, 0xFF, 0xFF, 0xBF, 0x2F, 0x08, 0x02, 0xFF, 
  0xFF, 0xBF, 0x40, 0x10, 0xA8, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xBE, 
  0x17, 0x08, 0x02, 0xFD, 0xFF, 0x7F, 0x41, 0x10, 0xB8, 0x7F, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0xBF, 0x2F, 0x08, 0x02, 0xFF, 0xFF, 0xBF, 0x40, 0x10, 
  0xA8, 0x7F, 0x00, 0x48, 0x22, 0x09, 0x00, 0xBF, 0x17, 0x08, 0x02, 0xFD, 
  0xFF, 0x7F, 0x41, 0x10, 0xB8, 0x7F, 0x20, 0x49, 0x22, 0x49, 0x02, 0xBF, 
  0x2F, 0x08, 0x02, 0xFF, 0xFF, 0xBF, 0xAA, 0xAA, 0xAA, 0x7F, 0x26, 0x49, 
  0x22, 0x49, 0x32, 0xBF, 0x57, 0x55, 0x55, 0xFD, 0xFF, 0x7F, 0x55, 0x55, 
  0xB5, 0x7F, 0x26, 0x49, 0x22, 0x49, 0x32, 0xBF, 0xAF, 0xAA, 0xAA, 0xFE, 
  0xFF, 0xBF, 0xAA, 0xAA, 0xAA, 0x7F, 0x26, 0x49, 0x22, 0x49, 0x32, 0xBF, 
  0x57, 0x55, 0x55, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x7F, 0x26, 0x49, 
  0x22, 0x49, 0x32, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xBF, 0x7F, 0x26, 0x49, 0x22, 0x49, 0x32, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x7F, 0x26, 0x49, 0x22, 0x49, 0x32, 0xBF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x7F, 0x26, 0x49, 
  0x22, 0x49, 0x32, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xBF, 0x7F, 0x26, 0x49, 0x22, 0x49, 0x32, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0x3F, 0x00, 0x49, 0x22, 0x49, 0x00, 0xBE, 
  0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 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, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 
  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xD5, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 
  0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 
  0x55, 0xD5, 0x55, 0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFC, 
  0xFF, 0x7F, 0xFC, 0xFF, 0xFF, 0x1F, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x1F, 0xF0, 0xFF, 0x1F, 0xF0, 0xFF, 0xFF, 0x03, 0xF0, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x0F, 0xE0, 0xFF, 0x0F, 0xE0, 0xFF, 
  0xFF, 0x00, 0xC0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x07, 0xC0, 
  0xFF, 0x07, 0xC0, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x03, 0x80, 0xFF, 0x03, 0x80, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x03, 0xC0, 0xFF, 0x03, 0xC0, 0xFF, 
  0x7F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x80, 
  0xFF, 0x05, 0x80, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFD, 0xDF, 0xFF, 0xFD, 0xDF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0x81, 0xFF, 0x05, 0x81, 0xFF, 
  0x3F, 0x10, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x05, 0xC1, 
  0xFF, 0x05, 0xC1, 0xFF, 0x7F, 0x10, 0x04, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x05, 0x81, 0xFF, 0x05, 0x81, 0xFF, 0x3F, 0x10, 0x04, 0xFF, 
  0xFF, 0xFF, 0x5F, 0xFD, 0xFF, 0xFF, 0x05, 0xC1, 0xFF, 0x05, 0xC1, 0xFF, 
  0x7F, 0x10, 0x04, 0xFF, 0xFF, 0xFF, 0x03, 0xE0, 0xFF, 0xFF, 0x05, 0x81, 
  0xFF, 0x05, 0x81, 0xFF, 0x3F, 0x10, 0x04, 0xFF, 0xFF, 0xFF, 0x79, 0x8F, 
  0xFF, 0xFF, 0x05, 0xC1, 0xFF, 0x05, 0xC1, 0xFF, 0x7F, 0x10, 0x04, 0xFF, 
  0xFF, 0xFF, 0x7C, 0x3F, 0xFF, 0xFF, 0x05, 0x81, 0xFF, 0x05, 0x81, 0xFF, 
  0x3F, 0x10, 0x04, 0xFF, 0xFF, 0x7F, 0x7E, 0x3F, 0xFE, 0xFF, 0x05, 0xC1, 
  0xFF, 0x05, 0xC1, 0xFF, 0x7F, 0x10, 0x04, 0xFF, 0xFF, 0x3F, 0x7D, 0xDF, 
  0xFC, 0xFF, 0x05, 0x81, 0xFF, 0x05, 0x81, 0xFF, 0x3F, 0x10, 0x04, 0xFF, 
  0xFF, 0x9F, 0x7B, 0xEF, 0xF9, 0xFF, 0x05, 0xC1, 0xFF, 0x05, 0xC1, 0xFF, 
  0x7F, 0x10, 0x04, 0xFF, 0xFF, 0x8F, 0x77, 0xF7, 0xF9, 0xFF, 0xFD, 0xFF, 
  0xFF, 0xFD, 0xFF, 0xFF, 0xBF, 0xFF, 0x7F, 0xFF, 0xFF, 0x9F, 0x6F, 0xFB, 
  0xF1, 0xFF, 0x01, 0x00, 0x55, 0x01, 0x80, 0xFF, 0x3F, 0x00, 0x00, 0xFF, 
  0xFF, 0x8F, 0x5F, 0xFD, 0xF9, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 
  0xAF, 0xAA, 0xAA, 0xFA, 0xFF, 0x9F, 0x3F, 0xFE, 0xF1, 0x7F, 0x55, 0x55, 
  0x55, 0x55, 0x55, 0xFF, 0x57, 0x55, 0x55, 0xFD, 0xFF, 0x0F, 0x00, 0x00, 
  0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x9F, 0x7F, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F, 0x7F, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x9F, 0x7F, 0xFF, 
  0xF1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0x8F, 0x7F, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 
};

const uint8_t frame2[] U8G_PROGMEM = {
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 
  0xFF, 0xFF, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x03, 0x00, 0x00, 
  0x1C, 0x00, 0x00, 0x00, 0xF0, 0x87, 0x1F, 0x00, 0x01, 0x30, 0x00, 0x00, 
  0x00, 0x3C, 0x00, 0x00, 0x00, 0x08, 0x60, 0x00, 0x00, 0x00, 0xCE, 0x1F, 
  0x38, 0x80, 0x21, 0xC0, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x88, 
  0x80, 0x01, 0x00, 0xC0, 0x00, 0x06, 0x00, 0x00, 0x22, 0x80, 0x01, 0x00, 
  0x40, 0x80, 0x00, 0x00, 0x00, 0x10, 0x04, 0x03, 0x00, 0x40, 0x20, 0x40, 
  0x00, 0x01, 0x20, 0x01, 0x02, 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x02, 0x06, 0x00, 0x60, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x06, 0x00, 
  0x20, 0x00, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x0C, 0x00, 0x30, 0xC0, 0x1F, 
  0x00, 0xC6, 0x7F, 0x00, 0x18, 0x00, 0x18, 0xE0, 0x7F, 0x80, 0xC3, 0xDF, 
  0x02, 0x3E, 0x00, 0x0C, 0xC0, 0xFF, 0x83, 0xF9, 0xFF, 0x02, 0x68, 0x00, 
  0x06, 0x00, 0xF0, 0x03, 0x1F, 0x01, 0xF0, 0xC1, 0x00, 0x6A, 0x00, 0x80, 
  0x00, 0x06, 0x07, 0xFC, 0x87, 0x01, 0x82, 0x0F, 0x80, 0x00, 0x00, 0x9E, 
  0x0F, 0x46, 0x01, 0xC2, 0xB9, 0x81, 0x00, 0x00, 0xF8, 0x21, 0x4C, 0x03, 
  0x02, 0xF0, 0xC1, 0x00, 0x00, 0x00, 0x70, 0x48, 0x02, 0x02, 0x04, 0x70, 
  0x00, 0x03, 0x00, 0x7C, 0x58, 0x02, 0x22, 0x06, 0x38, 0x00, 0x2F, 0x00, 
  0xCF, 0x5B, 0x02, 0x0E, 0x06, 0x1C, 0x00, 0x08, 0xC0, 0xC3, 0x49, 0x03, 
  0x16, 0x0F, 0x39, 0xF0, 0x09, 0xF8, 0x60, 0x08, 0x03, 0x4C, 0x0F, 0x60, 
  0x00, 0x0D, 0x5F, 0x70, 0x8C, 0x01, 0x08, 0x3F, 0xC0, 0x03, 0xE0, 0x43, 
  0x3C, 0x90, 0x01, 0x18, 0xF7, 0x80, 0x01, 0x7E, 0x60, 0x1F, 0xC0, 0x00, 
  0x18, 0xD7, 0x07, 0xF8, 0x3F, 0xF0, 0x1B, 0x70, 0x00, 0x10, 0x13, 0xFF, 
  0x7F, 0x30, 0xFC, 0x0C, 0x30, 0x00, 0x10, 0x97, 0xC1, 0x10, 0xA0, 0x7F, 
  0x04, 0x18, 0x00, 0x10, 0x9F, 0x41, 0x10, 0xF0, 0x4F, 0x06, 0x08, 0x00, 
  0x10, 0xFF, 0xEF, 0x38, 0xFF, 0x41, 0x03, 0x0C, 0x00, 0x10, 0xFF, 0xFF, 
  0xFF, 0x7F, 0xC0, 0x01, 0x04, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0x47, 0xC0, 
  0x00, 0x06, 0x00, 0x10, 0xFF, 0xFF, 0xFF, 0x40, 0x70, 0x00, 0x03, 0x00, 
  0x10, 0xEA, 0xFF, 0x67, 0xC0, 0x18, 0x00, 0x03, 0x00, 0x10, 0x5E, 0xC6, 
  0x60, 0x80, 0x0E, 0x80, 0x01, 0x00, 0x10, 0xCC, 0x84, 0x60, 0x80, 0x07, 
  0xE8, 0x00, 0x00, 0x10, 0xBC, 0x8C, 0x60, 0xF0, 0x21, 0x72, 0x00, 0x00, 
  0x18, 0xF0, 0x9F, 0xE1, 0x3F, 0x88, 0x18, 0x00, 0x00, 0x18, 0x00, 0xFF, 
  0xFF, 0x01, 0x22, 0x0E, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x80, 0x88, 
  0x07, 0x00, 0x00, 0x18, 0x08, 0x40, 0x01, 0x10, 0xC2, 0x01, 0x00, 0x00, 
  0x18, 0x20, 0x00, 0x00, 0x46, 0x78, 0x00, 0x00, 0x00, 0x18, 0x01, 0xFF, 
  0x0F, 0x0C, 0x1E, 0x00, 0x00, 0x00, 0x18, 0x04, 0x00, 0x60, 0x80, 0x07, 
  0x00, 0x00, 0x00, 0x18, 0x30, 0xFE, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00, 
  0x10, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 
  0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xF0, 0x03, 0x00, 
  0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x1F, 0xFE, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x1F, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
}; 

const uint8_t frame3[] PROGMEM = { 
  0xFF, 0xFF, // 11111111 11111111 00
  0xFF, 0xFF, // 11111111 11111111 01
  0xCF, 0xFF, // 11001111 11111111 02
  0xC3, 0xFF, // 11000011 11111111 03
  0xC0, 0xFF, // 11000000 11111111 04
  0xC0, 0x3F, // 11000000 00111111 05
  0xC0, 0x0F, // 11000000 00001111 06
  0xC0, 0x03, // 11000000 00000011 07
  0xC0, 0x0F, // 11000000 00001111 08
  0xC0, 0x3F, // 11000000 00111111 09
  0xC0, 0xFF, // 11000000 11111111 10 
  0xC3, 0xFF, // 11000011 11111111 11
  0xCF, 0xFF, // 11001111 11111111 12
  0xFF, 0xFF, // 11111111 11111111 13
}; 

const uint8_t frame4[] PROGMEM = {
  0xFF, 0xFF, // 11111111 11111111 00
  0xDF, 0xFB, // 11011111 11111011 01
  0xEC, 0x37, // 11101100 00110111 02
  0xF8, 0x1F, // 11111000 00011111 03 
  0xF0, 0x0F, // 11110000 00001111 04
  0x90, 0x09, // 10010000 00001001 05
  0xF0, 0x0F, // 11110000 00001111 06
  0xF8, 0x1F, // 11111000 00011111 07
  0xDC, 0x3B, // 11011100 00111011 08
  0xBD, 0xBD, // 10111101 10111101 09
  0xFC, 0x3F, // 11111100 00111111 10
  0xFD, 0xBF, // 11111101 10111111 11
  0xFE, 0x7F, // 11111110 01111111 12
  0xFF, 0xFF, // 11111111 11111111 13
}; 

const uint8_t frame5[] PROGMEM = {
  0xFF, 0xFF, // 11111111 11111111 00
  0xFF, 0xFF, // 11111111 11111111 01
  0xFC, 0x3F, // 11111100 00111111 02
  0xF8, 0x1F, // 11111000 00011111 03 
  0xF0, 0x0F, // 11110000 00001111 04
  0xF0, 0x0F, // 11110000 00001111 05
  0xF0, 0x0F, // 11110000 00001111 06
  0xF8, 0x1F, // 11111000 00011111 07
  0xFC, 0x3F, // 11111100 00111111 08
  0xFD, 0xBF, // 11111101 10111111 09
  0xFC, 0x3F, // 11111100 00111111 10
  0xFD, 0xBF, // 11111101 10111111 11
  0xFE, 0x7F, // 11111110 01111111 12
  0xFF, 0xFF, // 11111111 11111111 13
};

const uint8_t frame6[] PROGMEM = {
  0xFF, 0xFF, // 11111111 11111111 00
  0xFE, 0x7F, // 11111110 01111111 01
  0xF8, 0x1F, // 11111000 00011111 02
  0xF3, 0xCF, // 11110011 11001111 03 
  0xE7, 0xE7, // 11100111 11100111 04
  0xEF, 0xF3, // 11101111 11110111 05
  0xCF, 0xF3, // 11001111 11110011 06
  0xC0, 0x03, // 11000000 00000011 07
  0xC0, 0x03, // 11000000 00000011 08
  0xC1, 0x83, // 11000001 10000011 09
  0xC1, 0x83, // 11000001 10000011 10
  0xC1, 0x83, // 11000001 10000011 11
  0xC0, 0x03, // 11000000 00000011 12
  0xFF, 0xFF, // 11111111 11111111 13
}; 

const uint8_t frame7[] PROGMEM = {
  0xFF, 0xFF, // 11111111 11111111 00
  0xFF, 0xFF, // 11111111 11111111 01
  0xF3, 0xE7, // 11110011 11100111 02
  0xF3, 0xE7, // 11110011 11100111 03 
  0xF3, 0xE7, // 11110011 11100111 04
  0x80, 0x67, // 10000000 01100111 05
  0x80, 0x67, // 10000000 01100111 06
  0xF3, 0xE7, // 11110011 11100111 07
  0xF3, 0xE7, // 11110011 11100111 08
  0xF3, 0xC3, // 11110011 11000011 09
  0xFF, 0x81, // 11111111 10000001 10
  0xFF, 0x81, // 11111111 10000001 11
  0xFF, 0xC3, // 11111111 11000011 12
  0xFF, 0xE7, // 11111111 11100111 13
  0xFF, 0xFF, // 11111111 11111111 14
}; 

const uint8_t frame8[] PROGMEM = {
  0x00, 0x00, // 00000000 00000000 00
  0x00, 0x00, // 00000000 00000000 01
  0x0C, 0x18, // 00001100 00011000 02
  0x0C, 0x18, // 00001100 00011000 03 
  0x0C, 0x18, // 00001100 00011000 04
  0x7F, 0x98, // 01111111 10011000 05
  0x7F, 0x98, // 01111111 10011000 06
  0x0C, 0x18, // 00001100 00011000 07
  0x0C, 0x18, // 00001100 00011000 08
  0x0C, 0x3C, // 00001100 00111100 09
  0x00, 0x7E, // 00000000 01111110 10
  0x00, 0x7E, // 00000000 01111110 11
  0x00, 0x3C, // 00000000 00111100 12
  0x00, 0x18, // 00000000 00011000 13
  0x00, 0x00, // 00000000 00000000 14
}; 

const uint8_t frame9[] PROGMEM = {
  0xFF, 0xFF, // 11111111 11111111 00
  0xFC, 0x1F, // 11111100 00011111 01
  0xF0, 0x07, // 11110000 00000111 02
  0xEE, 0x0B, // 11101110 00001011 03 
  0xE7, 0x1B, // 11100111 00011011 04
  0xC3, 0x39, // 11000011 00111001 05
  0xC1, 0x71, // 11000001 01110001 06
  0xC0, 0x81, // 11000000 10000001 07
  0xC7, 0x41, // 11000111 01000001 08
  0xCE, 0x61, // 11001110 01100001 09
  0xEC, 0x73, // 11101100 01110011 10
  0xE8, 0x3B, // 11101000 00111011 11
  0xF0, 0x07, // 11110000 00000111 12
  0xFC, 0x1F, // 11111100 00011111 13
  0xFF, 0xFF, // 11111111 11111111 14
}; 

const uint8_t frame10[] PROGMEM = {
  0xFF, 0xFF, // 11111111 11111111 00
  0xFC, 0x9F, // 11111100 10011111 01
  0xF0, 0xC7, // 11110000 11000111 02
  0xE0, 0xE3, // 11100000 11100011 03 
  0xE0, 0xE3, // 11100000 11100011 04
  0xCC, 0xC1, // 11001100 11000001 05
  0xDE, 0x81, // 11011110 10000001 06
  0xFF, 0xFF, // 11111111 11111111 07
  0xC0, 0xBD, // 11000000 10111101 08
  0xC1, 0x99, // 11000001 10011001 09
  0xE3, 0x83, // 11100011 10000011 10
  0xE3, 0x83, // 11100011 10000011 11
  0xF1, 0x87, // 11110001 10000111 12
  0xFC, 0x9F, // 11111100 10011111 13
  0xFF, 0xFF, // 11111111 11111111 14
}; 

const uint8_t frame11[] PROGMEM = {  
  0x1F, 0x03, 0x18, // 00011111 00000011 00011000 00
  0x3B, 0x83, 0xB8, // 00111011 10000011 10111000 01
  0x79, 0xC1, 0xF0, // 01111001 11000001 11110000 02
  0xDA, 0xE0, 0xE0, // 11011010 11100000 11100000 03
  0xEB, 0x61, 0xF0, // 11101011 01100001 11110000 04
  0xF2, 0xE3, 0xB8, // 11110010 11100011 10111000 05
  0xF9, 0xE3, 0x18, // 11111001 11100011 00011000 06
  0xF2, 0xE0, 0x00, // 11110010 11100000 00000000 07
  0xEB, 0x60, 0x00, // 11101011 01100000 00000000 08
  0xDA, 0xE0, 0x00, // 11011010 11100000 00000000 09
  0x79, 0xC0, 0x00, // 01111001 11000000 00000000 10
  0x3B, 0x80, 0x00, // 00111011 10000000 00000000 11
  0x1F, 0x00, 0x00, // 00011111 00000000 00000000 12
}; 

void setup() {
  TM1637( 0, 0, 5);
  readEEPROM();
  rtc.begin();
  irrecv.enableIRIn();
  mySwitch.enableReceive(0);  // receiver on D2 (interrupt 0)
  SPI.begin();                // init SPI bus
  rfid.PCD_Init();            // init MFRC522 
  pinMode(relayDL, OUTPUT);
  pinMode(relayMP, OUTPUT); 
  pinMode(extBTen, OUTPUT);
  digitalWrite(extBTen, 0);
  pinMode(ledAuth, OUTPUT);  
  digitalWrite(ledAuth, 0);
  pinMode(ledVrOn, OUTPUT);   
  for (byte i = 0; i < 2; i++) {
    pinMode(buzzer[i], OUTPUT);
  }
  pinMode(play0, OUTPUT); 
  pinMode(play1, OUTPUT);
  pinMode(LM386, OUTPUT);
  pinMode(pwrRF, OUTPUT);
  pinMode(btnAl, INPUT);
  Serial.begin(9600);   
  Serial2.begin(9600);        // start serial communication at 9600bps EXT
  for (byte i = 0; i < exRXSize; i++) {
    exRX[i] = termCharSpc;
  }
  Serial3.begin(9600);        // INT
  myVR.begin(9600);
  voiceLoad(0);   
  ISD1820PY(0); 
  strSelector(0);
}

void loop() {
  irRecv();
  extRX();
  cyclicSysTmr(); 
  countdnSysTmr();
  intRX();
  btnRecv();
  sevenSum();
  voiceCmd();
  rfRecv();
  rfID();
  u8g.firstPage();  // picture loop
  do {
    draw();
  } while(u8g.nextPage());
  if (frame == 0) { 
    TM1637(2, 0, 0);
    delay(1000);
    frame = 1;
    clrScr(); 
  }
}

// ---- System Management
void wdRst() {
  wdt_enable(presc);  // start wd with the prescaller
  while(1) {          // the prescaller time has to expire 
  }        
}

void readEEPROM() {
  for (byte i = 0; i < 6; i++) {
    if (i < 4) {
      al[i] = EEPROM.read(addr[i + 5]);
      delay(20);
    }
    if (i == 5) {
      i = 9;
    }
    switch(i) {
      case 0:
        lockSystem(EEPROM.read(addr[i]));
        rfidHandler();
      case 1:
     // REMOVED FEATURE
      case 2:
        prntRTC = EEPROM.read(addr[i]);
      case 3:
        digitalWrite(relayDL, relayDLState = EEPROM.read(addr[i]));
        break;
      case 4:
        digitalWrite(relayMP, relayMPState = EEPROM.read(addr[i]));
        break;
      case 9:
        alOn = EEPROM.read(addr[i]);
        delay(20);
        i++; 
        digitalWrite(pwrRF, rfOn = EEPROM.read(addr[i])); 
        delay(20);
        i++; 
        digitalWrite(ledVrOn, vrOn = EEPROM.read(addr[i])); 
    }
    delay(20);
  }
}

// ---- Start of System Security Routines
void rfID() {
  if (cardManager) {
    for (byte i = 0; i < arrNUIDSize; i++) {
      if ((delNUID[i] == 1) && (strNUID[i] != strTerm)) {
        strNUID[i] = strTerm;
        delNUID[i] = boolTerm;
        cardBoolSwitches[3] = 1;     // del card
        cardBoolSwitches[2] = 1;     // not stored
        TM1637( 3, 5, 0);
      }
    }
  } 
  if (!rfid.PICC_IsNewCardPresent()) // wait for a new card
    return;
  if (!rfid.PICC_ReadCardSerial())   // check if the card has been readed
    return;
  cardBoolSwitches[0] = boolTerm;    // the card has not been seen
  strC = strTerm;
  MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak);
  if ((piccType != MFRC522::PICC_TYPE_MIFARE_MINI) && (piccType != MFRC522::PICC_TYPE_MIFARE_1K) && (piccType != MFRC522::PICC_TYPE_MIFARE_4K)) {
    if (!cardManager) {
      strSelector(34);
    }
    else {
      cardBoolSwitches[6] = 1;       // invalid type of card
      ISD1820PY(1);
    }
    return;  
  }
  for (byte i = 0; i < rfid.uid.size; i++) {
    strC.concat(String(rfid.uid.uidByte[i] < 0x10 ? " 0" : " "));
    strC.concat(String(rfid.uid.uidByte[i], HEX));
  }
  strC = strC.substring(1);
  if (cardManager) {
    if (strNUID[3].charAt(0) != termCharEmpty) {
      cardBoolSwitches[7] = 1;      // memory full
      TM1637( 3, 8, 0);
      return;
    }
    for (byte i = 0; i < arrNUIDSize; i++) { 
      if (strC == strNUID[i]) {     // maybe the readed card has been stored earlier
        cardBoolSwitches[4] = 1;    // already stored
        TM1637( 3, 7, 0);
      }
    }
    if (!cardBoolSwitches[4]) {
      for (byte i = 0; i < arrNUIDSize; i++) {
        if ((strNUID[i] == strTerm) && (!cardBoolSwitches[0]) && (strC != strTerm)) { // if there is a space for the new card, but only one space needed, if the reading strC isnt empty
          strNUID[i] = strC;
          cardBoolSwitches[5] = 1;  // card new
          cardBoolSwitches[0] = 1;  // card seen (because we want only one time to store) 
          cardBoolSwitches[2] = 1;  // card NOT stored yet
          TM1637( 3, 6, 0);
        }
      } 
    }
  } 
  else {
    for (byte i = 0; i < arrNUIDSize; i++) {
      if (strNUID[i] == strC) {
        lockSystem(!locked);
        strSelector(36);
        extTX(1);
      }
    }
    if ((locked) && (strNUID[0] != strC) && (strNUID[1] != strC) && (strNUID[2] != strC) && (strNUID[3] != strC)) {
      strSelector(35);
      extTX(1);
      ISD1820PY(1);
    }
  }
  rfid.PICC_HaltA();          // halt PICC
  rfid.PCD_StopCrypto1();     // stop encryption on PCD   
}

void rfidHandler() { 
  if (cardBoolSwitches[1]) {  // read at startup
    pointer = addr[12];
    for (byte i = 0; i < arrNUIDSize; i++) {
      strNUID[i] = (EEPROM.get(pointer, arrNUID[i])); 
      delay(20);  
      pointer = pointer + addr[13];
    }
    cardBoolSwitches[1] = boolTerm;
  }
  if (cardBoolSwitches[2]) {  // not stored yet or marked for delete
    buzz(0, 13, 1, 0);
    for (byte i = 0; i < (arrNUIDSize - 1); i++) {  // sort
      if (strNUID[i] == strTerm) {
        strNUID[i] = strNUID[i + 1];
        strNUID[i + 1] = strTerm;
      }
    }
    pointer = addr[12];
    for (byte i = 0; i < arrNUIDSize; i++) {
      strNUID[i].toCharArray(arrNUID[i], strNUID[i].length() + 1);  // conv str to ch array
      strNUID[i] = (EEPROM.put(pointer, arrNUID[i]));
      delay(40);   
      pointer = pointer + addr[13];
    }
    cardBoolSwitches[2] = boolTerm; 
  }
}

void lockSystem(bool op) {  // 0: unlock, 1: lock
  bool prevState = locked;
  EEPROM.write(addr[0], op);
  delay(40);
  locked = EEPROM.read(addr[0]);
  delay(20); 
  if (locked) {
    cardManager = boolTerm;
    sum = intTerm;
    relayHandlerDL(boolTerm);
    relayHandlerMP(boolTerm);
  }
  if (locked != prevState) {
    extTX(0);
  }
  intTX(0, lock_strings[locked]);
}

// ---- Start of 315/330/433MHz Receiver
void rfRecv() { 
  if ((locked) || (!pwrRF)) {
    return;
  }    
  if (mySwitch.available()) {
    if (mySwitch.getReceivedValue() != 0) {   
                                         // btn 'A' - Airing
                                                    //       <-- ADDR 2^20 | DATA 2^4 -->
      if (mySwitch.getReceivedValue() == 5592332) { // 010101010101010100001100
        delay(50);                                  // TRI-STATE FFFFFFFF0010
        if (!onlink) {                              // RAW 16972,524,1664,1576,572,516,1656,1596,556,544,1644,1604,556,508,1660,1584,580,528,1648,1588,552,540,1648,1596,564,500,1668,1576,576,516,1668,1596,548,516,1664,508,1668,532,1656,500,1672,1592,576,1552,640,464,1676,504,1664,
          strSelector(21);                          // PulseLength: 545 microseconds Protocol: 1
        }
        else {                        
          intTX(0, 42);                               
          strSelector(5);                             
        }
      }                                  // btn 'B' - Kitchen lights
      if (mySwitch.getReceivedValue() == 5592512) { // 010101010101010111000000
        delay(50);                                  // FFFFFFFF1000    
        if (!onlink) {                              // 16952,528,1644,1596,532,524,1648,1588,564,528,1636,1596,544,512,1656,1588,564,508,1652,1580,568,516,1656,1580,552,508,1664,1552,612,476,1680,1584,540,1584,568,1588,564,508,1656,528,1644,524,1656,500,1668,508,1664,504,1672,
          strSelector(21);                          // PulseLength: 546 microseconds Protocol: 1
        }
        else {          
          intTX(0, 82);                               
          strSelector(5);                             
        }
      }                                  // btn 'C' - Media player
      if (mySwitch.getReceivedValue() == 5592323) { // 010101010101010100000011
        delay(50);                                  // FFFFFFFF0001
        relayHandlerMP(2);                          // 16980,532,1640,1588,580,504,1660,1608,540,536,1648,1608,540,516,1656,1580,588,496,1676,1596,552,536,1636,1580,588,488,1688,1580,560,520,1664,1564,592,484,1672,512,1668,516,1668,520,1652,504,1664,536,1644,1608,564,1584,556,
        strSelector(5);                             // PulseLength: 546 microseconds Protocol: 1                                    
      }                                  // btn 'D' - Desklights                       
      if (mySwitch.getReceivedValue() == 5592368) { // 010101010101010100110000
        delay(50);                                  // FFFFFFFF0100
        relayHandlerDL(2);                          // 16996,528,1644,1596,544,508,1664,1576,584,496,1668,1568,580,536,1644,1588,560,500,1660,1564,604,484,1708,1580,524,524,1652,1580,568,532,1656,1580,556,508,1668,512,1668,1576,568,1600,552,508,1672,520,1672,484,1676,504,1664,
        strSelector(5);                             // PulseLength: 546 microseconds Protocol: 1                             
      }                                             
    }
    mySwitch.resetAvailable();
  }
}

// ---- Start of Matrix Handler Sequence
void btnRecv() {
  // --------------------- Accepted Keys on Main Screen --------------------------------------------------------------------
  //
  // -- Remote appliances:
  //   'A' : Airing On / Off
  //   'B' : Kitchen lights On / Off
  //   '*' : Heater On / Off (15 min timed mode)
  //
  // -- Local appliances:
  //   'C' : Media player On / Off
  //   'D' : Desklights On / Off
  // 
  // -- Other functions:
  //   '0' .. '9' : Enter Numeric Code command such as Target Temperature for 
  //                the Thermostat mode [10-24 (as Celsius) or 50-76 (as Fahrenheit)],
  //                or two-digit control code to access the attached home devices or system functions (see details below).
  //            --> '*': Delete the typed code, and go back to the Main Screen
  //            --> '#': Enter code
  //
  //        [by pressing first time] [second time]                                         [third time]
  //   '0' : Print RTC on LCD On  --> Print both RTC & Alarm on LCD, and turn Alarm On  --> Dismiss both
  //
  //   '#' : Enter the RFID handler menu
  //     --> 'A' : Delete pos 0    
  //     --> 'B' : Delete pos 1 
  //     --> 'C' : Delete pos 2    
  //     --> 'D' : Delete pos 3
  //     --> '#' : Exit RFID menu and go back to the Main Screen
  // -----------------------------------------------------------------------------------------------------------------------
  
  if (digitalRead(btnAl)) {
    delay(50);
    alOn = !alOn;
    EEPROM.write(addr[9], alOn);
    delay(40);
    TM1637(0, 0, 1); 
    buzz(0, 12, 10, 1);
  }
  char customKey = customKeypad.getKey();
  if (customKey != NO_KEY) {
    if (alCnt > 0) {
      alOn = boolTerm;
      EEPROM.write(addr[9], alOn);
      delay(40); 
      alCnt = alCntLim;       
      TM1637( 0, 0, 1);
      strSelector(59);
      return;
    }
    buzz(0, 22, 4, 0);
    if (group != 0) {
      group = 0;
      return;
    }
    if ((customKey == '0') && (!cardManager) && (sum == intTerm)) {
      TMandALmanager();
      return;
    }
    if (locked) {
      strSelector(70);
      return;
    }     
    if ((customKey == '#') && (sum == intTerm)) {  // rfid menu
      if (!cardManager) {
        TM1637( 3, 4, 0);
      }
      cardManager = !cardManager;
      if (!cardManager) {
        TM1637( 0, 0, 1);
      }
    }  
    if (cardManager) {  
      switch (customKey) {
      case 'A':
        delay(50);
        delNUID[0] = 1;
        break;
      case 'B':
        delay(50);
        delNUID[1] = 1;
        break;
      case 'C':
        delay(50);
        delNUID[2] = 1;
        break;
      case 'D':
        delay(50);
        delNUID[3] = 1;
        break;
      }  
    }
    else {
      switch (customKey) {
        case 'A':
          delay(10);
          if (!onlink) {                              
            strSelector(21);                          
          }
          else {  
            strSelector(6);
            intTX(0, 42);
          }
          break;
        case 'B':
          delay(10); 
          if (!onlink) {                              
            strSelector(21);                          
          }
          else {      
            strSelector(6);
            intTX(0, 82);
          }
          break;
        case 'C':
          delay(10);
          strSelector(6);
          relayHandlerMP(2);
          break;
        case 'D':
          delay(10);
          strSelector(6);
          relayHandlerDL(2);
          break;
        case '*':
          delay(10);
          if (sum > intTerm) {  // del the numeric code
            sum = intTerm;
          }
          else {
            if (!onlink) {                              
              strSelector(21);                          
            }
            else {  
              intTX(0, 32);
            }
          }
          break;
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9':
          delay(10);
          if ((sum <= 10) && (sum <= 99)) {
            sum = sum * 10 + (customKey - '0');
          }
          break;
        case '#':
          delay(10);
          if (sum == 25) {
            intTX(0, sum);
            delay(100);
            wdRst();
            return;            
          }
          if (sum == 26) {
            rfOn = !rfOn;
            digitalWrite(pwrRF, rfOn); 
            EEPROM.write(addr[10], rfOn); 
            delay(40);
            if (rfOn) {
              strSelector(63);
            }
            else {
              strSelector(64);
            }
          }
          if (sum == 27) {
            vrOn =! vrOn;
            digitalWrite(ledVrOn, vrOn);
            EEPROM.write(addr[11], vrOn); 
            delay(40);
            if (vrOn) {
              strSelector(68);
            }
            else {
              strSelector(69);
            }            
          }
          if (sum == 28) {
            sum = intTerm;
            if (auth) {
              scr();  
              strSelector(71);
              extTX(3);        
            }
            else {
              strSelector(72);
            }
          }
...

This file has been truncated, please download it to see its full contents.

Thermostat Unit [V2.0]

Arduino
// ---- THERMOSTAT PROGRAM CODE v2.0
// 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;                               // scr pointer

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

// ---- Strings for Display Printout and Bluetooth Reports 
#define STATE_ITEMS 3    // device state indicator strings for outputs
// i ->                                  0      1       2
const String state_str[STATE_ITEMS] = {"on.", "off.", "auto."}; 
String heaterState;               
String airingState;
String lightingState;
#define FUNCT_ITEMS 22
// i ->                                  0             1             2               3                4                  5               6                  7            8                 9     10    11    12        13              14                 15         16    17         18                   19   20        21
const String funct_str[FUNCT_ITEMS] = {"Heater is ", "Airing is ", "Lighting is ", "Window Alert!", "Hardware Error!", "Hit a Key >>", "or send a Code!", "Target = ", "Temperature = ", " * ", " -", "> ", "REPORT", "Celsius mode", "Fahrenheit mode", "System ", "un", "locked!", "Command rejected!", "X", "cost= ", "USD"};

// ---- Memory Management
#include <EEPROM.h>
const byte addr[4] = { 0, 1, 2, 3}; // ---- Memory Map
                                    //     [i] STORED
                                    //      0  byte tTarget
                                    //      1  bool celsius 
                                    //      2  bool locked
                                    //      3  int costMinutes, initial address [int: 2^16]

// ---- 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]
bool sftyTmrEnded;                  // boolean startup, the timer0 has ended
byte tTarget;                       // adjusted target tempr
bool celsius;                       // measurement unit; 0 = F, 1 = C
float heatCorrVal;                  // declares the degree of overheating and cooling back, see tempMeas() function
#define mUnit 2
#define tRef 2
#define corr 3
const float hCorrRef[mUnit][tRef] = {{62.6, 66.2}, {17, 19}};
const float hCorrVal[mUnit][corr] = {{0.9, 0.72, 0.54}, {0.5, 0.4, 0.3}};
bool hState = 0;                    // heater boolean state
bool hStatePrev = 0;                // previous 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
float temprStart;                   // copy of measured value for summary of a heating period
bool windowAlrt = 0;                // specified degree of tempr drop
#define aVal 3                      // drop/lift/under
const float wAlrt[mUnit][aVal] = {{ 0.36, -0.216, 68}, { 0.2, -0.12, 20}};
// = {{ 0.36, 0.2}, {-0.216, -0.12}, {68, 20}}; 
bool measError = 0;                 // measured tempr value is out of the range specified as normal
bool errMsgSentBySys = 0;           // do not flood
const long temprInterval = 60000;   // cyclic tempr measurement interval [ms]
unsigned long temprTmrPrev = 0;     // the elapsed will be the previous when temprMeas() called
bool sysChanged = 0;                // this bool will high, if the tempr meas system has changed recently (C2F/F2C),  
                                    // so the tempr analisys won't start due to the unappropriate temprPrev value
bool hPeriodFin = 0;                // writeout the summary after a heating period 
int costMinutes;                    // minute counter stored in EEPROM
int minutes = 0;                    // minute counter for summary of a heating period                                 
//                |<--  cost of 1 min  -->|
//                 |<--  USD/m^3 -->|
float costCoeff = ((10.52 / 28.31685) / 50); // based on the U.S. average annual natural gas residental price; $10.52 / 1000ft^3 (www.eia.gov)
float cost;                                  // 1000ft^3 = 28.31685m^3, and my boiler uses up 1m^3 natural gas in 50 minutes
                                  
// ---- System & Security
#include <avr/wdt.h>
uint8_t presc = WDTO_15MS;
bool locked;
bool startup = 1;                   // keep avoid a duplicate BT report at startup if the system is locked

// ---- Configuration of Serial Communication on virtual RXD/TXD [D8/D4]
#include <SoftwareSerial.h>   
const int RX1 = 8;
const int TX1 = 4;
SoftwareSerial sUART(RX1,TX1); 
char RX[2];                        // store received serial data
#define rprtInterval 1000          // sending interval of the Cyclic Binary Synchronous Report 
unsigned long prevRprt = 0;        //                    (please see details & the structure on the bottom of the code)
bool sent = 0;
bool onlink = 0;

// ---- Terminators & The Cleanup Crew
const char charTerm = 'Z';
const bool boolTerm = 0;
const int intTerm = 0;

const uint8_t frame1[] U8G_PROGMEM = {  // XBM 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, 0x3F, 0x00, 0xFE, 0xFF, 
  0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFC, 0xFF, 0x7F, 0xF0, 
  0x3F, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 
  0xFC, 0xFF, 0x7F, 0xF0, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 
  0xFF, 0xFF, 0x1F, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 
  0x8F, 0xFF, 0x1F, 0x7F, 0x8C, 0x3F, 0x1E, 0xFF, 0x00, 0xFE, 0x1F, 0xFF, 
  0xF1, 0x00, 0x18, 0xC0, 0x8F, 0xFF, 0x1F, 0x7F, 0x8C, 0x3F, 0x1E, 0xFF, 
  0x00, 0xFE, 0x1F, 0xFF, 0xF1, 0x00, 0x18, 0xC0, 0x8F, 0xFF, 0x1F, 0x1F, 
  0x0C, 0x3E, 0x1E, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0x31, 0xFE, 0x7F, 0xFC, 
  0x8F, 0xFF, 0x1F, 0x1F, 0x0C, 0x3E, 0x1E, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 
  0x31, 0xFE, 0x7F, 0xFC, 0x0F, 0x0E, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0xFC, 
  0x00, 0xF8, 0x1F, 0x7C, 0x30, 0xFE, 0x7F, 0xF0, 0x0F, 0x0E, 0x18, 0x1F, 
  0x0C, 0x3E, 0x1E, 0xFC, 0x00, 0xF8, 0x1F, 0x7C, 0x30, 0xFE, 0x7F, 0xF0, 
  0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C, 
  0xF0, 0x00, 0x7E, 0xF0, 0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C, 
  0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x00, 0x7E, 0xF0, 0x0F, 0xFE, 0x18, 0x1F, 
  0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x3F, 0x78, 0xF0, 
  0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C, 
  0xF0, 0x3F, 0x78, 0xF0, 0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C, 
  0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x3F, 0x78, 0xF0, 0x0F, 0xFE, 0x18, 0x1F, 
  0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x3F, 0x78, 0xF0, 
  0x3F, 0x00, 0x7E, 0x00, 0x3C, 0x80, 0x07, 0xF0, 0x00, 0xF8, 0x7F, 0x00, 
  0x3C, 0x00, 0x1E, 0xC0, 0x3F, 0x00, 0x7E, 0x00, 0x3C, 0x80, 0x07, 0xF0, 
  0x00, 0xF8, 0x7F, 0x00, 0x3C, 0x00, 0x1E, 0xC0, 0xFF, 0xFF, 0xFF, 0x1F, 
  0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 
  0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 
  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, 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, 
  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, 0x7E, 0x06, 0xE6, 0x3F, 0x06, 0xC6, 0x7F, 0xFE, 0xE7, 0x3F, 0x7E, 
  0xFE, 0xC7, 0x7F, 0x00, 0x00, 0x30, 0x06, 0x66, 0x60, 0x06, 0x66, 0x00, 
  0x60, 0x60, 0x60, 0x30, 0x06, 0x60, 0x00, 0x00, 0x00, 0x30, 0x06, 0x66, 
  0x60, 0x06, 0x66, 0x00, 0x60, 0x60, 0x60, 0x30, 0x06, 0x60, 0x00, 0x00, 
  0x00, 0x30, 0x1E, 0x66, 0x60, 0x06, 0x66, 0x00, 0x60, 0x60, 0x60, 0x30, 
  0x06, 0x60, 0x00, 0x00, 0x00, 0x30, 0x3E, 0x66, 0x60, 0x06, 0x66, 0x00, 
  0x60, 0x60, 0x60, 0x30, 0x06, 0x60, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0xE6, 
  0x61, 0x1E, 0xC7, 0x3F, 0x70, 0xE0, 0x3F, 0x3C, 0xFE, 0xC3, 0x3F, 0x00, 
  0x00, 0x3C, 0x7E, 0xE6, 0x61, 0x1E, 0xC7, 0x3F, 0x70, 0xE0, 0x3F, 0x3C, 
  0xFE, 0xC3, 0x3F, 0x00, 0x00, 0x3C, 0xDE, 0xE7, 0x61, 0x1E, 0x07, 0x70, 
  0x70, 0xE0, 0x1D, 0x3C, 0x1E, 0x00, 0x70, 0x00, 0x00, 0x3C, 0x1E, 0xE7, 
  0x61, 0x1E, 0x07, 0x70, 0x70, 0xE0, 0x31, 0x3C, 0x1E, 0x00, 0x70, 0x00, 
  0x00, 0x3C, 0x1E, 0xE6, 0x61, 0x1E, 0x07, 0x70, 0x70, 0xE0, 0x61, 0x3C, 
  0x1E, 0x00, 0x70, 0x00, 0x00, 0x3C, 0x1E, 0xE6, 0x61, 0x1E, 0x07, 0x70, 
  0x70, 0xE0, 0x61, 0x3C, 0x1E, 0x00, 0x70, 0x00, 0x00, 0x7F, 0x1E, 0xE6, 
  0x3F, 0xFC, 0xE3, 0x3F, 0x70, 0xE0, 0x61, 0x7E, 0xFE, 0xE7, 0x3F, 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, 0x00, 
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
  0x00, 0x00, 0x00, 0x00, 
};

const uint8_t frame2[] PROGMEM = {
  0xFF,0xFF, // 11111111 11111111 00
  0xFF,0xFF, // 11111111 11111111 01
  0xFE,0x7F, // 11111110 01111111 02
  0xF8,0x1F, // 11111000 00011111 03
  0xF3,0xCF, // 11110011 11001111 04 
  0xE7,0xE7, // 11100111 11100111 05
  0xEF,0xF3, // 11101111 11110111 06
  0xCF,0xF3, // 11001111 11110011 07
  0xC0,0x03, // 11000000 00000011 08
  0xC0,0x03, // 11000000 00000011 09
  0xC1,0x83, // 11000001 10000011 10
  0xC1,0x83, // 11000001 10000011 11
  0xC1,0x83, // 11000001 10000011 12
  0xC1,0x83, // 11000001 10000011 13
  0xC0,0x03, // 11000000 00000011 14
  0xC0,0x03, // 11000000 00000011 15
  0xFF,0xFF, // 11111111 11111111 16
  0xFF,0xFF, // 11111111 11111111 17
  }; 

void setup() {  
  sUART.begin(9600);
  pinMode(relayH, OUTPUT);   
  relayHandlerH(4);             // get the working state
  pinMode(ledH, OUTPUT);
  pinMode(relayA, OUTPUT);
  relayHandlerA(4);
  pinMode(ledA, OUTPUT);
  pinMode(relayL, OUTPUT);
  relayHandlerL(4);
  pinMode(ledL, OUTPUT);
  pinMode(buzzer, OUTPUT);
  sensors.begin();              // start DS18B20
  tTargetHandler(EEPROM.read(addr[0]));  // Read the previously stored tTarget value from the current address of the EEPROM at startup
                                         // First the tempMeas() will be called by tTargetHandler() by getting the appropriate tTarget
                                         // value readed from the EEPROM. Later the temprMeas() will do it.
  lockSystem(EEPROM.read(addr[2]));
  costCalc(0);
  startup = boolTerm;
}

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

void costCalc(bool op) {  // 0 = read, 1 = write
  if (!op) {
    costMinutes = EEPROM.get(addr[3], costMinutes);
    delay(20);
    cost = costMinutes * costCoeff;
  }
  else {
    EEPROM.put(addr[3], (costMinutes + minutes));
    delay(80);
  }  
}

void lockSystem(bool op) {
  bool prevState = locked;
  EEPROM.write(addr[2], op);
  delay(40);
  locked = EEPROM.read(addr[2]);
  delay(20);
  if (locked) {
    startup = 1;
    windowAlrt = boolTerm;
    relayHandlerH(0);
    relayHandlerA(0);
    relayHandlerL(0);
    startup = boolTerm;
  }
  if (locked != prevState) {
    sTX(12);
  }
}

// ---- System Management
void wdRst() {
  asm volatile ("jmp 0");
//wdt_disable();      // the WDT method works only on boards with new bootloader
//wdt_enable(presc);  // start wd with the prescaller
//while(1) {          // the prescaller time has to expire 
//}    
}

void btnReadings() {                 // --------- btn readings
  if (locked) {
    return;
  }
  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 <= 853){    // btn Airing
    if (windowAlrt) {                          // if the system is in Window Alert mode, disable it
      windowAlrt = boolTerm;                                                        
      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 >= 855 && btnVal <= 862) {   // inc & dec btns at the same time will change 
    delay(100);                                // the unit of temperature measurement.
    tTargetHandler(2);                         // flip measurement unit and convert the tempr target value 
  }
}

void btRecv() {           // ------------- Receive Serial Data  
  while (sUART.available() > 0) { // if data is available to read
    for (byte i = 0; i < 2; i++) {
      RX[i] = sUART.read();
    }
  }  
  int iRX[2]; 
  for (byte i = 0; i < 2; i++) {
    iRX[i] = RX[i] - '0';
  }
  if (iRX[0] * 10 + iRX[1] == 98) {
    lockSystem(0);
  }
  if (!locked) {
    switch (RX[0]) {       // ------------- 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':
        tTargetHandler(21);                           
        buzz(3, 1);
        break; 
      case 'E':
      case 'e':
        tTargetHandler(19);                           
        buzz(3, 1);
        break;
      case 'F':
      case 'f':
        tTargetHandler(14);                          
        buzz(3, 1);
        break;
      case 'R':             // call for an overview report about controlled devices
      case 'r':
        if (windowAlrt) {
          windowAlrt = boolTerm;                                                        
          buzz(4, 3);                                                            
          relayHandlerA(3);
        }
        else {
          sTX(8);
          sTX(2);
          buzz(5, 2);
        }  
        break;
      case 'W':             // disable Window Alert state
      case 'w':
        windowAlrt = boolTerm;                                                        
        buzz(4, 3);                                                            
        relayHandlerA(3);
        break;
      case '+':
        tTargetHandler(0);
        break;
      case '-':
        tTargetHandler(1);
        break;
      case 'l':
        lockSystem(1);
        break;  
      case 'X':            // accept a request and send back a report 
      case 'x':
        onlink = 1; 
        break; 
      case 'Y':  
      case 'y':
        sTX(16);
        break;
    }                             
                   // -------------------------------------- Accept COMBINED NUMERIC Control Codes     
                   // In this case a two-digit numeric control code arrives in char format, from an Android
                   // bluetooth serial app for instance. After a char to integer conversion
                   // (only if the first char is '1', '2', '5', '6', '7') a merge-process will follow, and the
                   // system of conditions and statements will make a decision and execute it.
                   //
                   // -------------------------- System Control Codes:
                   //
                   //    94: query for natural gas cost value
                   //    95: erase the cost value
                   //    96: lock the Thermostat Unit - arrives from the Central Unit (RFID)
                   //    97: unlock the Thermostat Unit - arrives from the Central Unit (RFID)
                   //    98: query for report of the devices (heater, airing, lights), and target temperature
                   //    99: sent by the Central Unit, activates the Onlink mode on the Thermostat Unit
                   //
                   // -------------------------- Device Control Codes:
                   //                  First = device code, Second = operator code
                   //
                   // 30, 31, 32 turns the heater: 30=off, 31=on, 32=flip logical state (on -> off / off -> on)
                   //                                            One Time Heating (15 mins) timed heater program
                   // 40, 41, 42 will do the same to the airing ventilator
                   // 80, 81, 82 handles the kitchen lights as above
                   //
                   // 90, 91, 92 desklights (on the Central Unit only)
                   // 93         media player flip boolean state (on the Central Unit only)
                   //
                   // -------------------------- Classified Operator Codes:
                   //             X3, X4 are classified, used only for function calls by inner program sequences
                   //
                   // -------------------------- Target Temperature:
                   // 10 - 24 as Celsius, or 50 - 76 as Fahrenheit values will be accepted and stored in EEPROM as 
                   // target temperature for the thermostat function. If the measurement unit changes, the system 
                   // converts all the previous temperature values (used for trend analisys, and summary statistics),
                   // and calls tempMeas() to make a new measurement in the actual unit.                
    switch (iRX[0]) {                                                      
      case 3:                                 
        relayHandlerH(iRX[1]);                  
        break;                                
      case 4:                                 
        relayHandlerA(iRX[1]);                  
        break;                                
      case 8: 
        if ((iRX[1] >= 0) && (iRX[1] <= 4)) {                                
          relayHandlerL(iRX[1]); 
        }                   
        break;                                
      case 9:
        switch (iRX[1]) {
          case 4:
            sTX(16);
            break;
          case 5: 
            costMinutes = intTerm;                  
            costCalc(1);                     
            sTX(16);
            break; 
          case 6:
            sTX(8);                 
            sTX(2);
            break;
          case 7:
            lockSystem(1);
            break;    
        }
      default:
        if (((iRX[0] * 10 + iRX[1] <= 24) && (iRX[0] * 10 + iRX[1] >= 10)) || ((iRX[0] * 10 + iRX[1] >= 50) && (iRX[0] * 10 + iRX[1] <= 76))) {
          tTargetHandler(iRX[0] * 10 + iRX[1]);      
          buzz(3, 1);                                   
        }  
        if (iRX[0] * 10 + iRX[1] == 25) {
          buzz(3, 1);
          wdRst();
        }
        break;                                          
    }                                                
  } 
  if (iRX[0] * 10 + iRX[1] == 97) {
    lockSystem(1);
  }                         
  if (iRX[0] * 10 + iRX[1] == 99) {
    onlink = 1;
  }
  for (byte i = 0; i < 2; i++) {
    RX[i] = charTerm;
  }
}

void relayHandlerL(byte lOperator) {  // lighting handler sequence
                                      // operators are: 0=off, 1=on, 2=flip the state, 
                                      // 4=fill/refill the lighting state string var.
  if ((measError) && ((lOperator == 1) || (lOperator == 2))) {
    sTX(4);
    return;                                    
  }
  if ((lOperator == 2) || (lOperator == 0) && (lState) || (lOperator == 1) && (!lState)) {
    lState = !lState;
    digitalWrite(relayL, lState);
    buzz(2, 1);
  }  
  if (lOperator >= 0) {               // fill up the working state char with the proper state indicator string
    if (lState) {
      lightingState = state_str[0];
    }
    else  {
      lightingState = state_str[1];
    }
    if ((!startup) && (!measError)) {
      sTX(7);
    }
  }
}

void relayHandlerA(byte aOperator) {   // airing handler sequence
                                       // operators are: 0=off, 1=on, 2=flip the state, 
  if ((measError) && ((aOperator == 1) || (aOperator == 2))) {  // operators are: 0=off, 1=on, 2=flip the state, 
    sTX(4);                                                     // 3=called by temprMeas() funct., 4=fill/refill the airing state char var.
    return;                                     
  }
  aState = digitalRead(relayA);        
  if (!windowAlrt) {
    if ((aOperator == 2) || (aState) && (aOperator == 0) || (!aState) && (aOperator == 1)) {
      aState = !aState;
      digitalWrite(relayA, aState);
      aStateByCmd = digitalRead(relayA);
      buzz(2, 1);
    } 
  } 
  if (aOperator == 3) {                // called by the temprMeas() function, 'windowAlrt' ended or started
    if ((!aState) && (windowAlrt) || (aState) && (!windowAlrt) && (!aStateByCmd)) {
      digitalWrite(relayA, windowAlrt);
    }
  }
  aState = digitalRead(relayA);
  if (aOperator >= 0) {
    if (aState) {
      if (windowAlrt) {
        airingState = state_str[2];
      }
      else  {
        airingState = state_str[0];
      }
    }
    else {
      airingState = state_str[1];
    }
  }
  if ((!startup) && (!measError)) {
    sTX(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 ((measError) && ((hOperator == 1) || (hOperator == 2))) {
    sTX(4);
    return;                                    
  }   
  hStatePrev = hState;                                   
  if ((!hThermostat) && (!windowAlrt) && (!measError)) {     // turn on/off the One Time Heating (15 mins) timed mode
    if ((hOperator == 2) || (hOperator == 1) && (!hState) || (!hOperator) && (hState)) {
      buzz(2, 1);
      hState = !hState;
      sftyTmrEnded = boolTerm;
      timer0 = 0;   
      digitalWrite(relayH, hState);
    }
  }
  if (windowAlrt) {
    sTX(3);
  }
  if (hOperator == 3) {               // this function called by the temprMeas() function (op 3) 
                                      // in order to examine windowAlrt & measError booleans extreme tempr values                                                                                                          
    if ((windowAlrt) && (hState)) {            // a window is open and the heater is running
      digitalWrite(relayH, 0);
      buzz(5, 3);
    }
    if ((!windowAlrt) && (!measError)) {
      if ((hThermostat) || (!hThermostat) && (hState) && (sftyTmrEnded)) { 
        digitalWrite(relayH, hThermostat);     // proceed the command of the thermostat routine
      }
    }
  }
  hState = digitalRead(relayH);
  if (hOperator >= 0) {
    if (hState) {
      if (hThermostat) {
        heaterState = state_str[2];
      }
      else  {
        heaterState = state_str[0];
      }
    }
    else {
      heaterState = state_str[1];
    }
  } 
//                                                       <------------------------------------------------------------------------------------------------------------------------------------>      
//                      <-------------------------->     <----------------------------->    <---------------------------->    <------------------------------------------>    <-------------->          
  if ((!measError) && (((!windowAlrt) && (!startup)) && (((hOperator == 0) && (!hState)) || ((hOperator == 1) && (hState)) || ((hOperator == 2) && (hState == hStatePrev)) || (hOperator == 4))) || (hState != hStatePrev)) {
    sTX(5); 
  }  
  if (hState) {
     minutes++;
  }
  if (hState != hStatePrev) {
    if (hState) {
      minutes = intTerm;
      temprStart = tempr;
    }
    else {
      costCalc(1);
      sTX(14);
      sTX(16);
      hPeriodFin = 1;
    }
  }
}

void safetyTmr () {        // timer for the One Time Heating (15 mins) timed mode
  if (locked) {
    return;
  }
  if ((hState) && (!sftyTmrEnded) && (timer0 > sftyTmrInterval) && (!hThermostat)) {
    sftyTmrEnded = 1;
    relayHandlerH(0);
    for (byte i = 1; i < 5; i++) {
      buzz(i, 2);
    }
  }
}

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

void temprMeas() {          // ----------- Tempr Measurement & Comparison Sequence
  temprPrev = tempr;                       // save the value for next comparison
  sensors.requestTemperatures();           // update sensor readings
  if (celsius) {
    tempr = sensors.getTempCByIndex(0);    // read remperature
  }
  else {
    tempr = sensors.getTempFByIndex(0); 
  }
  if (((celsius) && ((tempr >= 40) || (tempr <= 0))) ||  ((!celsius) && ((tempr >= 104) || (tempr <= 32)))) { 
    if (!errMsgSentBySys) {             // -127, -196.60 are HW errors, +85 is tipically SW error, but
      sTX(4);                           // can be fire, or a broken window
    }
    errMsgSentBySys = 1;
    hThermostat = boolTerm;
    if (hState) {
      relayHandlerH(0);                      
    }
    if (aState) {
      relayHandlerA(0);                      
    }
    if (lState) {
      relayHandlerL(0);
    }  
    measError = 1;
    for (byte i = 1; i < 10; i++) {        
      buzz(4, 1);                          
      delay(50);
    } 
  }                                                       
  else {
    measError = boolTerm;
    errMsgSentBySys = boolTerm;
  }
  if (!measError) {         // --------------- Start of Temperature Analysis Sequence
                                            // Frequent, short-term switching of the heater gas boiler would cut short its lifetime, the
                                            // 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
                                            // warmth from the freshly heated-up air, so the above described effect would more stronger.
    if (tempr <= hCorrRef[celsius][0]) {                    
      heatCorrVal = hCorrVal[celsius][0];                  
    }                                     
    if ((tempr > hCorrRef[celsius][0]) && (tempr < hCorrRef[celsius][1])) {   
      heatCorrVal = hCorrVal[celsius][1];
    }
    if (tempr >= hCorrRef[celsius][1]) {
      heatCorrVal = hCorrVal[celsius][2];
    }
    if (!sysChanged) {                       // If the meas system has changed recently, dont start the temp analisys for the first time 
      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)) {  
        hThermostat = boolTerm;
      }      
      if ((!windowAlrt) && (temprPrev - tempr >= wAlrt[celsius][0]) && (tempr <= wAlrt[celsius][2])) {       
        windowAlrt = 1;                      // in a measurement cycle and in heating season the temperature
        sftyTmrEnded = 1;                    // drops, it will evaluate as a window is open
        for (byte i = 1; i < 5; i++) {
          buzz(4, 1);
          delay(50);
        }
        relayHandlerA(3);                    // call airing function (opcode = 3), to help refresh the air
      }
      if ((windowAlrt) && (temprPrev - tempr <= wAlrt[celsius][1])) {
        windowAlrt = boolTerm;               // the tempr. falling is over, the air became warmer 
        buzz(4, 3);                          // due to the heat capacity of the environment, 
        relayHandlerA(3);                    // so switch back to normal mode
      }
      relayHandlerH(3);                      // the function will examine caller param(3) & windowAlrt & measError booleans
    }                                        // ---- end of sysChanged section                                                      
    if (!windowAlrt) {
      sTX(1);
    }
  }
  sysChanged = boolTerm;
}

void tTargetHandler (byte set) {             // -------------- Start of Target Temperature handler routine
  hPeriodFin = boolTerm;
  if (set == 0) {                
    if (((celsius) && (tTarget < 24)) || ((!celsius) && (tTarget < 76))) {         
      tTarget++ ;                                         // ------------------ Set of Operator Codes -------------------------
      tTargetEEPROM();                                    // 0 : INCR 
      buzz(3, 1);                                         // 1 : DECR tTarget until it reaches the max / min limit
      }                                                   // 2 : FLIP mesurement unit, and converts the stored tTarget
    else {                                                //     value into the appropriate unit. This function also converts
      buzz(2, 3);                                         //     temprPrev and temprStart values. Called by btnReadings()
    }                                                     //     if the INCR & DECR buttons has been pressed at the same time.
    tTargetEEPROM();                                      // 10..24 & 50..76: intervals received from Bluetooth, adding the
  }                                                       //     tTarget value, and the examination of tTargetHandler()
  if (set == 1) {                                         //     will declare the unit of the measurement.
    if (((celsius) && (tTarget > 10)) || ((!celsius) && (tTarget > 50))) {
      tTarget-- ;
      tTargetEEPROM();
      buzz(3, 1); 
    }
    else {
      buzz(2, 3);
    }
    tTargetEEPROM();
  }
  if (set == 2) {
    if (celsius) {
      tTarget = ((1.8 * tTarget) + 32), 0;
      temprPrev = ((1.8 * temprPrev) + 32), 2;
      if (hState) {
        temprStart = ((1.8 * temprStart) + 32), 2;
      }
    }
    else {
      tTarget = ((5 * (tTarget - 32)) / 9), 0;
      temprPrev = ((5 * (temprPrev - 32)) / 9), 2;
      if (hState) {
        temprStart = ((5 * (temprStart - 32)) / 9), 2;
      }
    }
    sysChanged = 1;
    celsius = !celsius;
    temprMeas();          // after set, call the EEPROM handler function, and write the tTarget value to the appropriate byte of the EEPROM
    tTargetEEPROM();      // target tempr has changed, call the temp meas function, don't wait for the cyclic timer
  }
  celsius = EEPROM.read(addr[1]);
  if (((set >= 10) && (set <= 24)) || ((set >= 50) && (set <= 76))) {
    tTarget = set;
    if ((tTarget <= 24) && (!celsius)) {
      sysChanged = 1;
      celsius = 1;
      if (hState) {
        temprStart = (5 * (temprStart - 32)) / 9;
      }
      temprPrev = (5 * (temprPrev - 32)) / 9;
      sTX(10);
    }
    if ((tTarget >= 50) && (celsius)) {
      sysChanged = 1;
      celsius = 0;
      if (hState) {
        temprStart = (1.8 * temprStart) + 32;
      }
      temprPrev = (1.8 * temprPrev) + 32;
      sTX(9);
    }
    tTargetEEPROM();
    temprMeas();
  }
}

void tTargetEEPROM() {
  EEPROM.write(addr[0], tTarget);  // after incr/decr/set, write the tTarget value to the appropriate byte of the EEPROM
  delay(40);
  EEPROM.write(addr[1], celsius); 
  delay(40);
  sTX(2);
}

void draw(void) {               
  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) {
    u8g.setPrintPos( 0, 14);
    u8g.print(funct_str[0]);
    u8g.setPrintPos(84, 14);
    u8g.print(heaterState);
  }
  else {
    u8g.setPrintPos( 0, 14);
    u8g.print(funct_str[3]);
  }
  if (!locked) {
    u8g.setPrintPos( 0, 28);
    u8g.print(funct_str[1]);
    u8g.setPrintPos(88, 28);
    u8g.print(airingState);
    u8g.setPrintPos( 0, 42);
    u8g.print(funct_str[2]);
    u8g.setPrintPos(95, 42);
    u8g.print(lightingState);
  }
  else {
    sysLckWriteOut();
  }
  if ((!hState) && (!aState) && (!lState)) {
    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) {
        u8g.setPrintPos( 4, 64);
        u8g.print(funct_str[4]);
      }
      else {
        if (hPeriodFin) {
          byte y = 48;
          u8g.setPrintPos(4, y);
          u8g.print(minutes);
          u8g.setPrintPos(26, y);
          u8g.print("min & ");
          if (tempr > temprStart) {
            u8g.setPrintPos(68, y);
            u8g.print("+");
          }
          u8g.setPrintPos(80, y);
          u8g.print(tempr - temprStart);
          if (celsius) {
            u8g.setPrintPos(114, y);
            u8g.print(char(176));
            u8g.setPrintPos(120, y);
            u8g.print("C");
          }
          else {
            u8g.setPrintPos(114, y);
            u8g.print("F"); 
          }
          costCalc(0);
          u8g.setPrintPos(  8, y + 16);
          u8g.print(funct_str[20]);
          u8g.setPrintPos( 62, y + 16);
          u8g.print(cost, 2);
          u8g.setPrintPos(104, y + 16);
          u8g.print(funct_str[21]);
        }
        else {
          if (locked) {
          sysLckWriteOut();
          }
          else {
            u8g.setPrintPos(33, 52);
            u8g.print(funct_str[5]);
            u8g.setPrintPos( 8, 64);
            u8g.print(funct_str[6]);
          }
        }
      }
    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);
  char buftTarget[9];                   
  sprintf (buftTarget, "%d", tTarget);  // int to char conversion
  u8g.drawStr(tX, tY, buftTarget);
  u8g.setPrintPos(tX + 18, tY);
  u8g.print(funct_str[9]);              // tX + 18 
  u8g.setPrintPos(tX + 50, tY);         // tX + 32
  u8g.print(tempr);                     // printing temp. 
  if (celsius) {
    u8g.print(char(176)); 
    u8g.print("C");
  }
  else {
    u8g.print("F");
  }
}

void sysLckWriteOut() {
  u8g.drawBitmapP(0, 22, 2, 18, frame2);
  u8g.drawHLine( 16, 22, 112);
  u8g.drawHLine( 16, 39, 112); 
  u8g.drawVLine(127, 22,  17); 
  u8g.setPrintPos(19, 36);     
  u8g.print(funct_str[15]);
  u8g.setPrintPos(71, 36);
  u8g.print(funct_str[17]);
}

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

void ledHandler() {                       // the brightHeat of a led is low, if the indicated device is off, and high, if its on
  if (!locked) {
    if (aState) {
      analogWrite(ledA, bright[2]); 
    }
    else {
      analogWrite(ledA, bright[1]); 
    }
    if (lState)  {
      analogWrite(ledL, bright[2]); 
    }
    else {
      analogWrite(ledL, bright[1]); 
    }
    if (hState) {
      if (!hThermostat) {
        ledBlnk() ;                       // the heater led blinks when the One Time Heating (15 mins) timed mode is activated,
      }
      else {
        brightHeat = bright[2] ;          // and constant bright, if the thermostat routine is active
      }
    }  
    else {
      brightHeat = bright[1] ; 
    }
    analogWrite(ledH, brightHeat);
  }
  else {
    analogWrite(ledL, bright[0]);
    analogWrite(ledA, bright[0]);
    analogWrite(ledH, bright[0]);  
  }
}

...

This file has been truncated, please download it to see its full contents.

Credits

Gyula Ősi

Gyula Ősi

4 projects • 33 followers

Comments