Components and supplies
SSD1306 OLED Display
Temperature Sensor: LM35dz
Arduino Nano
HC-05 Bluetooth Module
Apps and platforms
Arduino IDE 2.0 (beta)
Project description
Code
Thermostat Celsius - Gyula Ősi
cpp
The program code explains itself, useful for begin
1// Celsius version v1.1 2// Program code of an intelligent Arduino smarthome thermostat solution, 3// based on Arduino Nano (or higher) board, DS18B20 thermo sensor, HC-05 Bluetooth adapter, I2C 128X64 bicolor OLED display. 4// The system can be controlled by buttons and Android smartphone via bluetooth. 5// 6// It handles the HEATER gas boiler, the bathroom AIRING ventilator and the kitchen LIGHTING - swithed with relays. 7// The heater has two working ways. 1: One Time Heating (15 mins) timed mode, 2: Thermostat mode (higher priority). The adjusted target tempr. 8// stored in EEPROM. The program detects hardware errors and window opening - in these cases the heater stops and/or will not start. 9// 10// Designed and programmed by Gyula Osi. 11// All rights reserved. 12// ------------------------------------------------------------------------------------------------------------------------------------ 13 14// ---- Display I2C Bus, SDA(TX) -> A4, SCL(RX) -> A5 15#include "U8glib.h" 16U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE); // display constructor 17byte frame = 0; // start logo pointer 18 19// ---- Ports and related declarations 20const byte buzzer = 9; // buzzer to D9 21int btnVal; // stores analog values from buttons 22const byte relayA = 11; // airing 23bool aState = 0; 24bool aStateByCmd; // if "window alert" is gone, the airing control goes back to the original state 25const byte relayL = 13; // lighting 26bool lState = 0; 27const byte relayH = 10; // heater 28const byte ledH = 6; // PWM ports allow output level adjustment used to change brightness 29const byte ledA = 5; 30const byte ledL = 3; 31const byte bright[3] = {0, 10, 100}; 32byte brightHeat = bright[2]; 33#define ledInterval 1000 // heater led blinking interval 34unsigned long prev = 0; 35 36// ---- Strings for Display and Serial Reports 37#define STATE_ITEMS 3 // device state indicator strings for outputs 38// i -> 0 1 2 39const String state_str[STATE_ITEMS] = {"on.", "off.", "auto."}; 40String heaterState; 41String airingState; 42String lightingState; 43#define FUNCT_ITEMS 11 44// i -> 0 1 2 3 4 5 6 7 8 9 10 45String funct_str[FUNCT_ITEMS] = {"Heater is ", "Airing is ", "Lighting is ", "Window Alert!", "Hardware Error!", "Hit a Key >>", "or send a Code!", "Target tempr = ", "Temperature = ", " * ", " -"}; 46 47// ---- Temperature Measurement and Heater Related Features 48#include <elapsedMillis.h> 49elapsedMillis timer0; // 8-bit, PWM timer, used by function elapsedMillis() 50#define sftyTmrInterval 15 * 60000 // one Time Heating (15 mins) timed mode interval [ms] 51bool sftyTmrEnded; // boolean startup, the timer0 has ended 52#include <EEPROM.h> 53byte tTarget; // adjusted target tempr 54const int addr = 0; // the current address of the tTarget variable in the EEPROM memory 55bool hState = 0; // heater boolean state 56bool hThermostat = 0; // thermostat boolean state 57#include "OneWire.h" 58#include "DallasTemperature.h" 59#define DS18B20 2 // setup the OneWire bus on D2 60OneWire temprWire(DS18B20); // setup DS18B20 to work on the OneWire bus 61DallasTemperature sensors(&temprWire); 62float tempr; // measured value 63float temprPrev; // copy of measured value for trend analysis 64bool windowAlrt = 0; // specified degree of tempr drop 65bool measError = 0; // measured tempr value is out of the range specified as normal 66const long temprInterval = 60000; // cyclic tempr measurement interval [ms] 67unsigned long temprTmrPrev = 0; // the elapsed will be the previous when temprMeas() called 68float heatCorrVal; // declares the degree of overheating and cooling back, see tempMeas() function 69 70// ---- Configuration of Serial Communication on virtual RXD/TXD 71#include <SoftwareSerial.h> // SW serial RX & TX pins for HC-05 72const int RX1 = 8; 73const int TX1 = 4; 74SoftwareSerial sUART(RX1,TX1); 75char RX[2]; // store received serial data 76bool errMsgSentBySys = 0; 77bool startup = 1; // keep avoid a duplicate BT report at startup 78 79const uint8_t frame1[] U8G_PROGMEM = { // XBM map 80 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 81 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 82 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 83 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 84 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 85 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 86 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0xFE, 0xFF, 87 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFC, 0xFF, 0x7F, 0xF0, 88 0x3F, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 89 0xFC, 0xFF, 0x7F, 0xF0, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 90 0xFF, 0xFF, 0x1F, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xFF, 91 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 92 0x8F, 0xFF, 0x1F, 0x7F, 0x8C, 0x3F, 0x1E, 0xFF, 0x00, 0xFE, 0x1F, 0xFF, 93 0xF1, 0x00, 0x18, 0xC0, 0x8F, 0xFF, 0x1F, 0x7F, 0x8C, 0x3F, 0x1E, 0xFF, 94 0x00, 0xFE, 0x1F, 0xFF, 0xF1, 0x00, 0x18, 0xC0, 0x8F, 0xFF, 0x1F, 0x1F, 95 0x0C, 0x3E, 0x1E, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0x31, 0xFE, 0x7F, 0xFC, 96 0x8F, 0xFF, 0x1F, 0x1F, 0x0C, 0x3E, 0x1E, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 97 0x31, 0xFE, 0x7F, 0xFC, 0x0F, 0x0E, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0xFC, 98 0x00, 0xF8, 0x1F, 0x7C, 0x30, 0xFE, 0x7F, 0xF0, 0x0F, 0x0E, 0x18, 0x1F, 99 0x0C, 0x3E, 0x1E, 0xFC, 0x00, 0xF8, 0x1F, 0x7C, 0x30, 0xFE, 0x7F, 0xF0, 100 0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C, 101 0xF0, 0x00, 0x7E, 0xF0, 0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C, 102 0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x00, 0x7E, 0xF0, 0x0F, 0xFE, 0x18, 0x1F, 103 0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x3F, 0x78, 0xF0, 104 0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C, 105 0xF0, 0x3F, 0x78, 0xF0, 0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C, 106 0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x3F, 0x78, 0xF0, 0x0F, 0xFE, 0x18, 0x1F, 107 0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x3F, 0x78, 0xF0, 108 0x3F, 0x00, 0x7E, 0x00, 0x3C, 0x80, 0x07, 0xF0, 0x00, 0xF8, 0x7F, 0x00, 109 0x3C, 0x00, 0x1E, 0xC0, 0x3F, 0x00, 0x7E, 0x00, 0x3C, 0x80, 0x07, 0xF0, 110 0x00, 0xF8, 0x7F, 0x00, 0x3C, 0x00, 0x1E, 0xC0, 0xFF, 0xFF, 0xFF, 0x1F, 111 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 112 0xFF, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 113 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 114 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 115 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 116 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 117 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 118 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 119 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 120 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 121 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 122 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 123 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 124 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 125 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 126 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 127 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 128 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 140 0x00, 0x7E, 0x06, 0xE6, 0x3F, 0x06, 0xC6, 0x7F, 0xFE, 0xE7, 0x3F, 0x7E, 141 0xFE, 0xC7, 0x7F, 0x00, 0x00, 0x30, 0x06, 0x66, 0x60, 0x06, 0x66, 0x00, 142 0x60, 0x60, 0x60, 0x30, 0x06, 0x60, 0x00, 0x00, 0x00, 0x30, 0x06, 0x66, 143 0x60, 0x06, 0x66, 0x00, 0x60, 0x60, 0x60, 0x30, 0x06, 0x60, 0x00, 0x00, 144 0x00, 0x30, 0x1E, 0x66, 0x60, 0x06, 0x66, 0x00, 0x60, 0x60, 0x60, 0x30, 145 0x06, 0x60, 0x00, 0x00, 0x00, 0x30, 0x3E, 0x66, 0x60, 0x06, 0x66, 0x00, 146 0x60, 0x60, 0x60, 0x30, 0x06, 0x60, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0xE6, 147 0x61, 0x1E, 0xC7, 0x3F, 0x70, 0xE0, 0x3F, 0x3C, 0xFE, 0xC3, 0x3F, 0x00, 148 0x00, 0x3C, 0x7E, 0xE6, 0x61, 0x1E, 0xC7, 0x3F, 0x70, 0xE0, 0x3F, 0x3C, 149 0xFE, 0xC3, 0x3F, 0x00, 0x00, 0x3C, 0xDE, 0xE7, 0x61, 0x1E, 0x07, 0x70, 150 0x70, 0xE0, 0x1D, 0x3C, 0x1E, 0x00, 0x70, 0x00, 0x00, 0x3C, 0x1E, 0xE7, 151 0x61, 0x1E, 0x07, 0x70, 0x70, 0xE0, 0x31, 0x3C, 0x1E, 0x00, 0x70, 0x00, 152 0x00, 0x3C, 0x1E, 0xE6, 0x61, 0x1E, 0x07, 0x70, 0x70, 0xE0, 0x61, 0x3C, 153 0x1E, 0x00, 0x70, 0x00, 0x00, 0x3C, 0x1E, 0xE6, 0x61, 0x1E, 0x07, 0x70, 154 0x70, 0xE0, 0x61, 0x3C, 0x1E, 0x00, 0x70, 0x00, 0x00, 0x7F, 0x1E, 0xE6, 155 0x3F, 0xFC, 0xE3, 0x3F, 0x70, 0xE0, 0x61, 0x7E, 0xFE, 0xE7, 0x3F, 0x00, 156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 165 0x00, 0x00, 0x00, 0x00, 166}; 167 168void setup() { 169 sUART.begin(9600); 170 pinMode(relayH, OUTPUT); 171 relayHandlerH(4); // get the working state 172 pinMode(ledH, OUTPUT); 173 pinMode(relayA, OUTPUT); 174 relayHandlerA(4); 175 pinMode(ledA, OUTPUT); 176 pinMode(relayL, OUTPUT); 177 relayHandlerL(4); 178 pinMode(ledL, OUTPUT); 179 pinMode(buzzer, OUTPUT); 180 sensors.begin(); // start DS18B20 181 temprMeas(); // do not wait for the meas.timer, call the function once at startup 182 tTarget = EEPROM.read(addr); // read the previously stored tTarget value from the current address of the EEPROM at startup 183 startup = 0; 184 if (!measError) { 185 sTX(8); // call for instant report of working states after startup 186 } 187 else { 188 sTX(2); 189 } 190} 191 192void loop() { 193 temprTimer(); 194 ledHandler(); 195 btnReadings(); 196 sRX(); 197 safetyTmr(); 198 199 u8g.firstPage(); // scr loop 200 do { 201 draw(); 202 } while( u8g.nextPage() ); 203 if (frame == 0) { 204 delay(3000); 205 frame = 1; 206 clrScr(); 207 } 208} 209 210void btnReadings() { // --------- Btn Readings 211 btnVal = analogRead(A0); // read analog val from A0 212 if (btnVal >= 510 && btnVal <= 516) { // btn Lighting 213 delay(100); // btn debounce 214 buzz(3, 1); 215 relayHandlerL(2); // call proper function with logical state flip opcode as parameter 216 } 217 else if (btnVal >= 849 && btnVal <= 855){ // btn Airing 218 if (windowAlrt == 1) { // if the system is in Window Alert mode, disable it 219 windowAlrt = 0; 220 buzz(4, 3); 221 relayHandlerA(3); 222 } 223 else { // else turn on/off the airing ventilator 224 delay(100); 225 buzz(3, 1); 226 relayHandlerA(2); 227 } 228 } 229 else if (btnVal >= 927 && btnVal <= 933){ // btn One Time Heating (15 mins) timed mode 230 delay(100); 231 buzz(3, 1); 232 relayHandlerH(2); 233 } 234 else if (btnVal >= 767 && btnVal <= 777) { // btn decrease tTarget 235 delay(100); 236 tTargetHandler(0); 237 } 238 else if (btnVal >= 687 && btnVal <= 697) { // btn increase tTarget 239 delay(100); 240 tTargetHandler(1); 241 } 242 else if (btnVal >= 856 && btnVal <= 862) { // inc & dec btns at the same time 243 tTarget = 14; // <==== initial value - press these buttons at the very first powerup! 244 } 245} 246 247void sRX() { // ------------- Receive Serial Data 248 while (sUART.available() > 0) { // if data is available to read 249 for (byte i = 0; i < 2; i++) { 250 RX[i] = sUART.read(); 251 } 252 } 253 int iRX[2]; 254 for (byte i = 0; i < 2; i++) { 255 iRX[i] = RX[i] - '0'; 256 } 257 258 switch (RX[0]) { // ------------ accept SINGLE ALPHABETICAL control codes 259 case 'A': 260 relayHandlerH(1); // 1 = on 261 break; 262 case 'a': 263 relayHandlerH(0); // 0 = off 264 break; // Received serial data can be a single alphabetical letter from "Arduino 265 case 'B': // Bluetooth Control Device" Android app. If a proper alphabetical 266 relayHandlerA(1); // character arrives, the program code will not wait for the second one, 267 break; // but calls the applicable function with a proper operation code. 268 case 'b': // Cases of combined numeric data can be seen below. 269 relayHandlerA(0); 270 break; 271 case 'C': 272 relayHandlerL(1); 273 break; 274 case 'c': 275 relayHandlerL(0); 276 break; 277 case 'D': 278 case 'd': 279 tTarget = 21; 280 tTargetEEPROM(); 281 buzz(3, 1); 282 break; 283 case 'E': 284 case 'e': 285 tTarget = 19; 286 tTargetEEPROM(); 287 buzz(3, 1); 288 break; 289 case 'F': 290 case 'f': 291 tTarget = 14; 292 tTargetEEPROM(); 293 buzz(3, 1); 294 break; 295 case 'R': // call for an overview report about controlled devices 296 case 'r': 297 sTX(8); 298 break; 299 case 'W': // disable Window Alert state 300 case 'w': 301 windowAlrt = 0; 302 buzz(4, 3); 303 relayHandlerA(3); 304 break; 305 } 306 // ----------------------- accept COMBINED NUMERIC control codes 307 // In this case a two-digit numeric control code arrives in char format, 308 // from an Android bluetooth serial app for instance. After a char to integer 309 // conversion (only if the first char is '1' or '2') a merge-process will follow, 310 // and the system of conditions and statements will make a decision and execute it. 311 // Appropriate numeric codes are: 312 // 313 // ---------------- Target Temperature: 314 // 10 - 24 values will be accepted as a target temperature for the thermostat function. 315 // 316 // ---------------- Device Control Codes: 317 // First = device code, Second = operator code 318 // 30, 31, 32 turns the lighting: 30=off, 31=on 319 // 32=flip logical state (on -> off / off -> on) 320 // 40, 41, 42 will do the same to the airing ventilator 321 // 50, 51, 52 handles the One Time Heating (15 mins) timed heater program as above 322 // 323 // ---------------- Classified Operator Codes: 324 // X3, X4 are classified, used only for function calls by inner program sequences 325 if (RX[0] == '3') { 326 relayHandlerL(iRX[1]); 327 } 328 if (RX[0] == '4') { 329 relayHandlerA(iRX[1]); 330 } 331 if (RX[0] == '5') { 332 relayHandlerH(iRX[1]); 333 } 334 335 if ((iRX[0] * 10 + iRX[1] <= 24) && (iRX[0] * 10 + iRX[1] >= 10)) { // accept only numeric values between 10 & 24 336 tTarget = iRX[0] * 10 + iRX[1]; // merge two integers and set tTarget 337 tTargetEEPROM(); // after set, call the EEPROM handler function, and 338 buzz(3, 1); // write the tTarget value to the appropriate byte of the EEPROM 339 } 340 if (RX[0] =='0') { // test 341 for (byte i = 1; i < 5; i++) { 342 buzz(5, 2); 343 } 344 } 345 for (byte i = 0; i < 2; i++) { // empty all message receiver and conversion variables 346 RX[i] = 'Z'; 347 } 348} 349 350void relayHandlerL(byte lOperator) { // Lighting Handler Sequence 351 // operators are: 0=off, 1=on, 2=flip the state, 4=fill/refill the lighting state char var. 352 if ((measError) && ((lOperator == 1) || (lOperator == 2))) { 353 sTX(4); 354 return; 355 } 356 if ((lOperator == 2) || (lOperator == 0) && (lState) || (lOperator == 1) && (!lState)) { 357 lState = !lState; 358 digitalWrite(relayL, lState); 359 buzz(2, 1); 360 } 361 362 if (lOperator >= 0) { // fill up the working state char with the proper state indicator string 363 if (lState) { 364 lightingState = state_str[0]; 365 } 366 else { 367 lightingState = state_str[1]; 368 } 369 if (!startup) { 370 sTX(7); 371 } 372 } 373} 374 375void relayHandlerA(byte aOperator) { // Airing Handler Sequence 376 if ((measError) && ((aOperator == 1) || (aOperator == 2))) { // operators are: 0=off, 1=on, 2=flip the state, 377 sTX(4); // 3=called by temprMeas() funct., 4=fill/refill the airing state char var. 378 return; 379 } 380 aState = digitalRead(relayA); 381 382 if (!windowAlrt) { 383 if ((aOperator == 2) || (aState) && (aOperator == 0) || (!aState) && (aOperator == 1)) { 384 aState = !aState; 385 digitalWrite(relayA, aState); 386 aStateByCmd = digitalRead(relayA); 387 buzz(2, 1); 388 } 389 } 390 if (aOperator == 3) { // called by the temprMeas() function, 'windowAlrt' ended or started 391 if ((!aState) && (windowAlrt) || (aState) && (!windowAlrt) && (!aStateByCmd)) { 392 digitalWrite(relayA, windowAlrt); 393 } 394 } 395 aState = digitalRead(relayA); 396 if (aOperator >= 0) { 397 if (aState) { 398 if (windowAlrt) { 399 airingState = state_str[2]; 400 } 401 else { 402 airingState = state_str[0]; 403 } 404 } 405 else { 406 airingState = state_str[1]; 407 } 408 } 409 if (!startup) { 410 sTX(6); 411 } 412} 413 414void relayHandlerH(byte hOperator) { // Heater Handler Sequence 415 // operators are: 0=off, 1=on, 2=flip the state, 416 // 3=called by temprMeas() funct., 4=fill/refill the heater state char var. 417 if ((measError) && ((hOperator == 1) || (hOperator == 2))) { 418 sTX(4); 419 return; 420 } 421 if ((!hThermostat) && (!windowAlrt) && (!measError)) { // turn on/off the One Time Heating (15 mins) timed mode 422 if ((hOperator == 2) || (hOperator == 1) && (!hState) || (!hOperator) && (hState)) { 423 buzz(2, 1); 424 hState = !hState; 425 sftyTmrEnded = 0; 426 timer0 = 0; 427 digitalWrite(relayH, hState); 428 } 429 } 430 431 if (windowAlrt) { 432 sTX(3); 433 } 434 435 if (hOperator == 3) { // this function called by the temprMeas() function (op 3) 436 // in order to examine windowAlrt & measError booleans 437 if ((windowAlrt) && (hState)) { // a window is open and the heater is running 438 digitalWrite(relayH, 0); 439 buzz(5, 3); 440 } 441 if ((!windowAlrt) && (!measError)) { 442 if ((hThermostat) || (!hThermostat) && (hState) && (sftyTmrEnded)) { 443 digitalWrite(relayH, hThermostat); // proceed the command of the Thermostat Routine 444 } 445 } 446 } 447 hState = digitalRead(relayH); 448 if (hOperator >= 0) { 449 if (hState) { 450 if (hThermostat) { 451 heaterState = state_str[2]; 452 } 453 else { 454 heaterState = state_str[0]; 455 } 456 } 457 else { 458 heaterState = state_str[1]; 459 } 460 if ((((!windowAlrt) && (hOperator != 3)) || (hState)) && (!startup)) { 461 sTX(5); 462 } 463 } 464} 465 466void safetyTmr () { // Timer for the One Time Heating (15 mins timed) mode 467 if ((hState) && (!sftyTmrEnded) && (timer0 > sftyTmrInterval) && (!hThermostat)) { 468 sftyTmrEnded = 1; 469 relayHandlerH(0); 470 for (byte i = 1; i < 5; i++) { 471 buzz(i, 2); 472 } 473 } 474} 475 476void temprTimer() { // Cyclic Timer for temprMeas() 477 unsigned long temprTmrCurr = millis(); 478 if (temprInterval <= temprTmrCurr - temprTmrPrev) { 479 temprTmrPrev = temprTmrCurr; 480 temprMeas(); 481 } 482} 483 484void temprMeas() { // ----------- Temperature Measurement & Comparison Sequence 485 temprPrev = tempr; // save the value for next comparison 486 sensors.requestTemperatures(); // update sensor readings 487 tempr = sensors.getTempCByIndex(0); // read remperature 488 489 if ((tempr >= 40) || (tempr <= 0)) { // extreme meas values: 490 if (!errMsgSentBySys) { // -127, -196.60 are HW errors, +85 is tipically SW error, but 491 sTX(4); // can be fire, or a broken window 492 } 493 errMsgSentBySys = 1; 494 hThermostat = 0; 495 if (hState) { 496 relayHandlerH(0); 497 } 498 if (aState) { 499 relayHandlerA(0); 500 } 501 if (lState) { 502 relayHandlerL(0); 503 } 504 measError = 1; 505 for (byte i = 1; i < 10; i++) { 506 buzz(4, 1); 507 delay(50); 508 } 509 } 510 else { 511 temprPrev = tempr; 512 measError = 0; 513 errMsgSentBySys = 0; 514 } 515 516 if (!measError) { // ------------ Start of Temperature Analysis Sequence 517 if (tempr <= 17) { // Frequent, short-term switching of the heater gas boiler would cut short its lifetime, the 518 heatCorrVal = 0.5; // heatCorrVal value helps to keep avoid it. Declares the degree of overheating and cooling back. 519 } // Lower temperature demands greater heatCorrVal, because the walls are colder and adsorb better the 520 if ((tempr > 17) && (tempr < 19)) { // warmth from the freshly heated-up air, so the above described effect would more effective. 521 heatCorrVal = 0.4; 522 } 523 if (tempr >= 19) { 524 heatCorrVal = 0.3; 525 } 526 527 if (tTarget - tempr >= heatCorrVal) { // subtract measured value from target, if the difference equals or greater than heatCorrVal 528 sftyTmrEnded = 1; // deactivate the One Time Heating (15 mins) timed program if it is running 529 hThermostat = 1; // turn on the thermostat 530 buzz(1, 1); 531 } 532 if ((tTarget - tempr <= -1 * heatCorrVal) && (hThermostat)) { 533 hThermostat = 0; 534 } 535 536 if ((temprPrev - tempr >= 0.2) && (!windowAlrt) && (tempr <= 20)) { // in a measurement cycle and in heating season the temperature 537 windowAlrt = 1; // drops, it will evaluate as a window is open 538 sftyTmrEnded = 1; 539 for (byte i = 1; i < 5; i++) { 540 buzz(4, 1); 541 delay(50); 542 } 543 relayHandlerA(3); // call airing function (opcode = 3), to help refresh the air 544 } 545 if ((temprPrev - tempr <= -0.12) && (windowAlrt)) { // the tempr. falling is over, the air became warmer 546 windowAlrt = 0; // due to the heat capacity of the environment, 547 buzz(4, 3); // so switch back to normal mode 548 relayHandlerA(3); 549 } 550 relayHandlerH(3); // the function will examine caller param(3) & windowAlrt & measError booleans 551 552 if (!windowAlrt) { 553 sTX(1); 554 } 555 } 556} 557 558void tTargetHandler (bool set) { // set the needed tempr by increasing or decreasing 559 if (!set) { // incr 560 if (tTarget < 24) { // until it reaches the upper limit 561 tTarget++ ; 562 buzz(3, 1); 563 } 564 else { 565 buzz(2, 3); 566 } 567 } 568 else { // decr 569 if (tTarget > 10) { 570 tTarget-- ; 571 buzz(3, 1); 572 } 573 else { 574 buzz(2, 3); 575 } 576 } 577 tTargetEEPROM(); 578} 579 580void tTargetEEPROM() { 581 EEPROM.write(addr, tTarget); // after incr/decr/set, write the tTarget value to the appropriate byte of the EEPROM 582 delay(10); 583 sTX(2); 584} 585 586void draw(void) { // logo handler 587 if (frame == 0) { 588 u8g.drawXBMP( 0, 0, 128, 64, frame1); 589 } 590 else if (frame == 1) 591 screenFunctState(); 592} 593 594void screenFunctState(void) { // function state screen 595 temprWriteOut(0, 64); 596 u8g.drawHLine(0, 46, 128); 597 u8g.setFont(u8g_font_unifont); 598 if (!windowAlrt) { 599 u8g.setPrintPos( 0, 14); 600 u8g.print(funct_str[0]); 601 u8g.setPrintPos(84, 14); 602 u8g.print(heaterState); 603 } 604 else { 605 u8g.setPrintPos( 0, 14); 606 u8g.print(funct_str[3]); 607 } 608 u8g.setPrintPos( 0, 28); 609 u8g.print(funct_str[1]); 610 u8g.setPrintPos(88, 28); 611 u8g.print(airingState); 612 u8g.setPrintPos( 0, 42); 613 u8g.print(funct_str[2]); 614 u8g.setPrintPos(95, 42); 615 u8g.print(lightingState); 616 617 if ((!hState) && (!aState) && (!lState)) { 618 screenStndby(); // if all of controlled devices are in off, call standby screen 619 } 620} 621 622void screenStndby() { // standby scr 623 u8g.firstPage(); 624 do { 625 u8g.setFontRefHeightText(); 626 u8g.setFont(u8g_font_unifont); 627 if (!measError) { 628 u8g.setPrintPos(33, 52); 629 u8g.print(funct_str[5]); 630 u8g.setPrintPos( 8, 64); 631 u8g.print(funct_str[6]); 632 } 633 else { 634 u8g.setPrintPos( 4, 48); 635 u8g.print(funct_str[4]); 636 } 637 temprWriteOut(0, 16) ; 638 } while( u8g.nextPage() ); 639} 640 641void temprWriteOut (byte tX, byte tY) { // draw tempr & tTarget variables onto different coordinates 642 u8g.setFont(u8g_font_courB14); 643//u8g.setFont(u8g_font_6x12); // you can save ~10% of prog.memory using this font with 2x2 scale 644 char buftTarget[9]; 645 sprintf (buftTarget, "%d", tTarget); // int to char 646//u8g.setScale2x2(); 647//tY = tY / 2; 648 u8g.setPrintPos(tX, tY); 649 u8g.print(buftTarget); 650 u8g.setPrintPos(tX+18, tY); 651 u8g.print(funct_str[9]); 652 u8g.setPrintPos(tX+50, tY); 653 u8g.print(tempr); 654 u8g.print(char(176)); 655 u8g.print("C"); 656//u8g.undoScale(); 657} 658 659void clrScr(){ 660 u8g.firstPage(); 661 do { 662 } while( u8g.nextPage() ); 663} 664 665void ledHandler() { // the brightness of a led is low, if the indicated device is off, and high, if its on 666 if (aState) { 667 analogWrite(ledA, bright[2]); 668 } 669 else { 670 analogWrite(ledA, bright[1]); 671 } 672 if (lState) { 673 analogWrite(ledL, bright[2]); 674 } 675 else { 676 analogWrite(ledL, bright[1]); 677 } 678 if (hState) { 679 if (!hThermostat) { 680 ledBlnk() ; // the heater led blinks when the One Time Heating (15 mins) timed mode is activated, 681 } 682 else { 683 brightHeat = bright[2] ; // and constant bright, if the thermostat routine is active 684 } 685 } 686 else { 687 brightHeat = bright[1] ; 688 } 689 analogWrite(ledH, brightHeat); 690} 691 692void ledBlnk() { 693 unsigned long curr = millis(); 694 if (ledInterval <= curr - prev) { // subtract prev value from current, if the difference equals or greater than ledInterval const. 695 prev = curr; // overwrite the earlier value with the current and flip brightness level 696 if (brightHeat == bright[1]) { 697 brightHeat = bright[2]; 698 } 699 else { 700 brightHeat = bright[1]; 701 } 702 } 703 analogWrite(ledH, brightHeat); 704} 705 706void buzz(byte b, byte d) { // call with frequency and delay parameters 707 tone(buzzer, b * 1000); 708 delay(d * 100); 709 noTone(buzzer); 710} 711 712void sTX(byte reportTX) { // sending serial reports 713 switch (reportTX) { 714 case 0: 715 for (byte i = 0; i < 9; i++) { 716 sUART.print(funct_str[10]); 717 } 718 sUART.println(funct_str[10]); 719 break; 720 case 1: 721 sUART.print(funct_str[8]); // Tempr. 722 sUART.print(tempr); 723 sUART.print(char(176)); 724 sUART.println("C"); 725 break; 726 case 2: 727 sUART.print(funct_str[7]); // TTemp 728 sUART.print(tTarget); 729 sUART.print(char(176)); 730 sUART.println("C"); 731 break; 732 case 3: 733 sUART.print(funct_str[3]); // Window Alert 734 sUART.print(funct_str[9]); 735 sUART.print(tempr); 736 sUART.print(char(176)); 737 sUART.println("C"); 738 break; 739 case 4: 740 sUART.println(funct_str[4]); // Error report 741 break; 742 case 5: 743 sUART.print(funct_str[0]); // Working state of devices 744 sUART.println(heaterState); 745 break; 746 case 6: 747 sUART.print(funct_str[1]); 748 sUART.println(airingState); 749 break; 750 case 7: 751 sUART.print(funct_str[2]); 752 sUART.println(lightingState); 753 break; 754 case 8: // Overview report 755 sTX(0); 756 relayHandlerH(4); 757 relayHandlerA(4); 758 relayHandlerL(4); 759 sTX(2); 760 if (measError) { 761 sTX(4); 762 } 763 break; 764 } 765}
Thermostat Fahrenheit - Gyula Ősi
cpp
The program code explains itself, useful for begin
1// Fahrenheit version v1.1 2// Program code of an intelligent Arduino smarthome thermostat solution, 3// based on Arduino Nano (or higher) board, DS18B20 thermo sensor, HC-05 Bluetooth adapter, I2C 128X64 bicolor OLED display. 4// The system can be controlled by buttons and Android smartphone via bluetooth. 5// 6// It handles the HEATER gas boiler, the bathroom AIRING ventilator and the kitchen LIGHTING - swithed with relays. 7// The heater has two working ways. 1: One Time Heating (15 mins) timed mode, 2: Thermostat mode (higher priority). The adjusted target tempr. 8// stored in EEPROM. The program detects hardware errors and window opening - in these cases the heater stops and/or will not start. 9// 10// Designed and programmed by Gyula Osi. 11// All rights reserved. 12// ------------------------------------------------------------------------------------------------------------------------------------ 13 14// ---- Display I2C Bus, SDA(TX) -> A4, SCL(RX) -> A5 15#include "U8glib.h" 16U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE); // display constructor 17byte frame = 0; // start logo pointer 18 19// ---- Ports and related declarations 20const byte buzzer = 9; // buzzer to D9 21int btnVal; // stores analog values from buttons 22const byte relayA = 11; // airing 23bool aState = 0; 24bool aStateByCmd; // if "window alert" is gone, the airing control goes back to the original state 25const byte relayL = 13; // lighting 26bool lState = 0; 27const byte relayH = 10; // heater 28const byte ledH = 6; // PWM ports allow output level adjustment used to change brightness 29const byte ledA = 5; 30const byte ledL = 3; 31const byte bright[3] = {0, 10, 100}; 32byte brightHeat = bright[2]; 33#define ledInterval 1000 // heater led blinking interval 34unsigned long prev = 0; 35 36// ---- Strings for Display and Serial Reports 37#define STATE_ITEMS 3 // device state indicator strings for outputs 38// i -> 0 1 2 39const String state_str[STATE_ITEMS] = {"on.", "off.", "auto."}; 40String heaterState; 41String airingState; 42String lightingState; 43#define FUNCT_ITEMS 11 44// i -> 0 1 2 3 4 5 6 7 8 9 10 45String funct_str[FUNCT_ITEMS] = {"Heater is ", "Airing is ", "Lighting is ", "Window Alert!", "Hardware Error!", "Hit a Key >>", "or send a Code!", "Target tempr = ", "Temperature = ", " * ", " -"}; 46 47// ---- Temperature Measurement and Heater Related Features 48#include <elapsedMillis.h> 49elapsedMillis timer0; // 8-bit, PWM timer, used by function elapsedMillis() 50#define sftyTmrInterval 15 * 60000 // one Time Heating (15 mins) timed mode interval [ms] 51bool sftyTmrEnded; // boolean startup, the timer0 has ended 52#include <EEPROM.h> 53byte tTarget; // adjusted target tempr 54const int addr = 0; // the current address of the tTarget variable in the EEPROM memory 55bool hState = 0; // heater boolean state 56bool hThermostat = 0; // thermostat boolean state 57#include "OneWire.h" 58#include "DallasTemperature.h" 59#define DS18B20 2 // setup the OneWire bus on D2 60OneWire temprWire(DS18B20); // setup DS18B20 to work on the OneWire bus 61DallasTemperature sensors(&temprWire); 62float tempr; // measured value 63float temprPrev; // copy of measured value for trend analysis 64bool windowAlrt = 0; // specified degree of tempr drop 65bool measError = 0; // measured tempr value is out of the range specified as normal 66const long temprInterval = 60000; // cyclic tempr measurement interval [ms] 67unsigned long temprTmrPrev = 0; // the elapsed will be the previous when temprMeas() called 68float heatCorrVal; // declares the degree of overheating and cooling back, see tempMeas() function 69 70// ---- Configuration of Serial Communication on virtual RXD/TXD 71#include <SoftwareSerial.h> // SW serial RX & TX pins for HC-05 72const int RX1 = 8; 73const int TX1 = 4; 74SoftwareSerial sUART(RX1,TX1); 75char RX[2]; // store received serial data 76bool errMsgSentBySys = 0; 77bool startup = 1; // keep avoid a duplicate BT report at startup 78 79const uint8_t frame1[] U8G_PROGMEM = { // XBM map 80 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 81 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 82 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 83 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 84 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 85 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 86 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0xFE, 0xFF, 87 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFC, 0xFF, 0x7F, 0xF0, 88 0x3F, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0x07, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 89 0xFC, 0xFF, 0x7F, 0xF0, 0x8F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 90 0xFF, 0xFF, 0x1F, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 0x8F, 0xFF, 0xFF, 0xFF, 91 0xFF, 0xFF, 0x1F, 0xFF, 0xFF, 0xFF, 0x1F, 0xFF, 0xF1, 0xFF, 0xFF, 0xFF, 92 0x8F, 0xFF, 0x1F, 0x7F, 0x8C, 0x3F, 0x1E, 0xFF, 0x00, 0xFE, 0x1F, 0xFF, 93 0xF1, 0x00, 0x18, 0xC0, 0x8F, 0xFF, 0x1F, 0x7F, 0x8C, 0x3F, 0x1E, 0xFF, 94 0x00, 0xFE, 0x1F, 0xFF, 0xF1, 0x00, 0x18, 0xC0, 0x8F, 0xFF, 0x1F, 0x1F, 95 0x0C, 0x3E, 0x1E, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 0x31, 0xFE, 0x7F, 0xFC, 96 0x8F, 0xFF, 0x1F, 0x1F, 0x0C, 0x3E, 0x1E, 0xFF, 0xFF, 0xF8, 0x1F, 0xFF, 97 0x31, 0xFE, 0x7F, 0xFC, 0x0F, 0x0E, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0xFC, 98 0x00, 0xF8, 0x1F, 0x7C, 0x30, 0xFE, 0x7F, 0xF0, 0x0F, 0x0E, 0x18, 0x1F, 99 0x0C, 0x3E, 0x1E, 0xFC, 0x00, 0xF8, 0x1F, 0x7C, 0x30, 0xFE, 0x7F, 0xF0, 100 0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C, 101 0xF0, 0x00, 0x7E, 0xF0, 0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C, 102 0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x00, 0x7E, 0xF0, 0x0F, 0xFE, 0x18, 0x1F, 103 0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x3F, 0x78, 0xF0, 104 0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C, 105 0xF0, 0x3F, 0x78, 0xF0, 0x0F, 0xFE, 0x18, 0x1F, 0x0C, 0x3E, 0x1E, 0x3C, 106 0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x3F, 0x78, 0xF0, 0x0F, 0xFE, 0x18, 0x1F, 107 0x0C, 0x3E, 0x1E, 0x3C, 0x3E, 0xF8, 0x1F, 0x7C, 0xF0, 0x3F, 0x78, 0xF0, 108 0x3F, 0x00, 0x7E, 0x00, 0x3C, 0x80, 0x07, 0xF0, 0x00, 0xF8, 0x7F, 0x00, 109 0x3C, 0x00, 0x1E, 0xC0, 0x3F, 0x00, 0x7E, 0x00, 0x3C, 0x80, 0x07, 0xF0, 110 0x00, 0xF8, 0x7F, 0x00, 0x3C, 0x00, 0x1E, 0xC0, 0xFF, 0xFF, 0xFF, 0x1F, 111 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 112 0xFF, 0xFF, 0xFF, 0x1F, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 113 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 114 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 115 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 116 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 117 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 118 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 119 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 120 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 121 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 122 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 123 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 124 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 125 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 126 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 127 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 128 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 132 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 133 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 134 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 135 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 136 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 137 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 138 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 139 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 140 0x00, 0x7E, 0x06, 0xE6, 0x3F, 0x06, 0xC6, 0x7F, 0xFE, 0xE7, 0x3F, 0x7E, 141 0xFE, 0xC7, 0x7F, 0x00, 0x00, 0x30, 0x06, 0x66, 0x60, 0x06, 0x66, 0x00, 142 0x60, 0x60, 0x60, 0x30, 0x06, 0x60, 0x00, 0x00, 0x00, 0x30, 0x06, 0x66, 143 0x60, 0x06, 0x66, 0x00, 0x60, 0x60, 0x60, 0x30, 0x06, 0x60, 0x00, 0x00, 144 0x00, 0x30, 0x1E, 0x66, 0x60, 0x06, 0x66, 0x00, 0x60, 0x60, 0x60, 0x30, 145 0x06, 0x60, 0x00, 0x00, 0x00, 0x30, 0x3E, 0x66, 0x60, 0x06, 0x66, 0x00, 146 0x60, 0x60, 0x60, 0x30, 0x06, 0x60, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0xE6, 147 0x61, 0x1E, 0xC7, 0x3F, 0x70, 0xE0, 0x3F, 0x3C, 0xFE, 0xC3, 0x3F, 0x00, 148 0x00, 0x3C, 0x7E, 0xE6, 0x61, 0x1E, 0xC7, 0x3F, 0x70, 0xE0, 0x3F, 0x3C, 149 0xFE, 0xC3, 0x3F, 0x00, 0x00, 0x3C, 0xDE, 0xE7, 0x61, 0x1E, 0x07, 0x70, 150 0x70, 0xE0, 0x1D, 0x3C, 0x1E, 0x00, 0x70, 0x00, 0x00, 0x3C, 0x1E, 0xE7, 151 0x61, 0x1E, 0x07, 0x70, 0x70, 0xE0, 0x31, 0x3C, 0x1E, 0x00, 0x70, 0x00, 152 0x00, 0x3C, 0x1E, 0xE6, 0x61, 0x1E, 0x07, 0x70, 0x70, 0xE0, 0x61, 0x3C, 153 0x1E, 0x00, 0x70, 0x00, 0x00, 0x3C, 0x1E, 0xE6, 0x61, 0x1E, 0x07, 0x70, 154 0x70, 0xE0, 0x61, 0x3C, 0x1E, 0x00, 0x70, 0x00, 0x00, 0x7F, 0x1E, 0xE6, 155 0x3F, 0xFC, 0xE3, 0x3F, 0x70, 0xE0, 0x61, 0x7E, 0xFE, 0xE7, 0x3F, 0x00, 156 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 157 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 158 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 159 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 160 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 161 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 162 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 163 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 164 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 165 0x00, 0x00, 0x00, 0x00, 166}; 167 168void setup() { 169 sUART.begin(9600); 170 pinMode(relayH, OUTPUT); 171 relayHandlerH(4); // get the working state 172 pinMode(ledH, OUTPUT); 173 pinMode(relayA, OUTPUT); 174 relayHandlerA(4); 175 pinMode(ledA, OUTPUT); 176 pinMode(relayL, OUTPUT); 177 relayHandlerL(4); 178 pinMode(ledL, OUTPUT); 179 pinMode(buzzer, OUTPUT); 180 sensors.begin(); // start DS18B20 181 temprMeas(); // do not wait for the meas.timer, call the function once at startup 182 tTarget = EEPROM.read(addr); // read the previously stored tTarget value from the current address of the EEPROM at startup 183 startup = 0; 184 if (!measError) { 185 sTX(8); // call for instant report of working states after startup 186 } 187 else { 188 sTX(2); 189 } 190} 191 192void loop() { 193 temprTimer(); 194 ledHandler(); 195 btnReadings(); 196 sRX(); 197 safetyTmr(); 198 199 u8g.firstPage(); // scr loop 200 do { 201 draw(); 202 } while( u8g.nextPage() ); 203 if (frame == 0) { 204 delay(3000); 205 frame = 1; 206 clrScr(); 207 } 208} 209 210void btnReadings() { // --------- Btn Readings 211 btnVal = analogRead(A0); // read analog val from A0 212 if (btnVal >= 510 && btnVal <= 516) { // btn Lighting 213 delay(100); // btn debounce 214 buzz(3, 1); 215 relayHandlerL(2); // call proper function with logical state flip opcode as parameter 216 } 217 else if (btnVal >= 849 && btnVal <= 855){ // btn Airing 218 if (windowAlrt == 1) { // if the system is in Window Alert mode, disable it 219 windowAlrt = 0; 220 buzz(4, 3); 221 relayHandlerA(3); 222 } 223 else { // else turn on/off the airing ventilator 224 delay(100); 225 buzz(3, 1); 226 relayHandlerA(2); 227 } 228 } 229 else if (btnVal >= 927 && btnVal <= 933){ // btn One Time Heating (15 mins) timed mode 230 delay(100); 231 buzz(3, 1); 232 relayHandlerH(2); 233 } 234 else if (btnVal >= 767 && btnVal <= 777) { // btn decrease tTarget 235 delay(100); 236 tTargetHandler(0); 237 } 238 else if (btnVal >= 687 && btnVal <= 697) { // btn increase tTarget 239 delay(100); 240 tTargetHandler(1); 241 } 242 else if (btnVal >= 856 && btnVal <= 862) { // inc & dec btns at the same time 243 tTarget = 14; // <==== initial value - press these buttons at the very first powerup! 244 } 245} 246 247void sRX() { // ------------- Receive Serial Data 248 while (sUART.available() > 0) { // if data is available to read 249 for (byte i = 0; i < 2; i++) { 250 RX[i] = sUART.read(); 251 } 252 } 253 int iRX[2]; 254 for (byte i = 0; i < 2; i++) { 255 iRX[i] = RX[i] - '0'; 256 } 257 258 switch (RX[0]) { // ------------ accept SINGLE ALPHABETICAL control codes 259 case 'A': 260 relayHandlerH(1); // 1 = on 261 break; 262 case 'a': 263 relayHandlerH(0); // 0 = off 264 break; // Received serial data can be a single alphabetical letter from "Arduino 265 case 'B': // Bluetooth Control Device" Android app. If a proper alphabetical 266 relayHandlerA(1); // character arrives, the program code will not wait for the second one, 267 break; // but calls the applicable function with a proper operation code. 268 case 'b': // Cases of combined numeric data can be seen below. 269 relayHandlerA(0); 270 break; 271 case 'C': 272 relayHandlerL(1); 273 break; 274 case 'c': 275 relayHandlerL(0); 276 break; 277 case 'D': 278 case 'd': 279 tTarget = 21; 280 tTargetEEPROM(); 281 buzz(3, 1); 282 break; 283 case 'E': 284 case 'e': 285 tTarget = 19; 286 tTargetEEPROM(); 287 buzz(3, 1); 288 break; 289 case 'F': 290 case 'f': 291 tTarget = 14; 292 tTargetEEPROM(); 293 buzz(3, 1); 294 break; 295 case 'R': // call for an overview report about controlled devices 296 case 'r': 297 sTX(8); 298 break; 299 case 'W': // disable Window Alert state 300 case 'w': 301 windowAlrt = 0; 302 buzz(4, 3); 303 relayHandlerA(3); 304 break; 305 } 306 // ----------------------- accept COMBINED NUMERIC control codes 307 // In this case a two-digit numeric control code arrives in char format, 308 // from an Android bluetooth serial app for instance. After a char to integer 309 // conversion (only if the first char is '1' or '2') a merge-process will follow, 310 // and the system of conditions and statements will make a decision and execute it. 311 // Appropriate numeric codes are: 312 // 313 // ---------------- Target Temperature: 314 // 50 - 76 values will be accepted as a target temperature for the thermostat function. 315 // 316 // ---------------- Device Control Codes: 317 // First = device code, Second = operator code 318 // 10, 11, 12 turns the lighting: 10=off, 11=on 319 // 12=flip logical state (on -> off / off -> on) 320 // 20, 21, 22 will do the same to the airing ventilator 321 // 30, 31, 32 handles the One Time Heating (15 mins) timed heater program as above 322 // 323 // ---------------- Classified Operator Codes: 324 // X3, X4 are classified, used only for function calls by inner program sequences 325 if (RX[0] == '1') { 326 relayHandlerL(iRX[1]); 327 } 328 if (RX[0] == '2') { 329 relayHandlerA(iRX[1]); 330 } 331 if (RX[0] == '3') { 332 relayHandlerH(iRX[1]); 333 } 334 335 if ((iRX[0] * 10 + iRX[1] <= 76) && (iRX[0] * 10 + iRX[1] >= 50)) { // accept only numeric values between 50 & 76 336 tTarget = iRX[0] * 10 + iRX[1]; // merge two integers and set tTarget 337 tTargetEEPROM(); // after set, call the EEPROM handler function, and 338 buzz(3, 1); // write the tTarget value to the appropriate byte of the EEPROM 339 } 340 if (RX[0] =='0') { // test 341 for (byte i = 1; i < 5; i++) { 342 buzz(5, 2); 343 } 344 } 345 for (byte i = 0; i < 2; i++) { // empty all message receiver and conversion variables 346 RX[i] = 'Z'; 347 } 348} 349 350void relayHandlerL(byte lOperator) { // Lighting Handler Sequence 351 // operators are: 0=off, 1=on, 2=flip the state, 4=fill/refill the lighting state char var. 352 if ((measError) && ((lOperator == 1) || (lOperator == 2))) { 353 sTX(4); 354 return; 355 } 356 if ((lOperator == 2) || (lOperator == 0) && (lState) || (lOperator == 1) && (!lState)) { 357 lState = !lState; 358 digitalWrite(relayL, lState); 359 buzz(2, 1); 360 } 361 362 if (lOperator >= 0) { // fill up the working state char with the proper state indicator string 363 if (lState) { 364 lightingState = state_str[0]; 365 } 366 else { 367 lightingState = state_str[1]; 368 } 369 if (!startup) { 370 sTX(7); 371 } 372 } 373} 374 375void relayHandlerA(byte aOperator) { // Airing Handler Sequence 376 if ((measError) && ((aOperator == 1) || (aOperator == 2))) { // operators are: 0=off, 1=on, 2=flip the state, 377 sTX(4); // 3=called by temprMeas() funct., 4=fill/refill the airing state char var. 378 return; 379 } 380 aState = digitalRead(relayA); 381 382 if (!windowAlrt) { 383 if ((aOperator == 2) || (aState) && (aOperator == 0) || (!aState) && (aOperator == 1)) { 384 aState = !aState; 385 digitalWrite(relayA, aState); 386 aStateByCmd = digitalRead(relayA); 387 buzz(2, 1); 388 } 389 } 390 if (aOperator == 3) { // called by the temprMeas() function, 'windowAlrt' ended or started 391 if ((!aState) && (windowAlrt) || (aState) && (!windowAlrt) && (!aStateByCmd)) { 392 digitalWrite(relayA, windowAlrt); 393 } 394 } 395 aState = digitalRead(relayA); 396 if (aOperator >= 0) { 397 if (aState) { 398 if (windowAlrt) { 399 airingState = state_str[2]; 400 } 401 else { 402 airingState = state_str[0]; 403 } 404 } 405 else { 406 airingState = state_str[1]; 407 } 408 } 409 if (!startup) { 410 sTX(6); 411 } 412} 413 414void relayHandlerH(byte hOperator) { // Heater Handler Sequence 415 // operators are: 0=off, 1=on, 2=flip the state, 416 // 3=called by temprMeas() funct., 4=fill/refill the heater state char var. 417 if ((measError) && ((hOperator == 1) || (hOperator == 2))) { 418 sTX(4); 419 return; 420 } 421 if ((!hThermostat) && (!windowAlrt) && (!measError)) { // turn on/off the One Time Heating (15 mins) timed mode 422 if ((hOperator == 2) || (hOperator == 1) && (!hState) || (!hOperator) && (hState)) { 423 buzz(2, 1); 424 hState = !hState; 425 sftyTmrEnded = 0; 426 timer0 = 0; 427 digitalWrite(relayH, hState); 428 } 429 } 430 431 if (windowAlrt) { 432 sTX(3); 433 } 434 435 if (hOperator == 3) { // this function called by the temprMeas() function (op 3) 436 // in order to examine windowAlrt & measError booleans 437 if ((windowAlrt) && (hState)) { // a window is open and the heater is running 438 digitalWrite(relayH, 0); 439 buzz(5, 3); 440 } 441 if ((!windowAlrt) && (!measError)) { 442 if ((hThermostat) || (!hThermostat) && (hState) && (sftyTmrEnded)) { 443 digitalWrite(relayH, hThermostat); // proceed the command of the Thermostat Routine 444 } 445 } 446 } 447 hState = digitalRead(relayH); 448 if (hOperator >= 0) { 449 if (hState) { 450 if (hThermostat) { 451 heaterState = state_str[2]; 452 } 453 else { 454 heaterState = state_str[0]; 455 } 456 } 457 else { 458 heaterState = state_str[1]; 459 } 460 if ((((!windowAlrt) && (hOperator != 3)) || (hState)) && (!startup)) { 461 sTX(5); 462 } 463 } 464} 465 466void safetyTmr () { // Timer for the One Time Heating (15 mins timed) mode 467 if ((hState) && (!sftyTmrEnded) && (timer0 > sftyTmrInterval) && (!hThermostat)) { 468 sftyTmrEnded = 1; 469 relayHandlerH(0); 470 for (byte i = 1; i < 5; i++) { 471 buzz(i, 2); 472 } 473 } 474} 475 476void temprTimer() { // Cyclic Timer for temprMeas() 477 unsigned long temprTmrCurr = millis(); 478 if (temprInterval <= temprTmrCurr - temprTmrPrev) { 479 temprTmrPrev = temprTmrCurr; 480 temprMeas(); 481 } 482} 483 484void temprMeas() { // ----------- Temperature Measurement & Comparison Sequence 485 temprPrev = tempr; // save the value for next comparison 486 sensors.requestTemperatures(); // update sensor readings 487 tempr = sensors.getTempFByIndex(0); // read remperature 488 489 if ((tempr >= 104) || (tempr <= 32)) { // extreme meas values: 490 if (!errMsgSentBySys) { // -127, -196.60 are HW errors, +85 is tipically SW error, but 491 sTX(4); // can be fire, or a broken window 492 } 493 errMsgSentBySys = 1; 494 hThermostat = 0; 495 if (hState) { 496 relayHandlerH(0); 497 } 498 if (aState) { 499 relayHandlerA(0); 500 } 501 if (lState) { 502 relayHandlerL(0); 503 } 504 measError = 1; 505 for (byte i = 1; i < 10; i++) { 506 buzz(4, 1); 507 delay(50); 508 } 509 } 510 else { 511 temprPrev = tempr; 512 measError = 0; 513 errMsgSentBySys = 0; 514 } 515 516 if (!measError) { // ------------ Start of Temperature Analysis Sequence 517 if (tempr <= 62.6) { // Frequent, short-term switching of the heater gas boiler would cut short its lifetime, the 518 heatCorrVal = 0.9; // heatCorrVal value helps to keep avoid it. Declares the degree of overheating and cooling back. 519 } // Lower temperature demands greater heatCorrVal, because the walls are colder and adsorb better the 520 if ((tempr > 62.6) && (tempr < 66.2)) { // warmth from the freshly heated-up air, so the above described effect would more effective. 521 heatCorrVal = 0.72; 522 } 523 if (tempr >= 66.2) { 524 heatCorrVal = 0.54; 525 } 526 527 if (tTarget - tempr >= heatCorrVal) { // subtract measured value from target, if the difference equals or greater than heatCorrVal 528 sftyTmrEnded = 1; // deactivate the One Time Heating (15 mins) timed program if it is running 529 hThermostat = 1; // turn on the thermostat 530 buzz(1, 1); 531 } 532 if ((tTarget - tempr <= -1 * heatCorrVal) && (hThermostat)) { 533 hThermostat = 0; 534 } 535 536 if ((temprPrev - tempr >= 0.36) && (!windowAlrt) && (tempr <= 68)) { // in a measurement cycle and in heating season the temperature 537 windowAlrt = 1; // drops, it will evaluate as a window is open 538 sftyTmrEnded = 1; 539 for (byte i = 1; i < 5; i++) { 540 buzz(4, 1); 541 delay(50); 542 } 543 relayHandlerA(3); // call airing function (opcode = 3), to help refresh the air 544 } 545 if ((temprPrev - tempr <= -0.216) && (windowAlrt)) { // the tempr. falling is over, the air became warmer 546 windowAlrt = 0; // due to the heat capacity of the environment, 547 buzz(4, 3); // so switch back to normal mode 548 relayHandlerA(3); 549 } 550 relayHandlerH(3); // the function will examine caller param(3) & windowAlrt & measError booleans 551 552 if (!windowAlrt) { 553 sTX(1); 554 } 555 } 556} 557 558void tTargetHandler (bool set) { // set the needed tempr by increasing or decreasing 559 if (!set) { // incr 560 if (tTarget < 76) { // until it reaches the upper limit 561 tTarget++ ; 562 buzz(3, 1); 563 } 564 else { 565 buzz(2, 3); 566 } 567 } 568 else { // decr 569 if (tTarget > 50) { 570 tTarget-- ; 571 buzz(3, 1); 572 } 573 else { 574 buzz(2, 3); 575 } 576 } 577 tTargetEEPROM(); 578} 579 580void tTargetEEPROM() { 581 EEPROM.write(addr, tTarget); // after incr/decr/set, write the tTarget value to the appropriate byte of the EEPROM 582 delay(10); 583 sTX(2); 584} 585 586void draw(void) { // logo handler 587 if (frame == 0) { 588 u8g.drawXBMP( 0, 0, 128, 64, frame1); 589 } 590 else if (frame == 1) 591 screenFunctState(); 592} 593 594void screenFunctState(void) { // function state screen 595 temprWriteOut(0, 64); 596 u8g.drawHLine(0, 46, 128); 597 u8g.setFont(u8g_font_unifont); 598 if (!windowAlrt) { 599 u8g.setPrintPos( 0, 14); 600 u8g.print(funct_str[0]); 601 u8g.setPrintPos(84, 14); 602 u8g.print(heaterState); 603 } 604 else { 605 u8g.setPrintPos( 0, 14); 606 u8g.print(funct_str[3]); 607 } 608 u8g.setPrintPos( 0, 28); 609 u8g.print(funct_str[1]); 610 u8g.setPrintPos(88, 28); 611 u8g.print(airingState); 612 u8g.setPrintPos( 0, 42); 613 u8g.print(funct_str[2]); 614 u8g.setPrintPos(95, 42); 615 u8g.print(lightingState); 616 617 if ((!hState) && (!aState) && (!lState)) { 618 screenStndby(); // if all of controlled devices are in off, call standby screen 619 } 620} 621 622void screenStndby() { // standby scr 623 u8g.firstPage(); 624 do { 625 u8g.setFontRefHeightText(); 626 u8g.setFont(u8g_font_unifont); 627 if (!measError) { 628 u8g.setPrintPos(33, 52); 629 u8g.print(funct_str[5]); 630 u8g.setPrintPos( 8, 64); 631 u8g.print(funct_str[6]); 632 } 633 else { 634 u8g.setPrintPos( 4, 48); 635 u8g.print(funct_str[4]); 636 } 637 temprWriteOut(0, 16) ; 638 } while( u8g.nextPage() ); 639} 640 641void temprWriteOut (byte tX, byte tY) { // draw tempr & tTarget variables onto different coordinates 642 u8g.setFont(u8g_font_courB14); 643//u8g.setFont(u8g_font_6x12); // you can save ~10% of prog.memory using this font with 2x2 scale 644 char buftTarget[9]; 645 sprintf (buftTarget, "%d", tTarget); // int to char 646//u8g.setScale2x2(); 647//tY = tY / 2; 648 u8g.setPrintPos(tX, tY); 649 u8g.print(buftTarget); 650 u8g.setPrintPos(tX+18, tY); 651 u8g.print(funct_str[9]); 652 u8g.setPrintPos(tX+50, tY); 653 u8g.print(tempr); 654//u8g.print(char(176)); 655 u8g.print("F"); 656//u8g.undoScale(); 657} 658 659void clrScr(){ 660 u8g.firstPage(); 661 do { 662 } while( u8g.nextPage() ); 663} 664 665void ledHandler() { // the brightness of a led is low, if the indicated device is off, and high, if its on 666 if (aState) { 667 analogWrite(ledA, bright[2]); 668 } 669 else { 670 analogWrite(ledA, bright[1]); 671 } 672 if (lState) { 673 analogWrite(ledL, bright[2]); 674 } 675 else { 676 analogWrite(ledL, bright[1]); 677 } 678 if (hState) { 679 if (!hThermostat) { 680 ledBlnk() ; // the heater led blinks when the One Time Heating (15 mins) timed mode is activated, 681 } 682 else { 683 brightHeat = bright[2] ; // and constant bright, if the thermostat routine is active 684 } 685 } 686 else { 687 brightHeat = bright[1] ; 688 } 689 analogWrite(ledH, brightHeat); 690} 691 692void ledBlnk() { 693 unsigned long curr = millis(); 694 if (ledInterval <= curr - prev) { // subtract prev value from current, if the difference equals or greater than ledInterval const. 695 prev = curr; // overwrite the earlier value with the current and flip brightness level 696 if (brightHeat == bright[1]) { 697 brightHeat = bright[2]; 698 } 699 else { 700 brightHeat = bright[1]; 701 } 702 } 703 analogWrite(ledH, brightHeat); 704} 705 706void buzz(byte b, byte d) { // call with frequency and delay parameters 707 tone(buzzer, b * 1000); 708 delay(d * 100); 709 noTone(buzzer); 710} 711 712void sTX(byte reportTX) { // sending serial reports 713 switch (reportTX) { 714 case 0: 715 for (byte i = 0; i < 9; i++) { 716 sUART.print(funct_str[10]); 717 } 718 sUART.println(funct_str[10]); 719 break; 720 case 1: 721 sUART.print(funct_str[8]); // Tempr. 722 sUART.print(tempr); 723 //sUART.print(char(176)); 724 sUART.println("F"); 725 break; 726 case 2: 727 sUART.print(funct_str[7]); // TTemp 728 sUART.print(tTarget); 729 //sUART.print(char(176)); 730 sUART.println("F"); 731 break; 732 case 3: 733 sUART.print(funct_str[3]); // Window Alert 734 sUART.print(funct_str[9]); 735 sUART.print(tempr); 736 //sUART.print(char(176)); 737 sUART.println("F"); 738 break; 739 case 4: 740 sUART.println(funct_str[4]); // Error report 741 break; 742 case 5: 743 sUART.print(funct_str[0]); // Working state of devices 744 sUART.println(heaterState); 745 break; 746 case 6: 747 sUART.print(funct_str[1]); 748 sUART.println(airingState); 749 break; 750 case 7: 751 sUART.print(funct_str[2]); 752 sUART.println(lightingState); 753 break; 754 case 8: // Overview report 755 sTX(0); 756 relayHandlerH(4); 757 relayHandlerA(4); 758 relayHandlerL(4); 759 sTX(2); 760 if (measError) { 761 sTX(4); 762 } 763 break; 764 } 765}
Comments
Only logged in users can leave comments
gyula-osi
0 Followers
•0 Projects
Table of contents
Intro
0
0