Precise and programmable wireless thermostat
This thermostat will allow you to control your heating system precisely by measuring the temperature where you want it. It adapts to most radiators and boilers and allows you to program different temperatures depending on the time and day of the week.
Components and supplies
Breadboard 170 pins
1N4007 1A 1000V Diode
Arduino Nano 33 BLE
32.768 kHz Crystal
External RTC - DS1302
USB charger
Rotary Encoder Module
USB to micro USB cable
Diode 1N4148
Capacitor 470 µF
Jumper wires (generic)
1,3" OLED Display SH1106 128x64 I2C
Knob, 0.25 "
EEPROM AT24C256
9v Battery
9V Battery Clip
Breadboard 400 points
1 relay module 5 Vdc 10A (assembled)
Plastic enclosure 115x90x55 mm
DS18B20 Programmable Resolution 1-Wire Digital Thermometer
Tools and machines
soldering iron
Apps and platforms
Arduino IDE
Project description
Code
Thermostat BLE receiver
cpp
Code for the receiver
1/* Thermostat BLE receiver */ 2 3/* If you want the heating system to stop 4 heating when not connected to the 5 thermostat, change the next line to false */ 6const bool heatWhenNotConnected=true; 7 8bool heat; 9 10#include <ArduinoBLE.h> 11 12const int redLED=22; 13const int blueLED=23; 14 15/* If the LED is green when connected, replace 16 the previous line by the next one */ 17// const int blueLED=24; 18 19const int heatPin=13; 20 21/* This address must be the same as in the 22 thermostat software */ 23BLEService heatService 24 ("707158fa-c794-4774-9d5c-790121b1be5d"); 25 26BLEByteCharacteristic switchCharacteristic 27 ("707158fb-c794-4774-9d5c-790121b1be5d", 28 BLERead | BLEWrite); 29 30class chronometer 31{ 32 unsigned long lastTime, actualTime; 33 public : 34 unsigned long elapsed; 35 void init(); // start the chronometer 36 void now(); // measure elapsed time since init 37 chronometer(); 38}; 39 40void chronometer::init() 41{ 42 actualTime=millis(); 43 lastTime=actualTime; 44} 45 46void chronometer::now() 47{ 48 actualTime=millis(); 49 if (actualTime<lastTime) 50 // Overflow of the millis counter 51 elapsed=(0xFFFFFFFFul-lastTime+ 52 actualTime); 53 else 54 elapsed=(actualTime-lastTime); 55} 56 57chronometer::chronometer() 58{ 59 actualTime=millis(); 60 lastTime=actualTime; 61} 62 63void heatControl(void) 64{ 65 static chronometer recChrono; 66 67 recChrono.now(); 68 BLEDevice central=BLE.central(); 69 if(central) 70 { 71 if(recChrono.elapsed<200) 72 { 73 digitalWrite(redLED, LOW); 74 digitalWrite(blueLED, HIGH); 75 } 76 else 77 { 78 digitalWrite(redLED, HIGH); 79 digitalWrite(blueLED, LOW); 80 } 81 if(switchCharacteristic.written()) 82 { 83 heat= 84 switchCharacteristic.value()? 85 true:false; 86 recChrono.init(); 87 } 88 if(recChrono.elapsed>120000) 89 heat=heatWhenNotConnected; 90 } 91 else 92 { 93 if(recChrono.elapsed<120000) 94 { 95 digitalWrite(blueLED, LOW); 96 digitalWrite(redLED, HIGH); 97 } 98 else 99 { 100 digitalWrite(redLED, HIGH); 101 digitalWrite(blueLED, HIGH); 102 heat=heatWhenNotConnected; 103 } 104 } 105 if(heat) 106 digitalWrite(heatPin, HIGH); 107 else 108 digitalWrite(heatPin, LOW); 109} 110 111void setup() 112{ 113 pinMode(redLED, OUTPUT); 114 pinMode(blueLED, OUTPUT); 115 pinMode(heatPin, OUTPUT); 116 digitalWrite(redLED,HIGH); 117 digitalWrite(blueLED,HIGH); 118 heat=heatWhenNotConnected; 119 120 BLE.begin(); 121 BLE.setLocalName("remoteHeat"); 122 BLE.setAdvertisedService(heatService); 123 heatService.addCharacteristic 124 (switchCharacteristic); 125 BLE.addService(heatService); 126 switchCharacteristic.writeValue(0); 127 BLE.advertise(); 128} 129 130void loop() 131{ 132 heatControl(); 133}
Thermostat main code
cpp
Thermostat main code
1/* Thermostat BLE */ 2 3/* This address must be the same as in the 4 receiver software */ 5String deviceAddress 6 ("707158fa-c794-4774-9d5c-790121b1be5d"); 7 8#include <Wire.h> 9#include <MaximWire.h> 10#include <U8g2lib.h> 11#include <RTClib.h> 12#include <ArduinoBLE.h> 13#include "SourceFsm.h" 14 15#define rotaryAPin 6 16#define rotaryBPin 7 17#define rotarySwitchPin 8 18#define RTC_CLK A1 19#define RTC_DAT A2 20#define RTC_RST A3 21#define DS18B20Pin 2 22#define battPin A7 23 24/* Adapt the next line to the controller of 25 your OLED display */ 26 27U8G2_SH1106_128X64_NONAME_F_HW_I2C 28 u8g2(U8G2_R0); 29 30//U8G2_SSD1306_128X64_NONAME_F_HW_I2C 31// u8g2(U8G2_R0); 32 33DS1302 rtc(RTC_RST, RTC_CLK, RTC_DAT); 34MaximWire::Bus bus(DS18B20Pin); 35MaximWire::DS18B20 device; 36BLEDevice peripheral; 37BLECharacteristic heatCharacteristic; 38 39float tempIncr; 40float temp=19.0, tempDS18B20; 41float corrDS18B20; 42bool tempOK=false; 43float minTemp, maxTemp; 44int percent=50; 45float setPoint, fixSetPoint; 46bool changeSetPoint=false; 47 48bool heat=true; 49bool connected=false; 50 51int mode; 52#define stop 0 53#define fixed 1 54#define prog 2 55bool changeMode=false; 56 57int sleepDelay; 58bool displayActive=true; 59 60int tempUnit; 61#define Celsius 0 62#define Fahrenheit 1 63 64int language; 65#define english 0 66#define french 1 67 68enum {noSet, setSleepDelay, setTempUnit, 69 setDS18B20Corr, setLanguage} 70 settingsSet=noSet; 71 72float deltaT; /* When the difference 73 between the set point and the temperature 74 is larger than this value, the heating is 75 complete, else it is partial */ 76int minHeatPercent; 77int maxHeatPercent; 78int cycleTime; /* seconds */ 79float hysteresis; 80enum {noParam, setDeltaT, setMinHeat, 81 setMaxHeat, setCycleTime, 82 setHysteresis} paramSetting=noParam; 83 84/* Program mode global data */ 85 86int hourLimit[3][4]; 87int minuteLimit[3][4]; 88float progTemp[3][4]; 89int progNum; 90enum {noProg, setProg0, setProg1, setProg2, 91 setWeek} progSetting=noProg; 92bool setHourLimit[4]= 93 {false, false, false, false}; 94bool setProgTemp[4]= 95 {false, false, false, false}; 96int setDayProg=0; 97int dayProg[7]; 98 99/* Time & date global data */ 100enum {none, setYear, setMonth, setDayOfMonth, 101 setHours, setMinutes, setSeconds} 102 timeSetting=none; 103DateTime current; 104int hour, minute, second; 105int year, month, dayOfMonth; 106 107enum 108{ 109 EEPROMId0, 110 EEPROMId1, 111 EEPROMId2, 112 EEPROMMode, 113 EEPROMSetPointMSB, 114 EEPROMSetPointLSB, 115 EEPROMFixSetPointMSB, 116 EEPROMFixSetPointLSB, 117 EEPROMDeltaTMSB, 118 EEPROMDeltaTLSB, 119 EEPROMMinHeatPercent, 120 EEPROMMaxHeatPercent, 121 EEPROMCycleTime, 122 EEPROMHysteresisMSB, 123 EEPROMHysteresisLSB, 124 EEPROMCorrDS18B20MSB, 125 EEPROMCorrDS18B20LSB, 126 EEPROMSleepDelay, 127 EEPROMTempUnit, 128 EEPROMLanguage, 129 EEPROMWeek 130}; 131int EEPROMProg=50; 132 133/* Class made to use an external EEPROM 134 (AT24Cxx) through functions compatible 135 with the EEPROM library */ 136 137class EEPROMI2C 138{ 139 byte i2cAddress; 140 int address; 141 byte data; 142 public : 143 byte read(unsigned int address); 144 void write(unsigned int address, 145 byte data); 146 void update(unsigned int address, 147 byte data); 148 EEPROMI2C(byte i2cAddress); 149}; 150 151byte EEPROMI2C::read(unsigned int address) 152{ 153 Wire.beginTransmission(i2cAddress); 154 Wire.write(highByte(address)); 155 Wire.write(lowByte(address)); 156 Wire.endTransmission(); 157 delay(10); 158 Wire.requestFrom(i2cAddress, 1); 159 delay(10); 160 data=Wire.read(); 161 delay(10); 162 return data; 163} 164 165void EEPROMI2C::write(unsigned int address, 166 byte data) 167{ 168 Wire.beginTransmission(i2cAddress); 169 Wire.write(highByte(address)); 170 Wire.write(lowByte(address)); 171 Wire.write(data); 172 delay(10); 173 Wire.endTransmission(); 174 delay(10); 175} 176 177void EEPROMI2C::update(unsigned int address, 178 byte data) 179{ 180 if(read(address)!=data) 181 write(address, data); 182} 183 184EEPROMI2C::EEPROMI2C(byte i2cAddress) 185{ 186 this->i2cAddress=i2cAddress; 187} 188 189EEPROMI2C EEPROM(0x50); 190 191class chronometer 192{ 193 unsigned long lastTime, actualTime; 194 public : 195 unsigned long elapsed; 196 void init(); // start the chronometer 197 void now(); // measure elapsed time since 198 // init 199 chronometer(); 200}; 201 202void chronometer::init() 203{ 204 actualTime=millis(); 205 lastTime=actualTime; 206} 207 208void chronometer::now() 209{ 210 actualTime=millis(); 211 if (actualTime<lastTime) 212 // Overflow of the millis counter 213 elapsed=(0xFFFFFFFFul-lastTime+ 214 actualTime); 215 else 216 elapsed=(actualTime-lastTime); 217} 218 219chronometer::chronometer() 220{ 221 actualTime=millis(); 222 lastTime=actualTime; 223} 224 225/* Functions to read rotary encoder and 226 generate events which feed the Finite 227 State Machine */ 228 229enum potentialEvents {noEvent, cwRot, ccwRot, 230 shortSwitchPress, 231 longSwitchPress, 232 longSwitchPressAndHeat, 233 timeOut} event; 234volatile enum potentialEvents 235 interruptEvent=noEvent; 236 237#define maxTime 30000 238#define longPressTime 2000 239chronometer eventChrono; 240 241void interruptRoutineReadEncoder(void) 242{ 243 noInterrupts(); 244 interruptEvent=noEvent; 245 if(digitalRead(rotaryBPin)==LOW) 246 interruptEvent=ccwRot; 247 else 248 interruptEvent=cwRot; 249 delayMicroseconds(1000); 250 if(digitalRead(rotaryAPin)==HIGH) 251 interruptEvent=noEvent; 252 interrupts(); 253} 254 255void rotaryEncoderRead(void) 256{ 257 unsigned long pressedSwitchDelay=0; 258 unsigned long pressedSwitchTime=0; 259 static bool longPressTreated=false; 260 261 event=interruptEvent; 262 interruptEvent=noEvent; 263 if(event!=noEvent) eventChrono.init(); 264 265 if(digitalRead(rotarySwitchPin)==LOW) 266 { 267 if (!longPressTreated) 268 { 269 pressedSwitchTime=millis(); 270 while(digitalRead(rotarySwitchPin)==LOW 271 && (millis()-pressedSwitchTime)< 272 longPressTime) 273 eventChrono.init(); 274 pressedSwitchDelay=millis()- 275 pressedSwitchTime; 276 if(pressedSwitchDelay>=longPressTime) 277 { 278 event=longSwitchPress; 279 if(mode!=stop) 280 event=longSwitchPressAndHeat; 281 longPressTreated=true; 282 } 283 else if(pressedSwitchDelay>50) 284 event=shortSwitchPress; 285 } 286 } 287 else 288 longPressTreated=false; 289 eventChrono.now(); 290 if(eventChrono.elapsed>maxTime) 291 event=timeOut; 292} 293 294/* Temperature measurement with DS18B20 */ 295 296void measureTempDS18B20(void) 297{ 298 if (device.IsValid()) 299 { 300 tempDS18B20=device. 301 GetTemperature<float>(bus); 302 if (!isnan(tempDS18B20)) 303 { 304 device.Update(bus); 305 tempDS18B20+=corrDS18B20; 306 tempOK=true; 307 } 308 else 309 { 310 device.Reset(); 311 tempOK=false; 312 } 313 } 314 else 315 { 316 if (bus.Discover(). 317 FindNextDevice(device) && 318 device.GetModelCode() == 319 MaximWire::DS18B20::MODEL_CODE) 320 { 321 device.Update(bus); 322 } 323 else 324 { 325 device.Reset(); 326 } 327 tempOK=false; 328 } 329} 330 331void measureTemp(bool wait) 332{ 333 static chronometer chronoTemp; 334 335 chronoTemp.now(); 336 if((chronoTemp.elapsed>5000) || !wait) 337 { 338 chronoTemp.init(); 339 measureTempDS18B20(); 340 if(tempOK) 341 { 342 temp=tempDS18B20; 343 if(temp<minTemp) minTemp=temp; 344 if(temp>maxTemp) maxTemp=temp; 345 } 346 } 347} 348 349/* Calendar functions */ 350 351int dayOfWeek(DateTime dt) 352{ 353 /* 0= monday, 1=tuesday... */ 354 return ((dt.unixtime()/86400L)+3)%7; 355} 356 357/******** Display functions *************/ 358 359void drawHeatSymbol(int x, int y) 360{ 361 for(int i=y; i<=y+10; i+=5) 362 { 363 u8g2.drawPixel(x, i); 364 u8g2.drawPixel(x+1, i+1); 365 u8g2.drawPixel(x+2, i+2); 366 u8g2.drawPixel(x+3, i+2); 367 u8g2.drawPixel(x+4, i+1); 368 u8g2.drawPixel(x+5, i); 369 u8g2.drawPixel(x+6, i); 370 u8g2.drawPixel(x+7, i+1); 371 u8g2.drawPixel(x+8, i+2); 372 } 373} 374 375void centerCursor(char * s, int y) 376{ 377 #define screenWidth 128 378 379 u8g2.setCursor((screenWidth- 380 u8g2.getStrWidth(s))/2, y); 381} 382 383float tempFormat(float temp) 384{ 385 if(tempUnit==Celsius) 386 return temp; 387 else 388 return (temp*9./5.)+32.; 389} 390 391char * deg(void) 392{ 393 if(tempUnit==Celsius) 394 return "\xb0""C"; 395 else 396 return "\xb0""F"; 397} 398 399void mainScreenEnglish() 400{ 401 char line[100]; 402 403 u8g2.setFont(u8g2_font_6x13_mf); 404 current=rtc.now(); 405 sprintf(line, "%02d/%02d/%d %2d:%02d:%02d", 406 current.month(), current.day(), 407 current.year(), current.hour(), 408 current.minute(), current.second()); 409 centerCursor(line, 9); 410 u8g2.print(line); 411 412 u8g2.setFont(u8g2_font_9x15B_mf); 413 u8g2.setCursor(0, 28); 414 if(tempOK) 415 u8g2.print(tempFormat(temp), 1); 416 else 417 u8g2.print("--.-"); 418 u8g2.print(deg()); 419 420 u8g2.setFont(u8g2_font_6x13_mf); 421 u8g2.setCursor(76, 28); 422 u8g2.print(percent); 423 u8g2.print(" %"); 424 425 sprintf(line, "Set point : --.--%cC", 426 char(176)); 427 centerCursor(line, 46); 428 u8g2.print("Set point : "); 429 if (changeSetPoint) u8g2.setDrawColor(0); 430 if(mode==stop) 431 u8g2.print("--.-"); 432 else 433 { 434 u8g2.setFont(u8g2_font_6x13B_mf); 435 u8g2.print(tempFormat(setPoint), 1); 436 u8g2.setFont(u8g2_font_6x13_mf); 437 } 438 u8g2.setDrawColor(1); 439 u8g2.print(deg()); 440 441 switch(mode) 442 { 443 case stop : 444 sprintf(line, "Mode : stop"); 445 break; 446 case fixed : 447 sprintf(line, "Mode : fixed"); 448 break; 449 case prog : 450 sprintf(line, "Mode : program"); 451 u8g2.setFont(u8g2_font_blipfest_07_tn); 452 u8g2.setCursor(118, 61); 453 u8g2.print( 454 dayProg[dayOfWeek(current)]+1); 455 u8g2.setFont(u8g2_font_6x13_mf); 456 break; 457 } 458 centerCursor(line, 61); 459 u8g2.print(line); 460 if(heat) drawHeatSymbol(115, 17); 461} 462 463void mainScreenFrench() 464{ 465 char line[100]; 466 467 u8g2.setFont(u8g2_font_6x13_mf); 468 current=rtc.now(); 469 sprintf(line, "%2d/%02d/%d %2d:%02d:%02d", 470 current.day(), current.month(), 471 current.year(), current.hour(), 472 current.minute(), current.second()); 473 centerCursor(line, 9); 474 u8g2.print(line); 475 476 u8g2.setFont(u8g2_font_9x15B_mf); 477 u8g2.setCursor(0, 28); 478 if(tempOK) 479 u8g2.print(tempFormat(temp), 1); 480 else 481 u8g2.print("--.-"); 482 u8g2.print(deg()); 483 484 u8g2.setFont(u8g2_font_6x13_mf); 485 u8g2.setCursor(76, 28); 486 u8g2.print(percent); 487 u8g2.print(" %"); 488 489 sprintf(line, "Consigne : --.--%cC", 490 char(176)); 491 centerCursor(line, 46); 492 u8g2.print("Consigne : "); 493 if (changeSetPoint) u8g2.setDrawColor(0); 494 if(mode==stop) 495 u8g2.print("--.-"); 496 else 497 { 498 u8g2.setFont(u8g2_font_6x13B_mf); 499 u8g2.print(tempFormat(setPoint), 1); 500 u8g2.setFont(u8g2_font_6x13_mf); 501 } 502 u8g2.setDrawColor(1); 503 u8g2.print(deg()); 504 505 switch(mode) 506 { 507 case stop : 508 sprintf(line, "Mode : arr%ct", 509 char(234)); 510 break; 511 case fixed : 512 sprintf(line, "Mode : fixe"); 513 break; 514 case prog : 515 sprintf(line, "Mode : programme"); 516 u8g2.setFont(u8g2_font_blipfest_07_tn); 517 u8g2.setCursor(118, 61); 518 u8g2.print( 519 dayProg[dayOfWeek(current)]+1); 520 u8g2.setFont(u8g2_font_6x13_mf); 521 break; 522 } 523 centerCursor(line, 61); 524 u8g2.print(line); 525 if(heat) drawHeatSymbol(115, 17); 526} 527 528void mainScreen() 529{ 530 if(!displayActive) return; 531 u8g2.clearBuffer(); 532 switch(language) 533 { 534 case english : 535 mainScreenEnglish(); 536 break; 537 case french : 538 mainScreenFrench(); 539 break; 540 } 541 u8g2.sendBuffer(); 542} 543 544void modeScreenEnglish(void) 545{ 546 char stringToDisplay[20]; 547 548 u8g2.setFont(u8g2_font_6x13_mf); 549 sprintf(stringToDisplay, "Mode"); 550 centerCursor(stringToDisplay, 20); 551 u8g2.print(stringToDisplay); 552 u8g2.setFont(u8g2_font_9x15B_mf); 553 554 if(changeMode) u8g2.setDrawColor(0); 555 switch(mode) 556 { 557 case stop : 558 sprintf(stringToDisplay, "Stop"); 559 break; 560 case fixed : 561 sprintf(stringToDisplay, "Fixed"); 562 break; 563 case prog : 564 sprintf(stringToDisplay, "Program"); 565 break; 566 } 567 centerCursor(stringToDisplay, 40); 568 u8g2.print(stringToDisplay); 569 u8g2.setDrawColor(1); 570} 571 572void modeScreenFrench(void) 573{ 574 char stringToDisplay[20]; 575 576 u8g2.setFont(u8g2_font_6x13_mf); 577 sprintf(stringToDisplay, "Mode"); 578 centerCursor(stringToDisplay, 20); 579 u8g2.print(stringToDisplay); 580 u8g2.setFont(u8g2_font_9x15B_mf); 581 582 if(changeMode) u8g2.setDrawColor(0); 583 switch(mode) 584 { 585 case stop : 586 sprintf(stringToDisplay, "Arr%ct", 587 char(234)); 588 break; 589 case fixed : 590 sprintf(stringToDisplay, "Fixe"); 591 break; 592 case prog : 593 sprintf(stringToDisplay, "Programme"); 594 break; 595 } 596 centerCursor(stringToDisplay, 40); 597 u8g2.print(stringToDisplay); 598 u8g2.setDrawColor(1); 599} 600 601void modeScreen(void) 602{ 603 if(!displayActive) return; 604 u8g2.clearBuffer(); 605 switch(language) 606 { 607 case english : 608 modeScreenEnglish(); 609 break; 610 case french : 611 modeScreenFrench(); 612 break; 613 } 614 u8g2.sendBuffer(); 615} 616 617void progScreen(void) 618{ 619 char line[20]; 620 621 if(!displayActive) return; 622 u8g2.clearBuffer(); 623 u8g2.setDrawColor(1); 624 u8g2.setFont(u8g2_font_6x13_mf); 625 switch(language) 626 { 627 case english : 628 strcpy(line, "Program"); 629 break; 630 case french : 631 strcpy(line, "Programme"); 632 break; 633 } 634 centerCursor(line, 11); 635 u8g2.print(line); 636 637 u8g2.setFont(u8g2_font_6x13B_mf); 638 u8g2.setCursor(10, 30); 639 if(progSetting==setProg0) 640 u8g2.setDrawColor(0); 641 u8g2.print("Prog 1"); 642 u8g2.setDrawColor(1); 643 u8g2.setCursor(10, 50); 644 if(progSetting==setProg1) 645 u8g2.setDrawColor(0); 646 u8g2.print("Prog 2"); 647 u8g2.setDrawColor(1); 648 u8g2.setCursor(70, 30); 649 if(progSetting==setProg2) 650 u8g2.setDrawColor(0); 651 u8g2.print("Prog 3"); 652 u8g2.setDrawColor(1); 653 u8g2.setCursor(70, 50); 654 if(progSetting==setWeek) 655 u8g2.setDrawColor(0); 656 switch(language) 657 { 658 case english : 659 u8g2.print("Week"); 660 break; 661 case french : 662 u8g2.print("Semaine"); 663 break; 664 } 665 666 u8g2.setFont(u8g2_font_6x13_mf); 667 u8g2.setDrawColor(1); 668 u8g2.sendBuffer(); 669} 670 671void dailyProgScreen(void) 672{ 673 char line[20]; 674 675 if(!displayActive) return; 676 u8g2.clearBuffer(); 677 u8g2.setDrawColor(1); 678 u8g2.setFont(u8g2_font_6x13_mf); 679 680 switch(language) 681 { 682 case english : 683 sprintf(line, "Prog. %d", progNum+1); 684 break; 685 case french : 686 sprintf(line, "Prog. %d", progNum+1); 687 break; 688 } 689 centerCursor(line, 11); 690 u8g2.print(line); 691 for(int i=0; i<4; i++) 692 { 693 u8g2.setCursor(0, 12*(i+2)+1); 694 if(setHourLimit[i]) u8g2.setDrawColor(0); 695 u8g2.setFont(u8g2_font_6x13B_mf); 696 if(hourLimit[progNum][i]<10) 697 u8g2.print(" "); 698 u8g2.print(hourLimit[progNum][i]); 699 u8g2.print(":"); 700 if(minuteLimit[progNum][i]<10) 701 u8g2.print("0"); 702 u8g2.print(minuteLimit[progNum][i]); 703 u8g2.setFont(u8g2_font_6x13_mf); 704 u8g2.setDrawColor(1); 705 u8g2.print(" -> "); 706 707 if(setHourLimit[(i+1)%4]) 708 u8g2.setDrawColor(0); 709 u8g2.setFont(u8g2_font_6x13B_mf); 710 if(hourLimit[progNum][(i+1)%4]<10) 711 u8g2.print(" "); 712 u8g2.print(hourLimit[progNum][(i+1)%4]); 713 u8g2.print(":"); 714 if(minuteLimit[progNum][(i+1)%4]<10) 715 u8g2.print("0"); 716 u8g2.print(minuteLimit[progNum][(i+1)%4]); 717 u8g2.setDrawColor(1); 718 u8g2.print(" "); 719 720 if(setProgTemp[i]) u8g2.setDrawColor(0); 721 u8g2.print(tempFormat 722 (progTemp[progNum][i]), 1); 723 u8g2.setFont(u8g2_font_6x13_mf); 724 u8g2.setDrawColor(1); 725 u8g2.print(deg()); 726 } 727 u8g2.sendBuffer(); 728} 729 730void weekProgScreenEnglish(void) 731{ 732 char line[20]; 733 734 strcpy(line, "Week"); 735 centerCursor(line, 11); 736 u8g2.print(line); 737 738 for(int i=0; i<7; i++) 739 { 740 u8g2.setCursor((i<4)? 0 : 80, 741 (i&3)*12+25); 742 switch(i) 743 { 744 case 0: 745 u8g2.print("Mon: "); 746 break; 747 case 1: 748 u8g2.print("Tue: "); 749 break; 750 case 2: 751 u8g2.print("Wed: "); 752 break; 753 case 3: 754 u8g2.print("Thu: "); 755 break; 756 case 4: 757 u8g2.print("Fri: "); 758 break; 759 case 5: 760 u8g2.print("Sat: "); 761 break; 762 case 6: 763 u8g2.print("Sun: "); 764 break; 765 } 766 u8g2.setFont(u8g2_font_6x13B_mf); 767 if(i==setDayProg) 768 u8g2.setDrawColor(0); 769 u8g2.print(dayProg[i]+1); 770 u8g2.setDrawColor(1); 771 u8g2.setFont(u8g2_font_6x13_mf); 772 } 773} 774 775void weekProgScreenFrench(void) 776{ 777 char line[20]; 778 779 strcpy(line, "Semaine"); 780 centerCursor(line, 11); 781 u8g2.print(line); 782 783 for(int i=0; i<7; i++) 784 { 785 u8g2.setCursor((i<4)? 0 : 80, 786 (i&3)*12+25); 787 switch(i) 788 { 789 case 0: 790 u8g2.print("Lun : "); 791 break; 792 case 1: 793 u8g2.print("Mar : "); 794 break; 795 case 2: 796 u8g2.print("Mer : "); 797 break; 798 case 3: 799 u8g2.print("Jeu : "); 800 break; 801 case 4: 802 u8g2.print("Ven : "); 803 break; 804 case 5: 805 u8g2.print("Sam : "); 806 break; 807 case 6: 808 u8g2.print("Dim : "); 809 break; 810 } 811 u8g2.setFont(u8g2_font_6x13B_mf); 812 if(i==setDayProg) 813 u8g2.setDrawColor(0); 814 u8g2.print(dayProg[i]+1); 815 u8g2.setDrawColor(1); 816 u8g2.setFont(u8g2_font_6x13_mf); 817 } 818} 819 820void weekProgScreen(void) 821{ 822 if(!displayActive) return; 823 u8g2.clearBuffer(); 824 u8g2.setDrawColor(1); 825 u8g2.setFont(u8g2_font_6x13_mf); 826 switch(language) 827 { 828 case english : 829 weekProgScreenEnglish(); 830 break; 831 case french : 832 weekProgScreenFrench(); 833 break; 834 } 835 u8g2.sendBuffer(); 836} 837 838void heatingBehaviourScreenEnglish(void) 839{ 840 char line[30]; 841 842 u8g2.setFont(u8g2_font_6x13_mf); 843 strcpy(line, "Heating law"); 844 centerCursor(line, 10); 845 u8g2.print(line); 846 u8g2.setCursor(0, 23); 847 u8g2.print("Hysteresis : "); 848 if(paramSetting==setHysteresis) 849 u8g2.setDrawColor(0); 850 u8g2.setFont(u8g2_font_6x13B_mf); 851 if(tempUnit==Celsius) 852 u8g2.print(hysteresis, 1); 853 else 854 u8g2.print(hysteresis*9.0/5.0, 1); 855 u8g2.setFont(u8g2_font_6x13_mf); 856 u8g2.setDrawColor(1); 857 u8g2.print(deg()); 858 u8g2.setCursor(0, 36); 859 u8g2.print("Delta T : "); 860 if(paramSetting==setDeltaT) 861 u8g2.setDrawColor(0); 862 u8g2.setFont(u8g2_font_6x13B_mf); 863 if(tempUnit==Celsius) 864 u8g2.print(deltaT, 1); 865 else 866 u8g2.print(deltaT*9.0/5.0, 1); 867 u8g2.setFont(u8g2_font_6x13_mf); 868 u8g2.setDrawColor(1); 869 u8g2.print(deg()); 870 u8g2.setCursor(0, 49); 871 u8g2.print("Min : "); 872 if(paramSetting==setMinHeat) 873 u8g2.setDrawColor(0); 874 u8g2.setFont(u8g2_font_6x13B_mf); 875 u8g2.print(minHeatPercent); 876 u8g2.setFont(u8g2_font_6x13_mf); 877 u8g2.setDrawColor(1); 878 u8g2.print(" % Max : "); 879 if(paramSetting==setMaxHeat) 880 u8g2.setDrawColor(0); 881 u8g2.setFont(u8g2_font_6x13B_mf); 882 u8g2.print(maxHeatPercent); 883 u8g2.setFont(u8g2_font_6x13_mf); 884 u8g2.setDrawColor(1); 885 u8g2.print(" %"); 886 u8g2.setCursor(0, 62); 887 u8g2.print("Cycle : "); 888 if(paramSetting==setCycleTime) 889 u8g2.setDrawColor(0); 890 u8g2.setFont(u8g2_font_6x13B_mf); 891 u8g2.print(cycleTime); 892 u8g2.setFont(u8g2_font_6x13_mf); 893 u8g2.setDrawColor(1); 894 u8g2.print(" s"); 895} 896 897void heatingBehaviourScreenFrench(void) 898{ 899 char line[20]; 900 901 u8g2.setFont(u8g2_font_6x13_mf); 902 strcpy(line, "Courbe de chauffe"); 903 centerCursor(line, 10); 904 u8g2.print(line); 905 u8g2.setCursor(0, 23); 906 u8g2.print("Hysteresis : "); 907 if(paramSetting==setHysteresis) 908 u8g2.setDrawColor(0); 909 u8g2.setFont(u8g2_font_6x13B_mf); 910 if(tempUnit==Celsius) 911 u8g2.print(hysteresis, 1); 912 else 913 u8g2.print(hysteresis*9.0/5.0, 1); 914 u8g2.setFont(u8g2_font_6x13_mf); 915 u8g2.setDrawColor(1); 916 u8g2.print(deg()); 917 u8g2.setCursor(0, 36); 918 u8g2.print("Delta T : "); 919 if(paramSetting==setDeltaT) 920 u8g2.setDrawColor(0); 921 u8g2.setFont(u8g2_font_6x13B_mf); 922 if(tempUnit==Celsius) 923 u8g2.print(deltaT, 1); 924 else 925 u8g2.print(deltaT*9.0/5.0, 1); 926 u8g2.setFont(u8g2_font_6x13_mf); 927 u8g2.setDrawColor(1); 928 u8g2.print(deg()); 929 u8g2.setCursor(0, 49); 930 u8g2.print("Min : "); 931 if(paramSetting==setMinHeat) 932 u8g2.setDrawColor(0); 933 u8g2.setFont(u8g2_font_6x13B_mf); 934 u8g2.print(minHeatPercent); 935 u8g2.setFont(u8g2_font_6x13_mf); 936 u8g2.setDrawColor(1); 937 u8g2.print(" % Max : "); 938 if(paramSetting==setMaxHeat) 939 u8g2.setDrawColor(0); 940 u8g2.setFont(u8g2_font_6x13B_mf); 941 u8g2.print(maxHeatPercent); 942 u8g2.setFont(u8g2_font_6x13_mf); 943 u8g2.setDrawColor(1); 944 u8g2.print(" %"); 945 u8g2.setCursor(0, 62); 946 u8g2.print("Cycle : "); 947 if(paramSetting==setCycleTime) 948 u8g2.setDrawColor(0); 949 u8g2.setFont(u8g2_font_6x13B_mf); 950 u8g2.print(cycleTime); 951 u8g2.setFont(u8g2_font_6x13_mf); 952 u8g2.setDrawColor(1); 953 u8g2.print(" s"); 954} 955 956void heatingBehaviourScreen(void) 957{ 958 if(!displayActive) return; 959 u8g2.clearBuffer(); 960 switch(language) 961 { 962 case english : 963 heatingBehaviourScreenEnglish(); 964 break; 965 case french : 966 heatingBehaviourScreenFrench(); 967 break; 968 } 969 u8g2.sendBuffer(); 970} 971 972void systemScreenEnglish(void) 973{ 974 char line[20]; 975 976 u8g2.setFont(u8g2_font_7x13_mf); 977 strcpy(line, "System"); 978 centerCursor(line, 10); 979 u8g2.print(line); 980 981 u8g2.setCursor(0, 25); 982 u8g2.print("Connected : "); 983 if(connected) 984 u8g2.print("yes"); 985 else 986 u8g2.print("no"); 987 988 u8g2.setCursor(0, 40); 989 u8g2.print("Battery : "); 990 u8g2.print((float)analogRead(battPin)* 991 3.3*(47+220)/47/1023, 1); 992 u8g2.print(" V"); 993 994 u8g2.setCursor(0, 58); 995 u8g2.setFont(u8g2_font_7x13B_mf); 996 u8g2.print("Settings "); 997 u8g2.setFont(u8g2_font_6x13_mf); 998 u8g2.print("(press 3s)"); 999 u8g2.setFont(u8g2_font_7x13_mf); 1000} 1001 1002void systemScreenFrench(void) 1003{ 1004 char line[20]; 1005 1006 u8g2.setFont(u8g2_font_7x13_mf); 1007 strcpy(line, "Syst\xE8me"); 1008 centerCursor(line, 10); 1009 u8g2.print(line); 1010 1011 u8g2.setCursor(0, 25); 1012 u8g2.print("Connect\xe9 : "); 1013 if(connected) 1014 u8g2.print("oui"); 1015 else 1016 u8g2.print("non"); 1017 1018 u8g2.setCursor(0, 40); 1019 u8g2.print("Pile : "); 1020 u8g2.print((float)analogRead(battPin)* 1021 3.3*(47+220)/47/1023, 1); 1022 u8g2.print(" V"); 1023 1024 u8g2.setCursor(0, 58); 1025 u8g2.setFont(u8g2_font_7x13B_mf); 1026 u8g2.print("R\xe9glages "); 1027 u8g2.setFont(u8g2_font_6x13_mf); 1028 u8g2.print("(appui 3s)"); 1029 u8g2.setFont(u8g2_font_7x13_mf); 1030} 1031 1032void systemScreen(void) 1033{ 1034 if(!displayActive) return; 1035 u8g2.clearBuffer(); 1036 switch(language) 1037 { 1038 case english : 1039 systemScreenEnglish(); 1040 break; 1041 case french : 1042 systemScreenFrench(); 1043 break; 1044 } 1045 u8g2.sendBuffer(); 1046} 1047 1048void settingsScreenEnglish(void) 1049{ 1050 char line[30]; 1051 1052 u8g2.setFont(u8g2_font_7x13_mf); 1053 strcpy(line, "Settings"); 1054 centerCursor(line, 10); 1055 u8g2.print(line); 1056 1057 u8g2.setCursor(0, 23); 1058 u8g2.print("Sleep : "); 1059 if(settingsSet==setSleepDelay) 1060 u8g2.setDrawColor(0); 1061 u8g2.setFont(u8g2_font_7x13B_mf); 1062 if(sleepDelay>0) 1063 { 1064 u8g2.print(sleepDelay); 1065 u8g2.setFont(u8g2_font_7x13_mf); 1066 u8g2.setDrawColor(1); 1067 u8g2.print(" s"); 1068 } 1069 else 1070 { 1071 u8g2.print("no"); 1072 u8g2.setFont(u8g2_font_7x13_mf); 1073 u8g2.setDrawColor(1); 1074 } 1075 1076 u8g2.setCursor(0, 36); 1077 u8g2.print("Temp. unit : "); 1078 if(settingsSet==setTempUnit) 1079 u8g2.setDrawColor(0); 1080 u8g2.setFont(u8g2_font_7x13B_mf); 1081 u8g2.print(deg()); 1082 u8g2.setFont(u8g2_font_7x13_mf); 1083 u8g2.setDrawColor(1); 1084 1085 u8g2.setCursor(0, 49); 1086 u8g2.print("T\xb0 corr. : "); 1087 if(settingsSet==setDS18B20Corr) 1088 u8g2.setDrawColor(0); 1089 u8g2.setFont(u8g2_font_7x13B_mf); 1090 if(tempUnit==Celsius) 1091 u8g2.print(corrDS18B20, 1); 1092 else 1093 u8g2.print(corrDS18B20*9.0/5.0, 1); 1094 u8g2.setFont(u8g2_font_7x13_mf); 1095 u8g2.setDrawColor(1); 1096 u8g2.print(deg()); 1097 1098 u8g2.setCursor(0, 62); 1099 u8g2.print("Lang. : "); 1100 if(settingsSet==setLanguage) 1101 u8g2.setDrawColor(0); 1102 u8g2.setFont(u8g2_font_7x13B_mf); 1103 u8g2.print("english"); 1104 u8g2.setFont(u8g2_font_7x13_mf); 1105 u8g2.setDrawColor(1); 1106} 1107 1108void settingsScreenFrench(void) 1109{ 1110 char line[30]; 1111 1112 u8g2.setFont(u8g2_font_7x13_mf); 1113 strcpy(line, "R\xe9glages"); 1114 centerCursor(line, 10); 1115 u8g2.print(line); 1116 1117 u8g2.setCursor(0, 23); 1118 u8g2.print("Veille : "); 1119 if(settingsSet==setSleepDelay) 1120 u8g2.setDrawColor(0); 1121 u8g2.setFont(u8g2_font_7x13B_mf); 1122 if(sleepDelay>0) 1123 { 1124 u8g2.print(sleepDelay); 1125 u8g2.setFont(u8g2_font_7x13_mf); 1126 u8g2.setDrawColor(1); 1127 u8g2.print(" s"); 1128 } 1129 else 1130 { 1131 u8g2.print("non"); 1132 u8g2.setFont(u8g2_font_7x13_mf); 1133 u8g2.setDrawColor(1); 1134 } 1135 1136 u8g2.setCursor(0, 36); 1137 u8g2.print("Unit\xe9 T : "); 1138 if(settingsSet==setTempUnit) 1139 u8g2.setDrawColor(0); 1140 u8g2.setFont(u8g2_font_7x13B_mf); 1141 u8g2.print(deg()); 1142 u8g2.setFont(u8g2_font_7x13_mf); 1143 u8g2.setDrawColor(1); 1144 1145 u8g2.setCursor(0, 49); 1146 u8g2.print("Corr. T\xb0 : "); 1147 if(settingsSet==setDS18B20Corr) 1148 u8g2.setDrawColor(0); 1149 u8g2.setFont(u8g2_font_7x13B_mf); 1150 if(tempUnit==Celsius) 1151 u8g2.print(corrDS18B20, 1); 1152 else 1153 u8g2.print(corrDS18B20*9.0/5.0, 1); 1154 u8g2.setFont(u8g2_font_7x13_mf); 1155 u8g2.setDrawColor(1); 1156 u8g2.print(deg()); 1157 1158 u8g2.setCursor(0, 62); 1159 u8g2.print("Langue : "); 1160 if(settingsSet==setLanguage) 1161 u8g2.setDrawColor(0); 1162 u8g2.setFont(u8g2_font_7x13B_mf); 1163 u8g2.print("fran\xe7""ais"); 1164 u8g2.setFont(u8g2_font_7x13_mf); 1165 u8g2.setDrawColor(1); 1166} 1167 1168void settingsScreen(void) 1169{ 1170 if(!displayActive) return; 1171 u8g2.clearBuffer(); 1172 switch(language) 1173 { 1174 case english : 1175 settingsScreenEnglish(); 1176 break; 1177 case french : 1178 settingsScreenFrench(); 1179 break; 1180 } 1181 u8g2.sendBuffer(); 1182} 1183 1184void timeDateScreenEnglish(void) 1185{ 1186 char stringToDisplay[25]; 1187 char lengthString[25]; 1188 1189 u8g2.setDrawColor(1); 1190 u8g2.setFont(u8g2_font_6x13_mf); 1191 switch(dayOfWeek(DateTime(year, month, 1192 dayOfMonth))) 1193 { 1194 case 0 : 1195 sprintf(stringToDisplay, "Monday"); 1196 break; 1197 case 1 : 1198 sprintf(stringToDisplay, "Tuesday"); 1199 break; 1200 case 2 : 1201 sprintf(stringToDisplay, "Wednesday"); 1202 break; 1203 case 3 : 1204 sprintf(stringToDisplay, "Thursday"); 1205 break; 1206 case 4 : 1207 sprintf(stringToDisplay, "Friday"); 1208 break; 1209 case 5 : 1210 sprintf(stringToDisplay, "Saturday"); 1211 break; 1212 case 6 : 1213 sprintf(stringToDisplay, "Sunday"); 1214 break; 1215 } 1216 centerCursor(stringToDisplay, 45); 1217 u8g2.print(stringToDisplay); 1218 1219 u8g2.setFont(u8g2_font_9x15B_mf); 1220 sprintf(stringToDisplay, "%d", dayOfMonth); 1221 centerCursor(stringToDisplay, 29); 1222 if(timeSetting==setDayOfMonth) 1223 u8g2.setDrawColor(0); 1224 else u8g2.setDrawColor(1); 1225 u8g2.print(stringToDisplay); 1226 1227 u8g2.setFont(u8g2_font_6x13_mf); 1228 switch(month) 1229 { 1230 case 1 : 1231 sprintf(stringToDisplay, "January"); 1232 break; 1233 case 2 : 1234 sprintf(stringToDisplay, "February"); 1235 break; 1236 case 3 : 1237 sprintf(stringToDisplay, "March"); 1238 break; 1239 case 4 : 1240 sprintf(stringToDisplay, "April"); 1241 break; 1242 case 5 : 1243 sprintf(stringToDisplay, "May"); 1244 break; 1245 case 6 : 1246 sprintf(stringToDisplay, "June"); 1247 break; 1248 case 7 : 1249 sprintf(stringToDisplay, "July"); 1250 break; 1251 case 8 : 1252 sprintf(stringToDisplay, "August"); 1253 break; 1254 case 9 : 1255 sprintf(stringToDisplay, "September"); 1256 break; 1257 case 10 : 1258 sprintf(stringToDisplay, "October"); 1259 break; 1260 case 11 : 1261 sprintf(stringToDisplay, "November"); 1262 break; 1263 case 12 : 1264 sprintf(stringToDisplay, "December"); 1265 break; 1266 } 1267 strcpy(lengthString, stringToDisplay); 1268 strcat(lengthString, " 2022"); 1269 centerCursor(lengthString, 10); 1270 if(timeSetting==setMonth) 1271 u8g2.setDrawColor(0); 1272 else u8g2.setDrawColor(1); 1273 u8g2.print(stringToDisplay); 1274 u8g2.setDrawColor(1); 1275 u8g2.print(" "); 1276 if(timeSetting==setYear) 1277 u8g2.setDrawColor(0); 1278 else u8g2.setDrawColor(1); 1279 u8g2.print(year); 1280 1281 u8g2.setFont(u8g2_font_9x15B_mf); 1282 sprintf(lengthString, "%d:%02d:%02d", hour, 1283 minute, second); 1284 centerCursor(lengthString, 63); 1285 if(timeSetting==setHours) 1286 u8g2.setDrawColor(0); 1287 else u8g2.setDrawColor(1); 1288 u8g2.print(hour); 1289 u8g2.setDrawColor(1); 1290 u8g2.print(":"); 1291 sprintf(stringToDisplay, "%02d", minute); 1292 if(timeSetting==setMinutes) 1293 u8g2.setDrawColor(0); 1294 else u8g2.setDrawColor(1); 1295 u8g2.print(stringToDisplay); 1296 u8g2.setDrawColor(1); 1297 u8g2.print(":"); 1298 sprintf(stringToDisplay, "%02d", second); 1299 if(timeSetting==setSeconds) 1300 u8g2.setDrawColor(0); 1301 else u8g2.setDrawColor(1); 1302 u8g2.print(stringToDisplay); 1303} 1304 1305void timeDateScreenFrench(void) 1306{ 1307 char stringToDisplay[25]; 1308 char lengthString[25]; 1309 1310 u8g2.setDrawColor(1); 1311 u8g2.setFont(u8g2_font_6x13_mf); 1312 switch(dayOfWeek(DateTime(year, month, 1313 dayOfMonth))) 1314 { 1315 case 0 : 1316 sprintf(stringToDisplay, "Lundi"); 1317 break; 1318 case 1 : 1319 sprintf(stringToDisplay, "Mardi"); 1320 break; 1321 case 2 : 1322 sprintf(stringToDisplay, "Mercredi"); 1323 break; 1324 case 3 : 1325 sprintf(stringToDisplay, "Jeudi"); 1326 break; 1327 case 4 : 1328 sprintf(stringToDisplay, "Vendredi"); 1329 break; 1330 case 5 : 1331 sprintf(stringToDisplay, "Samedi"); 1332 break; 1333 case 6 : 1334 sprintf(stringToDisplay, "Dimanche"); 1335 break; 1336 } 1337 centerCursor(stringToDisplay, 10); 1338 u8g2.print(stringToDisplay); 1339 1340 u8g2.setFont(u8g2_font_9x15B_mf); 1341 sprintf(stringToDisplay, "%d", dayOfMonth); 1342 centerCursor(stringToDisplay, 29); 1343 if(timeSetting==setDayOfMonth) 1344 u8g2.setDrawColor(0); 1345 else u8g2.setDrawColor(1); 1346 u8g2.print(stringToDisplay); 1347 u8g2.setFont(u8g2_font_6x13_mf); 1348 switch(month) 1349 { 1350 case 1 : 1351 sprintf(stringToDisplay, "janvier"); 1352 break; 1353 case 2 : 1354 sprintf(stringToDisplay, "f%cvrier", 1355 char(233)); 1356 break; 1357 case 3 : 1358 sprintf(stringToDisplay, "mars"); 1359 break; 1360 case 4 : 1361 sprintf(stringToDisplay, "avril"); 1362 break; 1363 case 5 : 1364 sprintf(stringToDisplay, "mai"); 1365 break; 1366 case 6 : 1367 sprintf(stringToDisplay, "juin"); 1368 break; 1369 case 7 : 1370 sprintf(stringToDisplay, "juillet"); 1371 break; 1372 case 8 : 1373 sprintf(stringToDisplay, "ao%ct", 1374 char(251)); 1375 break; 1376 case 9 : 1377 sprintf(stringToDisplay, "septembre"); 1378 break; 1379 case 10 : 1380 sprintf(stringToDisplay, "octobre"); 1381 break; 1382 case 11 : 1383 sprintf(stringToDisplay, "novembre"); 1384 break; 1385 case 12 : 1386 sprintf(stringToDisplay, "d%ccembre", 1387 char(233)); 1388 break; 1389 } 1390 strcpy(lengthString, stringToDisplay); 1391 strcat(lengthString, " 2022"); 1392 centerCursor(lengthString, 45); 1393 if(timeSetting==setMonth) 1394 u8g2.setDrawColor(0); 1395 else u8g2.setDrawColor(1); 1396 u8g2.print(stringToDisplay); 1397 u8g2.setDrawColor(1); 1398 u8g2.print(" "); 1399 if(timeSetting==setYear) 1400 u8g2.setDrawColor(0); 1401 else u8g2.setDrawColor(1); 1402 u8g2.print(year); 1403 1404 u8g2.setFont(u8g2_font_9x15B_mf); 1405 sprintf(lengthString, "%d:%02d:%02d", hour, 1406 minute, second); 1407 centerCursor(lengthString, 63); 1408 if(timeSetting==setHours) 1409 u8g2.setDrawColor(0); 1410 else u8g2.setDrawColor(1); 1411 u8g2.print(hour); 1412 u8g2.setDrawColor(1); 1413 u8g2.print(":"); 1414 sprintf(stringToDisplay, "%02d", minute); 1415 if(timeSetting==setMinutes) 1416 u8g2.setDrawColor(0); 1417 else u8g2.setDrawColor(1); 1418 u8g2.print(stringToDisplay); 1419 u8g2.setDrawColor(1); 1420 u8g2.print(":"); 1421 sprintf(stringToDisplay, "%02d", second); 1422 if(timeSetting==setSeconds) 1423 u8g2.setDrawColor(0); 1424 else u8g2.setDrawColor(1); 1425 u8g2.print(stringToDisplay); 1426} 1427 1428void timeDateScreen(void) 1429{ 1430 if(!displayActive) return; 1431 u8g2.clearBuffer(); 1432 switch(language) 1433 { 1434 case english : 1435 timeDateScreenEnglish(); 1436 break; 1437 case french : 1438 timeDateScreenFrench(); 1439 break; 1440 } 1441 u8g2.sendBuffer(); 1442} 1443 1444void temperatureScreen(void) 1445{ 1446 char line[20]; 1447 1448 if(!displayActive) return; 1449 u8g2.clearBuffer(); 1450 u8g2.setFont(u8g2_font_logisoso26_tf); 1451 strcpy(line, "19.0dC"); 1452 centerCursor(line, 40); 1453 if(tempOK) 1454 u8g2.print(tempFormat(temp), 1); 1455 else 1456 u8g2.print("--.-"); 1457 u8g2.print(deg()); 1458 u8g2.setFont(u8g2_font_6x13_mf); 1459 u8g2.setCursor(0, 63); 1460 u8g2.print("Min : "); 1461 u8g2.print(tempFormat(minTemp), 1), 1462 u8g2.print(" Max : "); 1463 u8g2.print(tempFormat(maxTemp), 1); 1464 u8g2.sendBuffer(); 1465} 1466 1467/* Wake detection function to spare 1468 battery when rotary encoder is not 1469 used */ 1470 1471void wakeDetection(void) 1472{ 1473 eventChrono.now(); 1474 if((eventChrono.elapsed< 1475 (unsigned long)sleepDelay*1000) || 1476 (sleepDelay==0)) 1477 { 1478 u8g2.setPowerSave(0); 1479 displayActive=true; 1480 } 1481 else 1482 { 1483 u8g2.setPowerSave(1); 1484 displayActive=false; 1485 } 1486} 1487 1488/* Heating control functions */ 1489 1490void heatControl(void) 1491{ 1492 static chronometer heatChrono; 1493 1494/* 1495________________ 1496 | 1497 MaxHeatPercent | 1498 .\ 1499 . \ 1500 . \ 1501 . \ 1502 . \ 1503 . \ 1504 . \ hysteresis 1505 MinHeatPercent . \________ 1506 . |XXXXXX| 1507 . deltaT |XXXXXX| 1508_________________________|XXXXXX|________\ t° 1509 setPoint / 1510 */ 1511 1512 heatChrono.now(); 1513 if(heatChrono.elapsed>= 1514 (unsigned long)cycleTime*1000) 1515 heatChrono.init(); 1516 heat=false; 1517 if((mode==stop) || !tempOK) percent=0; 1518 else 1519 { 1520 if(temp>setPoint+hysteresis) percent=0; 1521 else if(temp <= setPoint-deltaT) 1522 percent=100; 1523 else if(temp<=setPoint) 1524 { 1525 percent=minHeatPercent+ 1526 (maxHeatPercent-minHeatPercent) / 1527 deltaT * (setPoint-temp); 1528 } 1529 if(percent>maxHeatPercent) heat=true; 1530 else if(percent>=minHeatPercent) 1531 if(heatChrono.elapsed< 1532 (unsigned long)cycleTime * percent * 1533 10) /* percent of milliseconds */ 1534 heat=true; 1535 } 1536} 1537 1538void setPointControl(void) 1539{ 1540 int progNum; 1541 if(mode==prog) 1542 { 1543 current=rtc.now(); 1544 if(current.second()==0) 1545 { 1546 progNum=dayProg[dayOfWeek(current)]; 1547 for(int i=0; i<4; i++) 1548 { 1549 if(current.hour()== 1550 hourLimit[progNum][i] && 1551 current.minute()== 1552 minuteLimit[progNum][i]) 1553 setPoint=progTemp[progNum][i]; 1554 } 1555 } 1556 } 1557} 1558 1559void setPointInit(void) 1560{ 1561 int currentMinutes, progNum; 1562 1563 current=rtc.now();; 1564 currentMinutes=current.hour()*60+ 1565 current.minute(); 1566 progNum=dayProg[dayOfWeek(current)]; 1567 1568 for(int i=0; i<=3; i++) 1569 { 1570/* Test if noon is between the two limits */ 1571 if(hourLimit[progNum][i]*60+ 1572 minuteLimit[progNum][i]< 1573 hourLimit[progNum][(i+1)%4]*60+ 1574 minuteLimit[progNum][(i+1)%4]) 1575 { 1576 if(currentMinutes>= 1577 hourLimit[progNum][i]*60+ 1578 minuteLimit[progNum][i] && 1579 currentMinutes< 1580 hourLimit[progNum][(i+1)%4]*60+ 1581 minuteLimit[progNum][(i+1)%4]) 1582 setPoint=progTemp[progNum][i]; 1583 } 1584 else 1585 { 1586 if(currentMinutes>= 1587 hourLimit[progNum][i]*60+ 1588 minuteLimit[progNum][i] || 1589 currentMinutes< 1590 hourLimit[progNum][(i+1)%4]*60+ 1591 minuteLimit[progNum][(i+1)%4]) 1592 setPoint=progTemp[progNum][i]; 1593 } 1594 } 1595} 1596 1597/* BLE connection functions */ 1598 1599int connectRemoteHeat(void) 1600{ 1601 unsigned long tOut=500; 1602 chronometer connectChrono; 1603 1604 connected=false; 1605 BLE.begin(); 1606 connectChrono.init(); 1607 do 1608 { 1609 connectChrono.now(); 1610 } 1611 while((!BLE.scanForUuid 1612 (deviceAddress)) && 1613 connectChrono.elapsed<tOut); 1614 if(connectChrono.elapsed>=tOut) 1615 { 1616 BLE.stopScan(); 1617 return 1; 1618 } 1619 1620 connectChrono.init(); 1621 do 1622 { 1623 connectChrono.now(); 1624 } 1625 while((!(peripheral=BLE.available())) && 1626 connectChrono.elapsed<tOut); 1627 BLE.stopScan(); 1628 if(connectChrono.elapsed>=tOut) 1629 return 2; 1630 1631 connectChrono.init(); 1632 do 1633 { 1634 connectChrono.now(); 1635 } 1636 while((!peripheral.connect()) && 1637 connectChrono.elapsed<tOut); 1638 if(connectChrono.elapsed>=tOut) 1639 return 3; 1640 1641 connectChrono.init(); 1642 do 1643 { 1644 connectChrono.now(); 1645 } 1646 while((!peripheral.discoverAttributes()) && 1647 connectChrono.elapsed<tOut); 1648 if(connectChrono.elapsed>=tOut) 1649 return 4; 1650 1651 connectChrono.init(); 1652 do 1653 { 1654 connectChrono.now(); 1655 } 1656 while((!(heatCharacteristic= 1657 peripheral.characteristic 1658 ("707158fb-c794-4774-9d5c-790121b1be5d"))) 1659 && connectChrono.elapsed<tOut); 1660 if(connectChrono.elapsed>=tOut) 1661 return 5; 1662 1663 connected=true; 1664 return 0; 1665} 1666 1667void remoteHeatControl(void) 1668{ 1669 static chronometer remChrono; 1670 static bool oldHeat=!heat; 1671 1672 remChrono.now(); 1673 if((heat!=oldHeat) || 1674 (remChrono.elapsed>30000)) 1675 { 1676 oldHeat=heat; 1677 remChrono.init(); 1678 connectRemoteHeat(); 1679 if(peripheral.connected()) 1680 { 1681 heatCharacteristic.writeValue(heat? 1682 (byte)1:(byte)0); 1683 peripheral.disconnect(); 1684 } 1685 BLE.end(); 1686 } 1687} 1688 1689/* Initialization functions */ 1690 1691void readEEPROM(void) 1692{ 1693 if(EEPROM.read(EEPROMId0)==byte('t') && 1694 EEPROM.read(EEPROMId1)==byte('h') && 1695 EEPROM.read(EEPROMId2)==byte('e')) 1696 { 1697 mode= 1698 EEPROM.read(EEPROMMode); 1699 setPoint=(float) 1700 (EEPROM.read(EEPROMSetPointMSB)*256+ 1701 EEPROM.read(EEPROMSetPointLSB))/10.0; 1702 fixSetPoint=(float) 1703 (EEPROM.read(EEPROMFixSetPointMSB)*256+ 1704 EEPROM.read(EEPROMFixSetPointLSB))/10.0; 1705 deltaT=(float) 1706 (EEPROM.read(EEPROMDeltaTMSB)*256+ 1707 EEPROM.read(EEPROMDeltaTLSB))/10.0; 1708 minHeatPercent= 1709 EEPROM.read(EEPROMMinHeatPercent); 1710 maxHeatPercent= 1711 EEPROM.read(EEPROMMaxHeatPercent); 1712 cycleTime= 1713 EEPROM.read(EEPROMCycleTime); 1714 hysteresis=(float) 1715 (EEPROM.read(EEPROMHysteresisMSB)*256+ 1716 EEPROM.read(EEPROMHysteresisLSB))/10.0; 1717 corrDS18B20=(float)((short) 1718 ((short)(EEPROM.read 1719 (EEPROMCorrDS18B20MSB))<<8)+ 1720 EEPROM.read(EEPROMCorrDS18B20LSB))/10.0; 1721 sleepDelay= 1722 EEPROM.read(EEPROMSleepDelay); 1723 tempUnit= 1724 EEPROM.read(EEPROMTempUnit); 1725 if(tempUnit==Celsius) 1726 tempIncr=0.1; 1727 else 1728 tempIncr=0.5/9.0; 1729 language= 1730 EEPROM.read(EEPROMLanguage); 1731 for(int i=0; i<7; i++) 1732 dayProg[i]=EEPROM.read(EEPROMWeek+i); 1733 for(int pr=0; pr<3; pr++) 1734 for(int i=0; i<4; i++) 1735 { 1736 hourLimit[pr][i]= 1737 EEPROM.read 1738 (EEPROMProg+16*pr+4*i); 1739 minuteLimit[pr][i]= 1740 EEPROM.read 1741 (EEPROMProg+16*pr+4*i+1); 1742 progTemp[pr][i]=(float) 1743 ((EEPROM.read 1744 (EEPROMProg+16*pr+4*i+2)*256+ 1745 EEPROM.read 1746 (EEPROMProg+16*pr+4*i+3))/ 1747 10.0); 1748 } 1749 } 1750 else 1751 { 1752 EEPROM.update(EEPROMId0, 't'); 1753 EEPROM.update(EEPROMId1, 'h'); 1754 EEPROM.update(EEPROMId2, 'e'); 1755 mode=stop; 1756 EEPROM.update(EEPROMMode, mode); 1757 setPoint=19.0; 1758 EEPROM.update(EEPROMSetPointMSB, 1759 (byte)((int)(setPoint*10.01)>>8)); 1760 EEPROM.update(EEPROMSetPointLSB, 1761 (byte)((int)(setPoint*10.01)%256)); 1762 fixSetPoint=19.0; 1763 EEPROM.update(EEPROMFixSetPointMSB, 1764 (byte)((int)(fixSetPoint*10.01)>>8)); 1765 EEPROM.update(EEPROMFixSetPointLSB, 1766 (byte)((int)(fixSetPoint*10.01)%256)); 1767 deltaT=0.0; 1768 EEPROM.update(EEPROMDeltaTMSB, 1769 (byte)((int)(deltaT*10.01)>>8)); 1770 EEPROM.update(EEPROMDeltaTLSB, 1771 (byte)((int)(deltaT*10.01)%256)); 1772 minHeatPercent=20; 1773 EEPROM.update(EEPROMMinHeatPercent, 1774 minHeatPercent); 1775 maxHeatPercent=85; 1776 EEPROM.update(EEPROMMaxHeatPercent, 1777 maxHeatPercent); 1778 cycleTime=120; 1779 EEPROM.update(EEPROMCycleTime, cycleTime); 1780 hysteresis=0.3; 1781 EEPROM.update(EEPROMHysteresisMSB, 1782 (byte)((int)(hysteresis*10.01)>>8)); 1783 EEPROM.update(EEPROMHysteresisLSB, 1784 (byte)((int)(hysteresis*10.01)%256)); 1785 corrDS18B20=0.0; 1786 EEPROM.update(EEPROMCorrDS18B20MSB, 1787 (byte) 1788 ((short)(corrDS18B20*10.01)>>8)); 1789 EEPROM.update(EEPROMCorrDS18B20LSB, 1790 (byte) 1791 ((short)(corrDS18B20*10.01)%256)); 1792 sleepDelay=15; 1793 EEPROM.update(EEPROMSleepDelay, 1794 sleepDelay); 1795 tempUnit=Celsius; 1796 tempIncr=0.1; 1797 EEPROM.update(EEPROMTempUnit, tempUnit); 1798 language=english; 1799 EEPROM.update(EEPROMLanguage, language); 1800 1801 dayProg[0]=0; 1802 dayProg[1]=0; 1803 dayProg[2]=0; 1804 dayProg[3]=0; 1805 dayProg[4]=1; 1806 dayProg[5]=2; 1807 dayProg[6]=2; 1808 for(int i=0; i<7; i++) 1809 EEPROM.update(EEPROMWeek+i, 1810 dayProg[i]); 1811 1812 hourLimit[0][0]=6; 1813 minuteLimit[0][0]=0; 1814 progTemp[0][0]=19.0; 1815 hourLimit[0][1]=8; 1816 minuteLimit[0][1]=30; 1817 progTemp[0][1]=17.5; 1818 hourLimit[0][2]=17; 1819 minuteLimit[0][2]=30; 1820 progTemp[0][2]=19.0; 1821 hourLimit[0][3]=23; 1822 minuteLimit[0][3]=00; 1823 progTemp[0][3]=16.0; 1824 1825 hourLimit[1][0]=6; 1826 minuteLimit[1][0]=0; 1827 progTemp[1][0]=19.0; 1828 hourLimit[1][1]=8; 1829 minuteLimit[1][1]=30; 1830 progTemp[1][1]=17.5; 1831 hourLimit[1][2]=12; 1832 minuteLimit[1][2]=00; 1833 progTemp[1][2]=19.0; 1834 hourLimit[1][3]=23; 1835 minuteLimit[1][3]=00; 1836 progTemp[1][3]=16.0; 1837 1838 hourLimit[2][0]=7; 1839 minuteLimit[2][0]=30; 1840 progTemp[2][0]=19.0; 1841 hourLimit[2][1]=12; 1842 minuteLimit[2][1]=00; 1843 progTemp[2][1]=19.0; 1844 hourLimit[2][2]=17; 1845 minuteLimit[2][2]=30; 1846 progTemp[2][2]=19.0; 1847 hourLimit[2][3]=23; 1848 minuteLimit[2][3]=00; 1849 progTemp[2][3]=16.0; 1850 1851 for(int pr=0; pr<3; pr++) 1852 for(int i=0; i<4; i++) 1853 { 1854 EEPROM.update 1855 (EEPROMProg+16*pr+4*i, 1856 hourLimit[pr][i]); 1857 EEPROM.update 1858 (EEPROMProg+16*pr+4*i+1, 1859 minuteLimit[pr][i]); 1860 EEPROM.update 1861 (EEPROMProg+16*pr+4*i+2, 1862 (byte)((int) 1863 (progTemp[pr][i]*10.01)>>8)); 1864 EEPROM.update 1865 (EEPROMProg+16*pr+4*i+3, 1866 (byte)((int) 1867 (progTemp[pr][i]*10.01)%256)); 1868 } 1869 } 1870 if(mode==prog) setPointInit(); 1871 if(mode==fixed) setPoint=fixSetPoint; 1872} 1873 1874#include "Thermostat_state_functions.h" 1875 1876#include "Thermostat_fsm.h" 1877 1878void setup() 1879{ 1880 pinMode(rotaryAPin, INPUT); 1881 pinMode(rotaryBPin, INPUT); 1882 pinMode(rotarySwitchPin, INPUT_PULLUP); 1883 digitalWrite(LED_PWR, LOW); 1884 Wire.begin(); 1885 u8g2.begin(); 1886 u8g2.setFont(u8g2_font_6x13_mf); 1887 u8g2.setFontDirection(0); 1888 u8g2.setDrawColor(1); 1889 rtc.begin(); 1890 if (!rtc.isrunning()) 1891 rtc.adjust(DateTime(__DATE__, __TIME__)); 1892 current=rtc.now(); 1893 if(current.hour()>24 || 1894 current.minute()>60 || 1895 current.month()>12) 1896 rtc.adjust(DateTime(__DATE__, __TIME__)); 1897 attachInterrupt(digitalPinToInterrupt 1898 (rotaryAPin), 1899 interruptRoutineReadEncoder, 1900 FALLING); 1901 if(digitalRead(rotarySwitchPin)==LOW) 1902 { 1903 EEPROM.update(EEPROMId0, 0xFF); 1904 EEPROM.update(EEPROMId1, 0xFF); 1905 EEPROM.update(EEPROMId2, 0xFF); 1906 } 1907 readEEPROM(); 1908 measureTemp(false); 1909 minTemp=temp; 1910 maxTemp=temp; 1911 setTransitions(); 1912} 1913 1914void loop() 1915{ 1916 measureTemp(true); 1917 rotaryEncoderRead(); 1918 myFsm.trigger(event); 1919 myFsm.run_machine(); 1920 setPointControl(); 1921 heatControl(); 1922 if(!changeSetPoint && !changeMode) 1923 remoteHeatControl(); 1924 wakeDetection(); 1925 if(!displayActive) 1926 delay(500); 1927}
SourceFsm.h
cpp
Must be in the same directory as the main code
1// This file is part of arduino-fsm. 2// 3// arduino-fsm is free software: you can redistribute it and/or modify it under 4// the terms of the GNU Lesser General Public License as published by the Free 5// Software Foundation, either version 3 of the License, or (at your option) 6// any later version. 7// 8// arduino-fsm is distributed in the hope that it will be useful, but WITHOUT 9// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 10// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License 11// for more details. 12// 13// You should have received a copy of the GNU Lesser General Public License 14// along with arduino-fsm. If not, see <http://www.gnu.org/licenses/>. 15 16struct State 17{ 18 State(void (*on_enter)(), void (*on_state)(), void (*on_exit)()); 19 void (*on_enter)(); 20 void (*on_state)(); 21 void (*on_exit)(); 22}; 23 24class Fsm 25{ 26public: 27 Fsm(State* initial_state); 28 ~Fsm(); 29 30 void add_transition(State* state_from, State* state_to, int event, 31 void (*on_transition)()); 32 void trigger(int event); 33 void run_machine(); 34 35private: 36 struct Transition 37 { 38 State* state_from; 39 State* state_to; 40 int event; 41 void (*on_transition)(); 42 }; 43 44 static Transition create_transition(State* state_from, State* state_to, 45 int event, void (*on_transition)()); 46 void make_transition(Transition* transition); 47 48private: 49 State* m_current_state; 50 Transition* m_transitions; 51 int m_num_transitions; 52 bool m_initialized; 53}; 54 55State::State(void (*on_enter)(), void (*on_state)(), void (*on_exit)()) 56: on_enter(on_enter), 57 on_state(on_state), 58 on_exit(on_exit) 59{ 60} 61 62Fsm::Fsm(State* initial_state) 63: m_current_state(initial_state), 64 m_transitions(NULL), 65 m_num_transitions(0), 66// m_num_timed_transitions(0), 67 m_initialized(false) 68{ 69} 70 71Fsm::~Fsm() 72{ 73 free(m_transitions); 74 m_transitions = NULL; 75} 76 77void Fsm::add_transition(State* state_from, State* state_to, int event, 78 void (*on_transition)()) 79{ 80 if (state_from == NULL || state_to == NULL) 81 return; 82 83 Transition transition = Fsm::create_transition(state_from, state_to, event, 84 on_transition); 85 m_transitions = (Transition*) realloc(m_transitions, (m_num_transitions + 1) 86 * sizeof(Transition)); 87 m_transitions[m_num_transitions] = transition; 88 m_num_transitions++; 89} 90 91Fsm::Transition Fsm::create_transition(State* state_from, State* state_to, 92 int event, void (*on_transition)()) 93{ 94 Transition t; 95 t.state_from = state_from; 96 t.state_to = state_to; 97 t.event = event; 98 t.on_transition = on_transition; 99 100 return t; 101} 102 103void Fsm::trigger(int event) 104{ 105 if (m_initialized) 106 { 107 // Find the transition with the current state and given event. 108 for (int i = 0; i < m_num_transitions; ++i) 109 { 110 if (m_transitions[i].state_from == m_current_state && 111 m_transitions[i].event == event) 112 { 113 Fsm::make_transition(&(m_transitions[i])); 114 return; 115 } 116 } 117 } 118} 119 120void Fsm::run_machine() 121{ 122 // first run must exec first state "on_enter" 123 if (!m_initialized) 124 { 125 m_initialized = true; 126 if (m_current_state->on_enter != NULL) 127 m_current_state->on_enter(); 128 } 129 130 if (m_current_state->on_state != NULL) 131 m_current_state->on_state(); 132} 133 134void Fsm::make_transition(Transition* transition) 135{ 136 137 // Execute the handlers in the correct order. 138 if (transition->state_from->on_exit != NULL) 139 transition->state_from->on_exit(); 140 141 if (transition->on_transition != NULL) 142 transition->on_transition(); 143 144 if (transition->state_to->on_enter != NULL) 145 transition->state_to->on_enter(); 146 147 m_current_state = transition->state_to; 148}
Thermostat_fsm.h
cpp
Must be in the same directory as the main code
1/* Finite State Machine which controls the 2 thermostat */ 3 4/* Main screen display and set states */ 5State mainDisplayState(&mainScreen, &mainDisplay, 6 NULL); 7State modeDisplayState(&modeScreen, &modeDisplay, 8 NULL); 9State setPointSetState(&setPointSetEnter, 10 &setPointSet, 11 &setPointSetExit); 12State modeSetState(&modeSetEnter, &modeSet, 13 &modeSetExit); 14 15/* Program display and set states */ 16State prog0DisplayState(&prog0DisplayEnter, 17 &progDisplay, NULL); 18State prog1DisplayState(&prog1DisplayEnter, 19 &progDisplay, NULL); 20State prog2DisplayState(&prog2DisplayEnter, 21 &progDisplay, NULL); 22State weekProgDisplayState( 23 &weekProgDisplayEnter, 24 &progDisplay, 25 NULL); 26 27State hourLimitSet0_0State( 28 &hourLimitSetEnter0, 29 &hourLimitSet0, 30 &hourLimitSetExit0); 31State hourLimitSet0_1State( 32 &hourLimitSetEnter1, 33 &hourLimitSet1, 34 &hourLimitSetExit1); 35State hourLimitSet0_2State( 36 &hourLimitSetEnter2, 37 &hourLimitSet2, 38 &hourLimitSetExit2); 39State hourLimitSet0_3State( 40 &hourLimitSetEnter3, 41 &hourLimitSet3, 42 &hourLimitSetExit3); 43State progTempSet0_0State( 44 &progTempSetEnter0, 45 &progTempSet0, 46 &progTempSetExit0); 47State progTempSet0_1State( 48 &progTempSetEnter1, 49 &progTempSet1, 50 &progTempSetExit1); 51State progTempSet0_2State( 52 &progTempSetEnter2, 53 &progTempSet2, 54 &progTempSetExit2); 55State progTempSet0_3State( 56 &progTempSetEnter3, 57 &progTempSet3, 58 &progTempSetExit3); 59 60State hourLimitSet1_0State( 61 &hourLimitSetEnter0, 62 &hourLimitSet0, 63 &hourLimitSetExit0); 64State hourLimitSet1_1State( 65 &hourLimitSetEnter1, 66 &hourLimitSet1, 67 &hourLimitSetExit1); 68State hourLimitSet1_2State( 69 &hourLimitSetEnter2, 70 &hourLimitSet2, 71 &hourLimitSetExit2); 72State hourLimitSet1_3State( 73 &hourLimitSetEnter3, 74 &hourLimitSet3, 75 &hourLimitSetExit3); 76State progTempSet1_0State( 77 &progTempSetEnter0, 78 &progTempSet0, 79 &progTempSetExit0); 80State progTempSet1_1State( 81 &progTempSetEnter1, 82 &progTempSet1, 83 &progTempSetExit1); 84State progTempSet1_2State( 85 &progTempSetEnter2, 86 &progTempSet2, 87 &progTempSetExit2); 88State progTempSet1_3State( 89 &progTempSetEnter3, 90 &progTempSet3, 91 &progTempSetExit3); 92 93State hourLimitSet2_0State( 94 &hourLimitSetEnter0, 95 &hourLimitSet0, 96 &hourLimitSetExit0); 97State hourLimitSet2_1State( 98 &hourLimitSetEnter1, 99 &hourLimitSet1, 100 &hourLimitSetExit1); 101State hourLimitSet2_2State( 102 &hourLimitSetEnter2, 103 &hourLimitSet2, 104 &hourLimitSetExit2); 105State hourLimitSet2_3State( 106 &hourLimitSetEnter3, 107 &hourLimitSet3, 108 &hourLimitSetExit3); 109State progTempSet2_0State( 110 &progTempSetEnter0, 111 &progTempSet0, 112 &progTempSetExit0); 113State progTempSet2_1State( 114 &progTempSetEnter1, 115 &progTempSet1, 116 &progTempSetExit1); 117State progTempSet2_2State( 118 &progTempSetEnter2, 119 &progTempSet2, 120 &progTempSetExit2); 121State progTempSet2_3State( 122 &progTempSetEnter3, 123 &progTempSet3, 124 &progTempSetExit3); 125 126State monProgSetState(&monProgSetEnter, 127 &dayProgSet, 128 &dayProgSetExit); 129State tueProgSetState(&tueProgSetEnter, 130 &dayProgSet, 131 &dayProgSetExit); 132State wedProgSetState(&wedProgSetEnter, 133 &dayProgSet, 134 &dayProgSetExit); 135State thuProgSetState(&thuProgSetEnter, 136 &dayProgSet, 137 &dayProgSetExit); 138State friProgSetState(&friProgSetEnter, 139 &dayProgSet, 140 &dayProgSetExit); 141State satProgSetState(&satProgSetEnter, 142 &dayProgSet, 143 &dayProgSetExit); 144State sunProgSetState(&sunProgSetEnter, 145 &dayProgSet, 146 &dayProgSetExit); 147 148/* Heating behaviour display and set states */ 149State heatingBehaviourDisplayState( 150 &heatingBehaviourScreen, 151 &heatingBehaviourDisplay, 152 NULL); 153State hysteresisSetState(&hysteresisSetEnter, 154 &hysteresisSet, 155 &hysteresisSetExit); 156State deltaTSetState(&deltaTSetEnter, 157 &deltaTSet, 158 &deltaTSetExit); 159State minHeatPercentSetState 160 (&minHeatPercentSetEnter, 161 &minHeatPercentSet, 162 &minHeatPercentSetExit); 163State maxHeatPercentSetState 164 (&maxHeatPercentSetEnter, 165 &maxHeatPercentSet, 166 &maxHeatPercentSetExit); 167State cycleTimeSetState(&cycleTimeSetEnter, 168 &cycleTimeSet, 169 &cycleTimeSetExit); 170 171/* System display and set states */ 172State systemDisplayState(&systemScreen, 173 &systemDisplay, 174 NULL); 175State sleepDelaySetState(&sleepDelaySetEnter, 176 &sleepDelaySet, 177 &sleepDelaySetExit); 178State tempUnitSetState(&tempUnitSetEnter, 179 &tempUnitSet, 180 &tempUnitSetExit); 181State corrDS18B20SetState(&corrDS18B20SetEnter, 182 &corrDS18B20Set, 183 &corrDS18B20SetExit); 184State languageSetState(&languageSetEnter, 185 &languageSet, 186 &languageSetExit); 187 188/* Clock and calendar display and set states */ 189State timeDateState(NULL, 190 &timeDateDisplay, 191 NULL); 192State hourSetState(&hourSetEnter, &hourSet, 193 NULL); 194State minuteSetState(&minuteSetEnter, 195 &minuteSet, NULL); 196State secondSetState(&secondSetEnter, 197 &secondSet, &timeUpdate); 198State yearSetState(&yearSetEnter, &yearSet, 199 &dateUpdate); 200State monthSetState(&monthSetEnter, &monthSet, 201 &dateUpdate); 202State dayOfMonthSetState(&dayOfMonthSetEnter, 203 &dayOfMonthSet, 204 &dateUpdate); 205 206/* Temperature display state */ 207State temperatureDisplayState(&temperatureScreen, 208 &temperatureDisplay, NULL); 209 210Fsm myFsm(&mainDisplayState); 211 212void setTransitions(void) 213{ 214/* Transitions between display states */ 215 myFsm.add_transition(&mainDisplayState, 216 &modeDisplayState, 217 cwRot, NULL); 218 myFsm.add_transition(&modeDisplayState, 219 &prog0DisplayState, 220 cwRot, NULL); 221 myFsm.add_transition(&prog0DisplayState, 222 &heatingBehaviourDisplayState, 223 cwRot, NULL); 224 myFsm.add_transition(&prog1DisplayState, 225 &heatingBehaviourDisplayState, 226 cwRot, NULL); 227 myFsm.add_transition(&prog2DisplayState, 228 &heatingBehaviourDisplayState, 229 cwRot, NULL); 230 myFsm.add_transition(&weekProgDisplayState, 231 &heatingBehaviourDisplayState, 232 cwRot, NULL); 233 myFsm.add_transition(&heatingBehaviourDisplayState, 234 &systemDisplayState, 235 cwRot, NULL); 236 myFsm.add_transition(&systemDisplayState, 237 &timeDateState, 238 cwRot, NULL); 239 myFsm.add_transition(&timeDateState, 240 &temperatureDisplayState, 241 cwRot, NULL); 242 myFsm.add_transition(&temperatureDisplayState, 243 &mainDisplayState, 244 cwRot, NULL); 245 myFsm.add_transition(&mainDisplayState, 246 &temperatureDisplayState, 247 ccwRot, NULL); 248 myFsm.add_transition(&temperatureDisplayState, 249 &timeDateState, 250 ccwRot, NULL); 251 myFsm.add_transition(&timeDateState, 252 &systemDisplayState, 253 ccwRot, NULL); 254 myFsm.add_transition(&systemDisplayState, 255 &heatingBehaviourDisplayState, 256 ccwRot, NULL); 257 myFsm.add_transition(&heatingBehaviourDisplayState, 258 &prog0DisplayState, 259 ccwRot, NULL); 260 myFsm.add_transition(&prog0DisplayState, 261 &modeDisplayState, 262 ccwRot, NULL); 263 myFsm.add_transition(&prog1DisplayState, 264 &modeDisplayState, 265 ccwRot, NULL); 266 myFsm.add_transition(&prog2DisplayState, 267 &modeDisplayState, 268 ccwRot, NULL); 269 myFsm.add_transition(&weekProgDisplayState, 270 &modeDisplayState, 271 ccwRot, NULL); 272 myFsm.add_transition(&modeDisplayState, 273 &mainDisplayState, 274 ccwRot, NULL); 275 276/* Transitions to set mode and set point */ 277 myFsm.add_transition(&modeDisplayState, 278 &modeSetState, 279 longSwitchPress, NULL); 280 myFsm.add_transition(&modeDisplayState, 281 &modeSetState, 282 longSwitchPressAndHeat, 283 NULL); 284 myFsm.add_transition(&modeSetState, 285 &mainDisplayState, 286 shortSwitchPress, NULL); 287 myFsm.add_transition(&modeSetState, 288 &mainDisplayState, 289 longSwitchPress, NULL); 290 myFsm.add_transition(&modeSetState, 291 &mainDisplayState, 292 longSwitchPressAndHeat, 293 NULL); 294 myFsm.add_transition(&mainDisplayState, 295 &setPointSetState, 296 longSwitchPressAndHeat, 297 NULL); 298 myFsm.add_transition(&setPointSetState, 299 &mainDisplayState, 300 shortSwitchPress, NULL); 301 myFsm.add_transition(&setPointSetState, 302 &mainDisplayState, 303 longSwitchPressAndHeat, 304 NULL); 305 myFsm.add_transition(&setPointSetState, 306 &mainDisplayState, 307 timeOut, NULL); 308 309/* Transitions to set prog */ 310 myFsm.add_transition(&prog0DisplayState, 311 &prog1DisplayState, 312 shortSwitchPress, NULL); 313 myFsm.add_transition(&prog1DisplayState, 314 &prog2DisplayState, 315 shortSwitchPress, NULL); 316 myFsm.add_transition(&prog2DisplayState, 317 &weekProgDisplayState, 318 shortSwitchPress, NULL); 319 myFsm.add_transition(&weekProgDisplayState, 320 &prog0DisplayState, 321 shortSwitchPress, NULL); 322/* Prog 0 */ 323 myFsm.add_transition(&prog0DisplayState, 324 &hourLimitSet0_0State, 325 longSwitchPress, NULL); 326 myFsm.add_transition(&prog0DisplayState, 327 &hourLimitSet0_0State, 328 longSwitchPressAndHeat, 329 NULL); 330 myFsm.add_transition(&hourLimitSet0_0State, 331 &hourLimitSet0_1State, 332 shortSwitchPress, NULL); 333 myFsm.add_transition(&hourLimitSet0_0State, 334 &prog0DisplayState, 335 longSwitchPress, NULL); 336 myFsm.add_transition(&hourLimitSet0_0State, 337 &prog0DisplayState, 338 longSwitchPressAndHeat, 339 NULL); 340 341 myFsm.add_transition(&hourLimitSet0_1State, 342 &progTempSet0_0State, 343 shortSwitchPress, NULL); 344 myFsm.add_transition(&hourLimitSet0_1State, 345 &prog0DisplayState, 346 longSwitchPress, NULL); 347 myFsm.add_transition(&hourLimitSet0_1State, 348 &prog0DisplayState, 349 longSwitchPressAndHeat, 350 NULL); 351 352 myFsm.add_transition(&progTempSet0_0State, 353 &hourLimitSet0_2State, 354 shortSwitchPress, NULL); 355 myFsm.add_transition(&progTempSet0_0State, 356 &prog0DisplayState, 357 longSwitchPress, NULL); 358 myFsm.add_transition(&progTempSet0_0State, 359 &prog0DisplayState, 360 longSwitchPressAndHeat, 361 NULL); 362 363 myFsm.add_transition(&hourLimitSet0_2State, 364 &progTempSet0_1State, 365 shortSwitchPress, NULL); 366 myFsm.add_transition(&hourLimitSet0_2State, 367 &prog0DisplayState, 368 longSwitchPress, NULL); 369 myFsm.add_transition(&hourLimitSet0_2State, 370 &prog0DisplayState, 371 longSwitchPressAndHeat, 372 NULL); 373 374 myFsm.add_transition(&progTempSet0_1State, 375 &hourLimitSet0_3State, 376 shortSwitchPress, NULL); 377 myFsm.add_transition(&progTempSet0_1State, 378 &prog0DisplayState, 379 longSwitchPress, NULL); 380 myFsm.add_transition(&progTempSet0_1State, 381 &prog0DisplayState, 382 longSwitchPressAndHeat, 383 NULL); 384 385 myFsm.add_transition(&hourLimitSet0_3State, 386 &progTempSet0_2State, 387 shortSwitchPress, NULL); 388 myFsm.add_transition(&hourLimitSet0_3State, 389 &prog0DisplayState, 390 longSwitchPress, NULL); 391 myFsm.add_transition(&hourLimitSet0_3State, 392 &prog0DisplayState, 393 longSwitchPressAndHeat, 394 NULL); 395 396 myFsm.add_transition(&progTempSet0_2State, 397 &progTempSet0_3State, 398 shortSwitchPress, NULL); 399 myFsm.add_transition(&progTempSet0_2State, 400 &prog0DisplayState, 401 longSwitchPress, NULL); 402 myFsm.add_transition(&progTempSet0_2State, 403 &prog0DisplayState, 404 longSwitchPressAndHeat, 405 NULL); 406 407 myFsm.add_transition(&progTempSet0_3State, 408 &hourLimitSet0_0State, 409 shortSwitchPress, NULL); 410 myFsm.add_transition(&progTempSet0_3State, 411 &prog0DisplayState, 412 longSwitchPress, NULL); 413 myFsm.add_transition(&progTempSet0_3State, 414 &prog0DisplayState, 415 longSwitchPressAndHeat, 416 NULL); 417/* Prog 1 */ 418 myFsm.add_transition(&prog1DisplayState, 419 &hourLimitSet1_0State, 420 longSwitchPress, NULL); 421 myFsm.add_transition(&prog1DisplayState, 422 &hourLimitSet1_0State, 423 longSwitchPressAndHeat, 424 NULL); 425 myFsm.add_transition(&hourLimitSet1_0State, 426 &hourLimitSet1_1State, 427 shortSwitchPress, NULL); 428 myFsm.add_transition(&hourLimitSet1_0State, 429 &prog1DisplayState, 430 longSwitchPress, NULL); 431 myFsm.add_transition(&hourLimitSet1_0State, 432 &prog1DisplayState, 433 longSwitchPressAndHeat, 434 NULL); 435 436 myFsm.add_transition(&hourLimitSet1_1State, 437 &progTempSet1_0State, 438 shortSwitchPress, NULL); 439 myFsm.add_transition(&hourLimitSet1_1State, 440 &prog1DisplayState, 441 longSwitchPress, NULL); 442 myFsm.add_transition(&hourLimitSet1_1State, 443 &prog1DisplayState, 444 longSwitchPressAndHeat, 445 NULL); 446 447 myFsm.add_transition(&progTempSet1_0State, 448 &hourLimitSet1_2State, 449 shortSwitchPress, NULL); 450 myFsm.add_transition(&progTempSet1_0State, 451 &prog1DisplayState, 452 longSwitchPress, NULL); 453 myFsm.add_transition(&progTempSet1_0State, 454 &prog1DisplayState, 455 longSwitchPressAndHeat, 456 NULL); 457 458 myFsm.add_transition(&hourLimitSet1_2State, 459 &progTempSet1_1State, 460 shortSwitchPress, NULL); 461 myFsm.add_transition(&hourLimitSet1_2State, 462 &prog1DisplayState, 463 longSwitchPress, NULL); 464 myFsm.add_transition(&hourLimitSet1_2State, 465 &prog1DisplayState, 466 longSwitchPressAndHeat, 467 NULL); 468 469 myFsm.add_transition(&progTempSet1_1State, 470 &hourLimitSet1_3State, 471 shortSwitchPress, NULL); 472 myFsm.add_transition(&progTempSet1_1State, 473 &prog1DisplayState, 474 longSwitchPress, NULL); 475 myFsm.add_transition(&progTempSet1_1State, 476 &prog1DisplayState, 477 longSwitchPressAndHeat, 478 NULL); 479 480 myFsm.add_transition(&hourLimitSet1_3State, 481 &progTempSet1_2State, 482 shortSwitchPress, NULL); 483 myFsm.add_transition(&hourLimitSet1_3State, 484 &prog1DisplayState, 485 longSwitchPress, NULL); 486 myFsm.add_transition(&hourLimitSet1_3State, 487 &prog1DisplayState, 488 longSwitchPressAndHeat, 489 NULL); 490 491 myFsm.add_transition(&progTempSet1_2State, 492 &progTempSet1_3State, 493 shortSwitchPress, NULL); 494 myFsm.add_transition(&progTempSet1_2State, 495 &prog1DisplayState, 496 longSwitchPress, NULL); 497 myFsm.add_transition(&progTempSet1_2State, 498 &prog1DisplayState, 499 longSwitchPressAndHeat, 500 NULL); 501 502 myFsm.add_transition(&progTempSet1_3State, 503 &hourLimitSet1_0State, 504 shortSwitchPress, NULL); 505 myFsm.add_transition(&progTempSet1_3State, 506 &prog1DisplayState, 507 longSwitchPress, NULL); 508 myFsm.add_transition(&progTempSet1_3State, 509 &prog1DisplayState, 510 longSwitchPressAndHeat, 511 NULL); 512 513/* Prog 2 */ 514 myFsm.add_transition(&prog2DisplayState, 515 &hourLimitSet2_0State, 516 longSwitchPress, NULL); 517 myFsm.add_transition(&prog2DisplayState, 518 &hourLimitSet2_0State, 519 longSwitchPressAndHeat, 520 NULL); 521 myFsm.add_transition(&hourLimitSet2_0State, 522 &hourLimitSet2_1State, 523 shortSwitchPress, NULL); 524 myFsm.add_transition(&hourLimitSet2_0State, 525 &prog2DisplayState, 526 longSwitchPress, NULL); 527 myFsm.add_transition(&hourLimitSet2_0State, 528 &prog2DisplayState, 529 longSwitchPressAndHeat, 530 NULL); 531 532 myFsm.add_transition(&hourLimitSet2_1State, 533 &progTempSet2_0State, 534 shortSwitchPress, NULL); 535 myFsm.add_transition(&hourLimitSet2_1State, 536 &prog2DisplayState, 537 longSwitchPress, NULL); 538 myFsm.add_transition(&hourLimitSet2_1State, 539 &prog2DisplayState, 540 longSwitchPressAndHeat, 541 NULL); 542 543 myFsm.add_transition(&progTempSet2_0State, 544 &hourLimitSet2_2State, 545 shortSwitchPress, NULL); 546 myFsm.add_transition(&progTempSet2_0State, 547 &prog2DisplayState, 548 longSwitchPress, NULL); 549 myFsm.add_transition(&progTempSet2_0State, 550 &prog2DisplayState, 551 longSwitchPressAndHeat, 552 NULL); 553 554 myFsm.add_transition(&hourLimitSet2_2State, 555 &progTempSet2_1State, 556 shortSwitchPress, NULL); 557 myFsm.add_transition(&hourLimitSet2_2State, 558 &prog2DisplayState, 559 longSwitchPress, NULL); 560 myFsm.add_transition(&hourLimitSet2_2State, 561 &prog2DisplayState, 562 longSwitchPressAndHeat, 563 NULL); 564 565 myFsm.add_transition(&progTempSet2_1State, 566 &hourLimitSet2_3State, 567 shortSwitchPress, NULL); 568 myFsm.add_transition(&progTempSet2_1State, 569 &prog2DisplayState, 570 longSwitchPress, NULL); 571 myFsm.add_transition(&progTempSet2_1State, 572 &prog2DisplayState, 573 longSwitchPressAndHeat, 574 NULL); 575 576 myFsm.add_transition(&hourLimitSet2_3State, 577 &progTempSet2_2State, 578 shortSwitchPress, NULL); 579 myFsm.add_transition(&hourLimitSet2_3State, 580 &prog2DisplayState, 581 longSwitchPress, NULL); 582 myFsm.add_transition(&hourLimitSet2_3State, 583 &prog2DisplayState, 584 longSwitchPressAndHeat, 585 NULL); 586 587 myFsm.add_transition(&progTempSet2_2State, 588 &progTempSet2_3State, 589 shortSwitchPress, NULL); 590 myFsm.add_transition(&progTempSet2_2State, 591 &prog2DisplayState, 592 longSwitchPress, NULL); 593 myFsm.add_transition(&progTempSet2_2State, 594 &prog2DisplayState, 595 longSwitchPressAndHeat, 596 NULL); 597 598 myFsm.add_transition(&progTempSet2_3State, 599 &hourLimitSet2_0State, 600 shortSwitchPress, NULL); 601 myFsm.add_transition(&progTempSet2_3State, 602 &prog2DisplayState, 603 longSwitchPress, NULL); 604 myFsm.add_transition(&progTempSet2_3State, 605 &prog2DisplayState, 606 longSwitchPressAndHeat, 607 NULL); 608 609 myFsm.add_transition(&weekProgDisplayState, 610 &monProgSetState, 611 longSwitchPress, NULL); 612 myFsm.add_transition(&weekProgDisplayState, 613 &monProgSetState, 614 longSwitchPressAndHeat, 615 NULL); 616 myFsm.add_transition(&monProgSetState, 617 &tueProgSetState, 618 shortSwitchPress, NULL); 619 myFsm.add_transition(&monProgSetState, 620 &weekProgDisplayState, 621 longSwitchPress, NULL); 622 myFsm.add_transition(&monProgSetState, 623 &weekProgDisplayState, 624 longSwitchPressAndHeat, 625 NULL); 626 myFsm.add_transition(&tueProgSetState, 627 &wedProgSetState, 628 shortSwitchPress, NULL); 629 myFsm.add_transition(&tueProgSetState, 630 &weekProgDisplayState, 631 longSwitchPress, NULL); 632 myFsm.add_transition(&tueProgSetState, 633 &weekProgDisplayState, 634 longSwitchPressAndHeat, 635 NULL); 636 myFsm.add_transition(&wedProgSetState, 637 &thuProgSetState, 638 shortSwitchPress, NULL); 639 myFsm.add_transition(&wedProgSetState, 640 &weekProgDisplayState, 641 longSwitchPress, NULL); 642 myFsm.add_transition(&wedProgSetState, 643 &weekProgDisplayState, 644 longSwitchPressAndHeat, 645 NULL); 646 myFsm.add_transition(&thuProgSetState, 647 &friProgSetState, 648 shortSwitchPress, NULL); 649 myFsm.add_transition(&thuProgSetState, 650 &weekProgDisplayState, 651 longSwitchPress, NULL); 652 myFsm.add_transition(&thuProgSetState, 653 &weekProgDisplayState, 654 longSwitchPressAndHeat, 655 NULL); 656 myFsm.add_transition(&friProgSetState, 657 &satProgSetState, 658 shortSwitchPress, NULL); 659 myFsm.add_transition(&friProgSetState, 660 &weekProgDisplayState, 661 longSwitchPress, NULL); 662 myFsm.add_transition(&friProgSetState, 663 &weekProgDisplayState, 664 longSwitchPressAndHeat, 665 NULL); 666 myFsm.add_transition(&satProgSetState, 667 &sunProgSetState, 668 shortSwitchPress, NULL); 669 myFsm.add_transition(&satProgSetState, 670 &weekProgDisplayState, 671 longSwitchPress, NULL); 672 myFsm.add_transition(&satProgSetState, 673 &weekProgDisplayState, 674 longSwitchPressAndHeat, 675 NULL); 676 myFsm.add_transition(&sunProgSetState, 677 &monProgSetState, 678 shortSwitchPress, NULL); 679 myFsm.add_transition(&sunProgSetState, 680 &weekProgDisplayState, 681 longSwitchPress, NULL); 682 myFsm.add_transition(&sunProgSetState, 683 &weekProgDisplayState, 684 longSwitchPressAndHeat, 685 NULL); 686 687/* Transitions to set heating behaviour */ 688 myFsm.add_transition(&heatingBehaviourDisplayState, 689 &hysteresisSetState, 690 longSwitchPress, NULL); 691 myFsm.add_transition(&heatingBehaviourDisplayState, 692 &hysteresisSetState, 693 longSwitchPressAndHeat, 694 NULL); 695 696 myFsm.add_transition(&hysteresisSetState, 697 &deltaTSetState, 698 shortSwitchPress, NULL); 699 myFsm.add_transition(&hysteresisSetState, 700 &heatingBehaviourDisplayState, 701 longSwitchPress, NULL); 702 myFsm.add_transition(&hysteresisSetState, 703 &heatingBehaviourDisplayState, 704 longSwitchPressAndHeat, NULL); 705 706 myFsm.add_transition(&deltaTSetState, 707 &minHeatPercentSetState, 708 shortSwitchPress, NULL); 709 myFsm.add_transition(&deltaTSetState, 710 &heatingBehaviourDisplayState, 711 longSwitchPress, NULL); 712 myFsm.add_transition(&deltaTSetState, 713 &heatingBehaviourDisplayState, 714 longSwitchPressAndHeat, NULL); 715 716 myFsm.add_transition(&minHeatPercentSetState, 717 &maxHeatPercentSetState, 718 shortSwitchPress, NULL); 719 myFsm.add_transition(&minHeatPercentSetState, 720 &heatingBehaviourDisplayState, 721 longSwitchPress, NULL); 722 myFsm.add_transition(&minHeatPercentSetState, 723 &heatingBehaviourDisplayState, 724 longSwitchPressAndHeat, NULL); 725 726 myFsm.add_transition(&maxHeatPercentSetState, 727 &cycleTimeSetState, 728 shortSwitchPress, NULL); 729 myFsm.add_transition(&maxHeatPercentSetState, 730 &heatingBehaviourDisplayState, 731 longSwitchPress, NULL); 732 myFsm.add_transition(&maxHeatPercentSetState, 733 &heatingBehaviourDisplayState, 734 longSwitchPressAndHeat, NULL); 735 736 myFsm.add_transition(&cycleTimeSetState, 737 &heatingBehaviourDisplayState, 738 shortSwitchPress, NULL); 739 myFsm.add_transition(&cycleTimeSetState, 740 &heatingBehaviourDisplayState, 741 longSwitchPress, NULL); 742 myFsm.add_transition(&cycleTimeSetState, 743 &heatingBehaviourDisplayState, 744 longSwitchPressAndHeat, NULL); 745 746/* Transistions to set system params */ 747 myFsm.add_transition(&systemDisplayState, 748 &sleepDelaySetState, 749 longSwitchPress, NULL); 750 myFsm.add_transition(&systemDisplayState, 751 &sleepDelaySetState, 752 longSwitchPressAndHeat, 753 NULL); 754 755 myFsm.add_transition(&sleepDelaySetState, 756 &tempUnitSetState, 757 shortSwitchPress, NULL); 758 myFsm.add_transition(&sleepDelaySetState, 759 &systemDisplayState, 760 longSwitchPress, 761 NULL); 762 myFsm.add_transition(&sleepDelaySetState, 763 &systemDisplayState, 764 longSwitchPressAndHeat, 765 NULL); 766 767 myFsm.add_transition(&tempUnitSetState, 768 &corrDS18B20SetState, 769 shortSwitchPress, NULL); 770 myFsm.add_transition(&tempUnitSetState, 771 &systemDisplayState, 772 longSwitchPress, 773 NULL); 774 myFsm.add_transition(&tempUnitSetState, 775 &systemDisplayState, 776 longSwitchPressAndHeat, 777 NULL); 778 779 myFsm.add_transition(&corrDS18B20SetState, 780 &languageSetState, 781 shortSwitchPress, NULL); 782 myFsm.add_transition(&corrDS18B20SetState, 783 &systemDisplayState, 784 longSwitchPress, NULL); 785 myFsm.add_transition(&corrDS18B20SetState, 786 &systemDisplayState, 787 longSwitchPressAndHeat, 788 NULL); 789 790 myFsm.add_transition(&languageSetState, 791 &systemDisplayState, 792 shortSwitchPress, NULL); 793 myFsm.add_transition(&languageSetState, 794 &systemDisplayState, 795 longSwitchPress, NULL); 796 myFsm.add_transition(&languageSetState, 797 &systemDisplayState, 798 longSwitchPressAndHeat, 799 NULL); 800 801/* Transitions to set date and time */ 802 myFsm.add_transition(&timeDateState, 803 &hourSetState, 804 longSwitchPress, NULL); 805 myFsm.add_transition(&timeDateState, 806 &hourSetState, 807 longSwitchPressAndHeat, 808 NULL); 809 myFsm.add_transition(&hourSetState, 810 &minuteSetState, 811 shortSwitchPress, NULL); 812 myFsm.add_transition(&hourSetState, 813 &timeDateState, 814 longSwitchPress, 815 &timeUpdate); 816 myFsm.add_transition(&hourSetState, 817 &timeDateState, 818 longSwitchPressAndHeat, 819 &timeUpdate); 820 myFsm.add_transition(&hourSetState, 821 &timeDateState, 822 timeOut, &timeUpdate); 823 824 myFsm.add_transition(&minuteSetState, 825 &secondSetState, 826 shortSwitchPress, NULL); 827 myFsm.add_transition(&minuteSetState, 828 &timeDateState, 829 longSwitchPress, 830 &timeUpdate); 831 myFsm.add_transition(&minuteSetState, 832 &timeDateState, 833 longSwitchPressAndHeat, 834 &timeUpdate); 835 myFsm.add_transition(&minuteSetState, 836 &timeDateState, 837 timeOut, &timeUpdate); 838 839 myFsm.add_transition(&secondSetState, 840 &yearSetState, 841 shortSwitchPress, 842 &timeUpdate); 843 myFsm.add_transition(&secondSetState, 844 &timeDateState, 845 longSwitchPress, 846 &timeUpdate); 847 myFsm.add_transition(&secondSetState, 848 &timeDateState, 849 longSwitchPressAndHeat, 850 &timeUpdate); 851 myFsm.add_transition(&secondSetState, 852 &timeDateState, 853 timeOut, &timeUpdate); 854 855 myFsm.add_transition(&yearSetState, 856 &monthSetState, 857 shortSwitchPress, NULL); 858 myFsm.add_transition(&yearSetState, 859 &timeDateState, 860 longSwitchPress,NULL); 861 myFsm.add_transition(&yearSetState, 862 &timeDateState, 863 longSwitchPressAndHeat, 864 NULL); 865 myFsm.add_transition(&yearSetState, 866 &timeDateState, 867 timeOut, NULL); 868 869 myFsm.add_transition(&monthSetState, 870 &dayOfMonthSetState, 871 shortSwitchPress, NULL); 872 myFsm.add_transition(&monthSetState, 873 &timeDateState, 874 longSwitchPress, NULL); 875 myFsm.add_transition(&monthSetState, 876 &timeDateState, 877 longSwitchPressAndHeat, 878 NULL); 879 myFsm.add_transition(&monthSetState, 880 &timeDateState, 881 timeOut, NULL); 882 883 myFsm.add_transition(&dayOfMonthSetState, 884 &timeDateState, 885 shortSwitchPress, NULL); 886 myFsm.add_transition(&dayOfMonthSetState, 887 &timeDateState, 888 longSwitchPress, NULL); 889 myFsm.add_transition(&dayOfMonthSetState, 890 &timeDateState, 891 longSwitchPressAndHeat, 892 NULL); 893 myFsm.add_transition(&dayOfMonthSetState, 894 &timeDateState, 895 timeOut, NULL); 896}
Thermostat_state_functions.h
cpp
Must be in the same directory as the main code
1/* Functions called by the FSM of the 2 thermostat */ 3 4chronometer displayChrono; 5 6/* Main screen display and set functions */ 7void mainDisplay(void) 8{ 9 static int oldSecond; 10 11 current=rtc.now(); 12 if(current.second()!=oldSecond) 13 { 14 oldSecond=current.second(); 15 mainScreen(); 16 } 17} 18 19void modeDisplay(void) 20{ 21 displayChrono.now(); 22 if(displayChrono.elapsed>1000) 23 { 24 displayChrono.init(); 25 modeScreen(); 26 } 27} 28 29void modeSetEnter(void) 30{ 31 changeMode=true; 32 modeScreen(); 33} 34 35void modeSet(void) 36{ 37 if(event==cwRot) 38 { 39 if(mode==stop) mode=fixed; 40 else if(mode==fixed) mode=prog; 41 else if(mode==prog) mode=stop; 42 modeScreen(); 43 } 44 else if(event==ccwRot) 45 { 46 if(mode==stop) mode=prog; 47 else if(mode==prog) mode=fixed; 48 else if(mode==fixed) mode=stop; 49 modeScreen(); 50 } 51} 52 53void modeSetExit(void) 54{ 55 changeMode=false; 56 modeScreen(); 57 EEPROM.update(EEPROMMode, mode); 58 if(mode==prog) setPointInit(); 59 if(mode==fixed) setPoint=fixSetPoint; 60} 61 62void setPointSetEnter(void) 63{ 64 changeSetPoint=true; 65 mainScreen(); 66} 67 68void setPointSet(void) 69{ 70 mainDisplay(); 71 if(event==cwRot) 72 { 73 setPoint+=tempIncr; 74 if(setPoint>30.0) setPoint=30.0; 75 mainScreen(); 76 } 77 if(event==ccwRot) 78 { 79 setPoint-=tempIncr; 80 if(setPoint<5.0) setPoint=5.0; 81 mainScreen(); 82 } 83} 84 85void setPointSetExit(void) 86{ 87 changeSetPoint=false; 88 mainScreen(); 89 EEPROM.update(EEPROMSetPointMSB, 90 (byte)((int)(setPoint*10.01)>>8)); 91 EEPROM.update(EEPROMSetPointLSB, 92 (byte)((int)(setPoint*10.01)%256)); 93 if(mode==fixed) 94 { 95 fixSetPoint=setPoint; 96 EEPROM.update(EEPROMFixSetPointMSB, 97 (byte)((int)(fixSetPoint*10.01)>>8)); 98 EEPROM.update(EEPROMFixSetPointLSB, 99 (byte)((int)(fixSetPoint*10.01)%256)); 100 } 101} 102 103void progDisplayEnter(void) 104{ 105 progSetting=noProg; 106 progScreen(); 107} 108 109void progDisplay(void) 110{ 111 displayChrono.now(); 112 if(displayChrono.elapsed>1000) 113 { 114 displayChrono.init(); 115 progScreen(); 116 } 117} 118 119void prog0DisplayEnter(void) 120{ 121 progSetting=setProg0; 122 progNum=0; 123 progScreen(); 124} 125 126void prog1DisplayEnter(void) 127{ 128 progSetting=setProg1; 129 progNum=1; 130 progScreen(); 131} 132 133void prog2DisplayEnter(void) 134{ 135 progSetting=setProg2; 136 progNum=2; 137 progScreen(); 138} 139 140void weekProgDisplayEnter(void) 141{ 142 progSetting=setWeek; 143 progNum=0; 144 progScreen(); 145} 146 147void hourLimitSetEnter(int n) 148{ 149 setHourLimit[n]=true; 150 dailyProgScreen(); 151} 152 153void hourLimitSet(int n) 154{ 155 if(event==cwRot) 156 { 157 if((hourLimit[progNum][n]*60+ 158 minuteLimit[progNum][n]+10)% 159 1440!= 160 hourLimit[progNum][(n+1)%4]*60+ 161 minuteLimit[progNum][(n+1)%4]) 162 { 163 minuteLimit[progNum][n]+=10; 164 if(minuteLimit[progNum][n]>=60) 165 { 166 minuteLimit[progNum][n]=0; 167 hourLimit[progNum][n]++; 168 if(hourLimit[progNum][n]>=24) 169 hourLimit[progNum][n]=0; 170 } 171 } 172 dailyProgScreen(); 173 } 174 175 else if(event==ccwRot) 176 { 177 if(hourLimit[progNum][n]*60+ 178 minuteLimit[progNum][n]!= 179 (hourLimit[progNum][(n+3)%4]*60+ 180 minuteLimit[progNum][(n+3)%4]+10)%1440) 181 { 182 minuteLimit[progNum][n]-=10; 183 if(minuteLimit[progNum][n]<0) 184 { 185 minuteLimit[progNum][n]=50; 186 hourLimit[progNum][n]--; 187 if(hourLimit[progNum][n]<0) 188 hourLimit[progNum][n]=23; 189 } 190 } 191 dailyProgScreen(); 192 } 193} 194 195void hourLimitSetExit(int n) 196{ 197 setHourLimit[n]=false; 198 EEPROM.update(EEPROMProg+16*progNum+4*n, 199 hourLimit[progNum][n]); 200 EEPROM.update(EEPROMProg+16*progNum+4*n+1, 201 minuteLimit[progNum][n]); 202 if(mode==prog) setPointInit(); 203} 204 205void hourLimitSetEnter0(void) 206{ 207 hourLimitSetEnter(0); 208} 209 210void hourLimitSet0(void) 211{ 212 hourLimitSet(0); 213} 214 215void hourLimitSetExit0(void) 216{ 217 hourLimitSetExit(0); 218} 219 220void hourLimitSetEnter1(void) 221{ 222 hourLimitSetEnter(1); 223} 224 225void hourLimitSet1(void) 226{ 227 hourLimitSet(1); 228} 229 230void hourLimitSetExit1(void) 231{ 232 hourLimitSetExit(1); 233} 234 235void hourLimitSetEnter2(void) 236{ 237 hourLimitSetEnter(2); 238} 239 240void hourLimitSet2(void) 241{ 242 hourLimitSet(2); 243} 244 245void hourLimitSetExit2(void) 246{ 247 hourLimitSetExit(2); 248} 249 250void hourLimitSetEnter3(void) 251{ 252 hourLimitSetEnter(3); 253} 254 255void hourLimitSet3(void) 256{ 257 hourLimitSet(3); 258} 259 260void hourLimitSetExit3(void) 261{ 262 hourLimitSetExit(3); 263} 264 265void progTempSetEnter(int n) 266{ 267 setProgTemp[n]=true; 268 dailyProgScreen(); 269} 270 271void progTempSet(int n) 272{ 273 if(event==cwRot) 274 { 275 progTemp[progNum][n]+=tempIncr; 276 if(progTemp[progNum][n]>30.0) 277 progTemp[progNum][n]=30.0; 278 dailyProgScreen(); 279 } 280 if(event==ccwRot) 281 { 282 progTemp[progNum][n]-=tempIncr; 283 if(progTemp[progNum][n]<5.0) 284 progTemp[progNum][n]=5.0; 285 dailyProgScreen(); 286 } 287} 288 289void progTempSetExit(int n) 290{ 291 setProgTemp[n]=false; 292 EEPROM.update(EEPROMProg+16*progNum+4*n+2, 293 (int)(10.01*progTemp[progNum][n]/256)); 294 EEPROM.update(EEPROMProg+16*progNum+4*n+3, 295 ((int)(10.01*progTemp[progNum][n])%256)); 296 if(mode==prog) setPointInit(); 297} 298 299void progTempSetEnter0(void) 300{ 301 progTempSetEnter(0); 302} 303 304void progTempSet0(void) 305{ 306 progTempSet(0); 307} 308 309void progTempSetExit0(void) 310{ 311 progTempSetExit(0); 312} 313 314void progTempSetEnter1(void) 315{ 316 progTempSetEnter(1); 317} 318 319void progTempSet1(void) 320{ 321 progTempSet(1); 322} 323 324void progTempSetExit1(void) 325{ 326 progTempSetExit(1); 327} 328 329void progTempSetEnter2(void) 330{ 331 progTempSetEnter(2); 332} 333 334void progTempSet2(void) 335{ 336 progTempSet(2); 337} 338 339void progTempSetExit2(void) 340{ 341 progTempSetExit(2); 342} 343 344void progTempSetEnter3(void) 345{ 346 progTempSetEnter(3); 347} 348 349void progTempSet3(void) 350{ 351 progTempSet(3); 352} 353 354void progTempSetExit3(void) 355{ 356 progTempSetExit(3); 357} 358 359void monProgSetEnter(void) 360{ 361 setDayProg=0; 362 weekProgScreen(); 363} 364 365void tueProgSetEnter(void) 366{ 367 setDayProg=1; 368 weekProgScreen(); 369} 370 371void wedProgSetEnter(void) 372{ 373 setDayProg=2; 374 weekProgScreen(); 375} 376 377void thuProgSetEnter(void) 378{ 379 setDayProg=3; 380 weekProgScreen(); 381} 382 383void friProgSetEnter(void) 384{ 385 setDayProg=4; 386 weekProgScreen(); 387} 388 389void satProgSetEnter(void) 390{ 391 setDayProg=5; 392 weekProgScreen(); 393} 394 395void sunProgSetEnter(void) 396{ 397 setDayProg=6; 398 weekProgScreen(); 399} 400 401void dayProgSet(void) 402{ 403 if(event==cwRot) 404 { 405 dayProg[setDayProg]++; 406 dayProg[setDayProg]%=3; 407 weekProgScreen(); 408 } 409 if(event==ccwRot) 410 { 411 dayProg[setDayProg]+=2; 412 dayProg[setDayProg]%=3; 413 weekProgScreen(); 414 } 415} 416 417void dayProgSetExit(void) 418{ 419 EEPROM.update(EEPROMWeek+setDayProg, 420 dayProg[setDayProg]); 421 if(mode==prog) setPointInit(); 422} 423 424/*Temperature display */ 425 426void temperatureDisplay(void) 427{ 428 displayChrono.now(); 429 if(displayChrono.elapsed>1000) 430 { 431 displayChrono.init(); 432 temperatureScreen(); 433 } 434 if(event==longSwitchPress || 435 event==longSwitchPressAndHeat) 436 { 437 minTemp=temp; 438 maxTemp=temp; 439 } 440} 441 442/* Heating behaviour display and set 443 functions */ 444 445void heatingBehaviourDisplay(void) 446{ 447 displayChrono.now(); 448 if(displayChrono.elapsed>1000) 449 { 450 displayChrono.init(); 451 heatingBehaviourScreen(); 452 } 453} 454 455void hysteresisSetEnter(void) 456{ 457 paramSetting=setHysteresis; 458 heatingBehaviourScreen(); 459} 460 461void hysteresisSet(void) 462{ 463 if(event==cwRot) 464 { 465 hysteresis+=tempIncr; 466 if(hysteresis>5.0) hysteresis=5.0; 467 heatingBehaviourScreen(); 468 } 469 if(event==ccwRot) 470 { 471 hysteresis-=tempIncr; 472 if(hysteresis<0.0) hysteresis=0.0; 473 heatingBehaviourScreen(); 474 } 475} 476 477void hysteresisSetExit(void) 478{ 479 paramSetting=noParam; 480 EEPROM.update(EEPROMHysteresisMSB, 481 (byte)((int)(hysteresis*10.01)>>8)); 482 EEPROM.update(EEPROMHysteresisLSB, 483 (byte)((int)(hysteresis*10.01)%256)); 484} 485 486void deltaTSetEnter(void) 487{ 488 paramSetting=setDeltaT; 489 heatingBehaviourScreen(); 490} 491 492void deltaTSet(void) 493{ 494 if(event==cwRot) 495 { 496 deltaT+=tempIncr; 497 if(deltaT>10.0) deltaT=10.0; 498 heatingBehaviourScreen(); 499 } 500 if(event==ccwRot) 501 { 502 deltaT-=tempIncr; 503 if(deltaT<0.0) deltaT=0.0; 504 heatingBehaviourScreen(); 505 } 506} 507 508void deltaTSetExit(void) 509{ 510 paramSetting=noParam; 511 EEPROM.update(EEPROMDeltaTMSB, 512 (byte)((int)(deltaT*10.01)>>8)); 513 EEPROM.update(EEPROMDeltaTLSB, 514 (byte)((int)(deltaT*10.01)%256)); 515} 516 517void minHeatPercentSetEnter(void) 518{ 519 paramSetting=setMinHeat; 520 heatingBehaviourScreen(); 521} 522 523void minHeatPercentSet(void) 524{ 525 if(event==cwRot && 526 minHeatPercent<maxHeatPercent) 527 { 528 minHeatPercent++; 529 heatingBehaviourScreen(); 530 } 531 if(event==ccwRot && minHeatPercent>0) 532 { 533 minHeatPercent--; 534 heatingBehaviourScreen(); 535 } 536} 537 538void minHeatPercentSetExit(void) 539{ 540 paramSetting=noParam; 541 EEPROM.update(EEPROMMinHeatPercent, 542 minHeatPercent); 543} 544 545void maxHeatPercentSetEnter(void) 546{ 547 paramSetting=setMaxHeat; 548 heatingBehaviourScreen(); 549} 550 551void maxHeatPercentSet(void) 552{ 553 if(event==cwRot && maxHeatPercent<100) 554 { 555 maxHeatPercent++; 556 heatingBehaviourScreen(); 557 } 558 if(event==ccwRot && 559 maxHeatPercent>minHeatPercent) 560 { 561 maxHeatPercent--; 562 heatingBehaviourScreen(); 563 } 564} 565 566void maxHeatPercentSetExit(void) 567{ 568 paramSetting=noParam; 569 EEPROM.update(EEPROMMaxHeatPercent, 570 maxHeatPercent); 571} 572 573void cycleTimeSetEnter(void) 574{ 575 paramSetting=setCycleTime; 576 heatingBehaviourScreen(); 577} 578 579void cycleTimeSet(void) 580{ 581 if(event==cwRot && cycleTime<=240) 582 { 583 cycleTime+=10; 584 heatingBehaviourScreen(); 585 } 586 if(event==ccwRot && cycleTime>=20) 587 { 588 cycleTime-=10; 589 heatingBehaviourScreen(); 590 } 591} 592 593void cycleTimeSetExit(void) 594{ 595 paramSetting=noParam; 596 EEPROM.update(EEPROMCycleTime, 597 cycleTime); 598} 599 600/* System display and set functions */ 601 602void systemDisplay(void) 603{ 604 displayChrono.now(); 605 if(displayChrono.elapsed>1000) 606 { 607 displayChrono.init(); 608 systemScreen(); 609 } 610} 611 612void sleepDelaySetEnter(void) 613{ 614 settingsSet=setSleepDelay; 615 settingsScreen(); 616} 617 618void sleepDelaySet(void) 619{ 620 if(event==cwRot) 621 { 622 if(sleepDelay<55) 623 sleepDelay+=5; 624 settingsScreen(); 625 } 626 if(event==ccwRot) 627 { 628 if(sleepDelay>=5) 629 sleepDelay-=5; 630 settingsScreen(); 631 } 632} 633 634void sleepDelaySetExit(void) 635{ 636 settingsSet=noSet; 637 EEPROM.update(EEPROMSleepDelay, sleepDelay); 638} 639 640void corrDS18B20SetEnter(void) 641{ 642 settingsSet=setDS18B20Corr; 643 settingsScreen(); 644} 645 646void corrDS18B20Set(void) 647{ 648 if(event==cwRot) 649 { 650 corrDS18B20+=tempIncr; 651 if(corrDS18B20>5.0) corrDS18B20=5.0; 652 settingsScreen(); 653 } 654 if(event==ccwRot) 655 { 656 corrDS18B20-=tempIncr; 657 if(corrDS18B20<-5.0) corrDS18B20=-5.0; 658 settingsScreen(); 659 } 660} 661 662void corrDS18B20SetExit(void) 663{ 664 settingsSet=noSet; 665 EEPROM.update(EEPROMCorrDS18B20MSB, 666 (byte) 667 ((short)(corrDS18B20*10.01)>>8)); 668 EEPROM.update(EEPROMCorrDS18B20LSB, 669 (byte) 670 ((short)(corrDS18B20*10.01)%256)); 671} 672 673void tempUnitSetEnter(void) 674{ 675 settingsSet=setTempUnit; 676 settingsScreen(); 677} 678 679void tempUnitSet(void) 680{ 681 if(event==cwRot || event==ccwRot) 682 { 683 if(tempUnit==Celsius) 684 { 685 tempUnit=Fahrenheit; 686 tempIncr=0.5/9.0; 687 } 688 else 689 { 690 tempUnit=Celsius; 691 tempIncr=0.1; 692 } 693 settingsScreen(); 694 } 695} 696 697void tempUnitSetExit(void) 698{ 699 settingsSet=noSet; 700 EEPROM.update(EEPROMTempUnit, tempUnit); 701} 702 703void languageSetEnter(void) 704{ 705 settingsSet=setLanguage; 706 settingsScreen(); 707} 708 709void languageSet(void) 710{ 711 if(event==cwRot) 712 { 713 switch(language) 714 { 715 case french : 716 language=english; 717 break; 718 case english : 719 language=french; 720 break; 721 } 722 settingsScreen(); 723 } 724 if(event==ccwRot) 725 { 726 switch(language) 727 { 728 case english : 729 language=french; 730 break; 731 case french : 732 language=english; 733 break; 734 } 735 settingsScreen(); 736 } 737} 738 739void languageSetExit(void) 740{ 741 settingsSet=noSet; 742 EEPROM.update(EEPROMLanguage, language); 743} 744 745/* Clock and calendar display and set 746 functions */ 747 748void timeDateDisplay(void) 749{ 750 static int oldSecond; 751 752 current=rtc.now(); 753 if(current.second()!=oldSecond) 754 { 755 oldSecond=current.second(); 756 year=current.year(); 757 month=current.month(); 758 dayOfMonth=current.day(); 759 hour=current.hour(); 760 minute=current.minute(); 761 second=current.second(); 762 timeSetting=none; 763 timeDateScreen(); 764 } 765} 766 767void timeUpdate(void) 768{ 769 rtc.adjust(DateTime(year, month, dayOfMonth, 770 hour, minute, second)); 771 if(mode==prog) setPointInit(); 772} 773 774void dateUpdate(void) 775{ 776 current=rtc.now(); 777 current.setyear(year); 778 current.setmonth(month); 779 current.setday(dayOfMonth); 780 rtc.adjust(current); 781 if(mode==prog) setPointInit(); 782} 783 784void hourSetEnter(void) 785{ 786 timeSetting=setHours; 787 current=rtc.now(); 788 year=current.year(); 789 month=current.month(); 790 dayOfMonth=current.day(); 791 hour=current.hour(); 792 minute=current.minute(); 793 second=current.second(); 794 timeDateScreen(); 795} 796 797void hourSet(void) 798{ 799 if(event==cwRot) 800 { 801 if(hour<23) 802 { 803 hour++; 804 } 805 else hour=0; 806 timeDateScreen(); 807 } 808 if(event==ccwRot) 809 { 810 if(hour>0) 811 { 812 hour--; 813 } 814 else hour=23; 815 timeDateScreen(); 816 } 817} 818 819void minuteSetEnter(void) 820{ 821 timeSetting=setMinutes; 822 timeDateScreen(); 823} 824 825void minuteSet(void) 826{ 827 if(event==cwRot) 828 { 829 if(minute<59) 830 { 831 minute++; 832 } 833 else minute=0; 834 timeDateScreen(); 835 } 836 if(event==ccwRot) 837 { 838 if(minute>0) 839 { 840 minute--; 841 } 842 else minute=59; 843 timeDateScreen(); 844 } 845} 846 847void secondSetEnter(void) 848{ 849 timeSetting=setSeconds; 850 timeDateScreen(); 851} 852 853void secondSet(void) 854{ 855 timeSetting=setSeconds; 856 if(event==cwRot) 857 { 858 if(second<59) 859 { 860 second++; 861 } 862 else second=0; 863 timeDateScreen(); 864 } 865 if(event==ccwRot) 866 { 867 if(second>0) 868 { 869 second--; 870 } 871 else second=59; 872 timeDateScreen(); 873 } 874} 875 876void yearSetEnter(void) 877{ 878 timeSetting=setYear; 879 current=rtc.now(); 880 year=current.year(); 881 month=current.month(); 882 dayOfMonth=current.day(); 883 timeDateScreen(); 884} 885 886void yearSet(void) 887{ 888 static int oldSecond; 889 890 current=rtc.now(); 891 hour=current.hour(); 892 minute=current.minute(); 893 second=current.second(); 894 if((event==cwRot) && (year<2100)) 895 { 896 year++; 897 timeDateScreen(); 898 } 899 if((event==ccwRot) && (year>2000)) 900 { 901 year--; 902 timeDateScreen(); 903 } 904 if(current.second()!=oldSecond) 905 { 906 oldSecond=current.second(); 907 timeDateScreen(); 908 } 909} 910 911void monthSetEnter(void) 912{ 913 timeSetting=setMonth; 914 timeDateScreen(); 915} 916 917void monthSet(void) 918{ 919 static int oldSecond; 920 921 current=rtc.now(); 922 hour=current.hour(); 923 minute=current.minute(); 924 second=current.second(); 925 if(event==cwRot) 926 { 927 month++; 928 if(month>12) month=1; 929 } 930 if(event==ccwRot) 931 { 932 month--; 933 if(month<1) month=12; 934 } 935 if(event==cwRot || event==ccwRot) 936 { 937 if ((month==4 || month==6 || month==9 || 938 month == 11) && 939 dayOfMonth==31) 940 dayOfMonth=30; 941 if (month==2 && dayOfMonth > 28) 942 dayOfMonth=28; 943 timeDateScreen(); 944 } 945 if(current.second()!=oldSecond) 946 { 947 oldSecond=current.second(); 948 timeDateScreen(); 949 } 950} 951 952void dayOfMonthSetEnter(void) 953{ 954 timeSetting=setDayOfMonth; 955 timeDateScreen(); 956} 957 958void dayOfMonthSet(void) 959{ 960 int numberOfDays=31; 961 static int oldSecond; 962 963 current=rtc.now(); 964 hour=current.hour(); 965 minute=current.minute(); 966 second=current.second(); 967 if(event==cwRot) 968 dayOfMonth++; 969 if(event==ccwRot) 970 dayOfMonth--; 971 if(event==cwRot || event==ccwRot) 972 { 973 if (month==4 || month==6 || month==9 || 974 month == 11) 975 numberOfDays=30; 976 if (month==2) 977 { 978 if (year%4!=0 || 979 (year%100==0 && year%400!=0)) 980 { 981 numberOfDays=28; 982 } 983 else 984 { 985 numberOfDays=29; 986 } 987 } 988 if(dayOfMonth<1) 989 dayOfMonth=numberOfDays; 990 if(dayOfMonth>numberOfDays) 991 dayOfMonth=1; 992 timeDateScreen(); 993 } 994 if(current.second()!=oldSecond) 995 { 996 oldSecond=current.second(); 997 timeDateScreen(); 998 } 999}
Downloadable files
Receiver schematics
Fixed part of the thermostat
Receiver schematics.jpg

Thermostat drawing
Mobile part of the thermostat
Thermostat drawing.jpg

Thermostat schematics
Mobile part of the thermostat
Thermostat schematics.jpg

Comments
Only logged in users can leave comments