-
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathART-ESP32-Touch-TFT-Thermostat-main.ino
1137 lines (826 loc) · 38.9 KB
/
ART-ESP32-Touch-TFT-Thermostat-main.ino
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
// hello
// https://oshwlab.com/l.dijkman/esp32-dev-kit-38-pin-to-spi-touch-tft
// https://github.com/ldijkman/ART-ESP32-Touch-TFT-Thermostat
// http://www.Arduino.TK
//
// https://m.facebook.com/groups/2643123052617990
// https://www.facebook.com/groups/esp32smartthermostat
//
// *****************************************************************************
// GNU General Public License,
// which basically means that you may freely copy, change, and distribute it,
// but you may not impose any restrictions on further distribution,
// and you must make the source code available.
// *****************************************************************************
//
// i have treid this program on various ESP32 38-Pin devices
// 38-Pin ESP32 WROOM 32 (one had a reset switch that does not work)
// 38-Pin ESP32 WROOM 32D
// 38-Pin ESP32 WROOM 32U (External antenne)
// 38-Pin ESP32 WROVER (one had a blob off solder (near G22) connecting two pins of ESP32Chip wich prevented programming)
//
// probably will also work on 30-32 pin ESP32 Devices
//
// on first startup the screen is for 10 to 20 seconds snowy / blank (a format message now)
// think its formatting the filesystem during that time
//
// TFT white screen / blank screen
// make sure u set the file
// ......................../arduino/libraries/TFT_eSPI/User_Setup.h
// Correct to match your TFT screen driver and hardware
//
// my example User_Setup.h settings at http://Arduino.TK
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//
//********************************************************************************
// 21 december 2020 switched to BME280 temp, mbar, humid, sensor == much better
//********************************************************************************
// ART ESP32 Thermostat by luberth dijkman
// https://oshwlab.com/l.dijkman/esp32-dev-kit-38-pin-to-spi-touch-tft
// https://create.arduino.cc/editor/luberth/becc77e8-4000-4673-9412-dbaac0a3b268/preview
// https://www.youtube.com/user/LuberthDijkman
// https://m.facebook.com/luberth.dijkman
// 320x240 screen or bigger but then the display is 320x240
// under construction
//
// https://youtu.be/CM0h_ad7ETU by Fabio Mastrotto, He got me into this trouble
// ART ESP32Thermostat by luberth dijkman
// https://oshwlab.com/l.dijkman/esp32-dev-kit-38-pin-to-spi-touch-tft
// under construction
// Thank you for the Coffee!
// https://paypal.me/LDijkman
#include <WiFi.h>
#include <WebServer.h>
WebServer server(80);
#include <WiFiClient.h>
// some say do not use spaces in broadcasted wifi router name
const char* ssid = "Bangert-30-Andijk"; // wifi router name broadcasted in the air by your wifi router
const char* password = "password"; // your wifi router password
const char* soft_ap_ssid = "ART Thermostat Access Point"; // AP wifi name broadcasted in the air for direct connection
const char* soft_ap_password= "";
#include <NTPClient.h> // Include NTPClient library https://github.com/arduino-libraries/NTPClient sketch include lib install from zip
#include <TimeLib.h> // Include Arduino time library https://github.com/PaulStoffregen/Time sketch include lib install from zip
WiFiUDP ntpUDP;
//#include <moonPhase.h> // http://github.com/CelliesProjects/moonPhase-esp32 download zip, and install library from zip
// You can specify the time server pool and the offset, (in seconds)
// additionaly you can specify the update interval (in milliseconds).
byte NTP_Offset = 1; // NTP time offset in hours + or -
//NTPClient timeClient(ntpUDP, "europe.pool.ntp.org", NTP_Offset * 60 * 60, 24 * 60 * 60 * 1000); // offset in seconds, 24 hour update
NTPClient timeClient(ntpUDP, "time.google.com", NTP_Offset * 60 * 60, 24 * 60 * 60 * 1000); // offset in seconds, 24 hour update
//NTPClient timeClient(ntpUDP, "time.nist.gov", NTP_Offset * 60 * 60, 24 * 60 * 60 * 1000); // offset in seconds, 24 hour update
int last_second = 0, second_ = 0, minute_ = 0, hour_ = 0, day_ = 0, month_ = 0, year_ = 0; // some variables for NTP time
unsigned long unix_epoch;
#include "FS.h" // i guess File System
#include <SPI.h> // i guess Serial Peripheral Interface
#include <TFT_eSPI.h> // Hardware-specific TFT SPI library https://github.com/Bodmer/TFT_eSPI
TFT_eSPI tft = TFT_eSPI(); // Invoke custom TFT library
// The SPIFFS (FLASH filing system) is used to hold touch screen calibration data
// This is the file name used to store the calibration data file, name must start with "/".
#define CALIBRATION_FILE "/TouchCalData"
//#define FORMAT_SPIFFS_IF_FAILED 0
// Set REPEAT_CAL to true instead of false or 1 or 0 to run calibration
byte REPEAT_CAL = 0; // repeat call flag fr calibration
byte drawgreendot = 1; // draw touch position with a greendot
// IMPORTANTE!
// set to 0 if RTClock is programmed and program arduino again with this set to 0
byte Force_DateTimeRewrite = 0; // if 1 write time and date to DS3231 RTClock // 1= each reboot will set the time and date of first program loading
// you can set time and date on tft now
#include <Wire.h>
#define I2C_SDA 33 // Gpio 33 non standard i2c adress
#define I2C_SCL 32 // Gpio 32 non standard i2c adress
#include "RTClib.h" // https://github.com/adafruit/RTClib
RTC_DS3231 rtc; // download zip from above and install library from zip
// Sketch=>include library=>Add ZIP Library
#include <Adafruit_Sensor.h> // used zip from https://github.com/adafruit/Adafruit_Sensor
#include <Adafruit_BME280.h> // used zip from https://github.com/adafruit/Adafruit_BME280_Library
// Sketch=>include library=>Add ZIP Library
#define SEALEVELPRESSURE_HPA (1013.25)
Adafruit_BME280 BME280; // I2C
bool BME280_status;
const int ledPin = 17; // corresponds to GPIO17 PWM for backlight brightness
// connect to LED of SPI TFT display
// setting PWM properties
const int freq = 4000; // hz
const int ledChannel = 0; // think channel 0 is in use by buzzer
const int resolution = 8; // 8 bit = 0 to 255
byte backgroundlightval = 127; // not below 5 and upto to 255 backlight brightness better not totaly black
byte nightbackgroundlightval = 10;
// Color definitions
#define BLACK 0x0000
#define BLUE 0x001F
#define RED 0xF800
#define GREEN 0x07E0
#define CYAN 0x07FF
#define MAGENTA 0xF81F
#define YELLOW 0xFFE0
#define WHITE 0xFFFF
#define NAVY 0x000F
#define DARKGREEN 0x03E0
#define DARKCYAN 0x03EF
#define MAROON 0x7800
#define PURPLE 0x780F
#define OLIVE 0x7BE0
#define LIGHTGREY 0xC618
#define DARKGREY 0x4208
#define ORANGE 0xFD20
#define GREENYELLOW 0xAFE5
#define PINK 0xF81F
#define dutchorange 0xfbc0
#define iceblue 0x1dfb
// pitty you can not enter a colorcode on next page RGB565 colours: https://chrishewett.com/blog/true-rgb565-colour-picker/
unsigned long TempLong; // some variables for storing millis
unsigned long touchtime;
unsigned long runTime;
unsigned long runTime2;
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
const int heat_relais_pin = 26; // Gpio 26 relais Heat for control central heating
const int cool_relais_pin = 25; // Gpio 25 relais Cool for aico / fan
float TempCelsius = 20;
byte HeatState = 0;
byte CoolState = 0;
// name "mode" should be changed its colored orange allready used by Arduino or library?
// changed name "mode" to "modus"
byte modus = 1; // start with eco modus that is safest
byte oldmodus;
double decrement_step = 0.1; // steps for + and - button
double temp_setpoint = 20;
double normal_setpoint = 21; // save our planet
double auto_setpoint = 20; // save our planet
double eco_setpoint = 15; // save our planet
double cool_setpoint = 25; // save our planet
int time_in_minutes;
float CalibrationOffset = 0.0; // correction for actual temperature +or-
float switchbelowset = 0.2; // switch point below
float switchaboveset = 0.2; // switch poit above
// some things for sleepless nights
// float lowtempalarm = 5;
// float hightempalarm = 35;
// int timetosetpointtolong = 30; // min
// int timeheatontolong = 60; // minutes
// int minumumheatontime = 4; // minutes can imagine if not getting hot condesation corrosion
// int maximumheatontime = 60; // desired temperature not reached within .. minutes
int oldminute;
int X;
const char *monthName[12] = {"Januari", "Februari", "March", "April", "May", "Juni",
"Juli", "Augustus", "September", "October", "November", "December"
};
char dayname[7][12] = {"Sunday ", "Monday ", "Tuesday ", "Wednesday ", "Thursday ", "Friday ", "Saturday "};
float HeatONhour[20], HeatONminute[20], tempON[20];
float HeatOFFhour[20], HeatOFFminute[20], tempOFF[20];
uint16_t x, y;
uint16_t calibrationData[5];
uint8_t calDataOK = 0;
byte out = 0; // a flag, goto label: did not work
byte fullscreenactive = 0; // flag fullscreen 0 or 1
int secondstoswitchtofullscreen = 20; // seconds to go fullscreen with barometer and humdity
int bordercolor = dutchorange;
byte DOW; // my week 1=monday 7=sunday = yes = real weekends
byte BlinkState;
void setup(void) {
// configure LED PWM functionalitites // screen brightness background light
ledcSetup(ledChannel, freq, resolution);
// attach the channel to the GPIO to be controlled
ledcAttachPin(ledPin, ledChannel);
ledcWrite(ledChannel, backgroundlightval); // 100 +/- halfbright 0-255 PWM screen brightness background light
// Jo less energy
Wire.begin(I2C_SDA, I2C_SCL); // start i2c on non stndard i2c pins
pinMode(heat_relais_pin, OUTPUT);
pinMode(cool_relais_pin, OUTPUT);
digitalWrite(heat_relais_pin, HIGH); // HIGH = heat output relais off
digitalWrite(cool_relais_pin, HIGH); // HIGH = cool output relais off
// times must be from 00:00 to 23:59 following sequence??? maybe left 00:00 if not used
// 3 on/off switch times a day monday to friday
//5:30 to 6:30
HeatONhour[0] = 5, HeatONminute[0] = 30, tempON[0] = 21;
HeatOFFhour[0] = 6, HeatOFFminute[0] = 30, tempOFF[0] = 14;
//11:00 to 12:30
HeatONhour[1] = 11, HeatONminute[1] = 00, tempON[1] = 20;
HeatOFFhour[1] = 12, HeatOFFminute[1] = 30, tempOFF[1] = 16;
//16:00 to 23:00
HeatONhour[2] = 16, HeatONminute[2] = 00, tempON[2] = 20;
HeatOFFhour[2] = 23, HeatOFFminute[2] = 00, tempOFF[2] = 12;
// 3 on/off switch times a day saturday to sunday
//8:00 to 9:00
HeatONhour[10] = 8, HeatONminute[10] = 00, tempON[10] = 21;
HeatOFFhour[10] = 9, HeatOFFminute[10] = 00, tempOFF[10] = 14;
//11:00 to 13:00
HeatONhour[11] = 11, HeatONminute[11] = 00, tempON[11] = 20;
HeatOFFhour[11] = 13, HeatOFFminute[11] = 00, tempOFF[11] = 16;
//15:00 to 23:30
HeatONhour[12] = 15, HeatONminute[12] = 00, tempON[12] = 20;
HeatOFFhour[12] = 23, HeatOFFminute[12] = 30, tempOFF[12] = 12;
Serial.begin(115200); // serial monitor
tft.init(); // tft_espi
tft.setRotation(1); // TFT SPI setrotation before touch calibration
tft.fillScreen(TFT_BLACK); // Clear the screen
tft.drawRoundRect(1, 1, 319, 239, 2, DARKGREY); // show screen size on bigger display
tft.setCursor(0, 60);
tft.setTextColor(LIGHTGREY); tft.setTextSize(2);
tft.println("Format FileSystem"); // if its a new blank chip show a message
tft.println("10 to 20 seconds?");
tft.setTextSize(1); tft.setCursor(20, 230);
tft.println("Made by Luberth Dijkman Andijk The Netherlands");
touch_calibrate(); // TFT Calibrate the touch screen and retrieve the scaling factors
tft.fillScreen(TFT_BLACK); // Clear the screen
tft.drawRoundRect(1, 1, 319, 239, 2, DARKGREY); // show screen size on bigger display
tft.setCursor(0, 60);
tft.setTextColor(LIGHTGREY); tft.setTextSize(3);
tft.println(" ART Thermostat");
tft.println(" The ART of");
tft.println(" Temperature");
tft.println(" Controlled");
tft.setTextSize(1); tft.setCursor(20, 230);
tft.println("Made by Luberth Dijkman Andijk The Netherlands");
// 8 second delay with countdown on screen
TempLong = millis(); // store millis() counter in temporary variable TempLong
while (1 == 1) { // 1 wil always be 1 so forever
if ((millis() - TempLong) > 8000)break; // after 8 seconds break while loop
tft.setCursor(155, 200); tft.setTextSize(3);
tft.setTextColor (LIGHTGREY, BLACK);
//tft.print(8 - ((millis() - TempLong) / 1000)); tft.print(" "); // tft print the countdown
tft.drawRoundRect(8 , 170, 304, 16, 8, GREEN); // illusion progress loadbar outline
tft.fillRoundRect(10, 172, map((millis() - TempLong), 0, 8000, 10, 300), 12, 5, GREEN); // illusion progress loadbar
}
if (! rtc.begin()) {
tft.fillScreen(RED);
tft.setTextColor(YELLOW); tft.setTextSize(3);
while (! rtc.begin()) {
Serial.println("Could not find RTC, i2c DS3231 realtimeclock not found");
tft.setCursor(0, 30);
tft.println(" DS3231 RTC & BME280");
tft.println(" Not Found");
tft.println(" RTC i2c on pin");
tft.println(" SDA=G33 SCL=G32");
tft.println(" VCC=3.3V & GND");
}
tft.fillScreen(GREEN);
tft.setTextColor(BLACK);
tft.setCursor(0, 80);
tft.print(" YES found RTC");
delay(10000);
}
tft.setTextColor(LIGHTGREY);
BME280_status = BME280.begin(0x76);
if (!BME280_status) {
Serial.println("Could not find a valid BME280 sensor, check wiring!");
tft.fillScreen(RED); tft.setTextSize(3);
tft.setCursor(10, 30);
tft.setTextColor(YELLOW);
tft.println("BME280 Not Found");
delay(20000);
}
// set the time from PC to DS3231 RTC
if (rtc.lostPower() || Force_DateTimeRewrite == 1) { // means OR
tft.fillScreen(MAROON);
tft.setCursor(0, 80);
tft.setTextSize(2);
tft.print(" RTC Setting xTime/Date");
tft.setTextSize(3);
delay(5000); // 5 seconds delay
// if you uncomment above if, forcing to program time date
// then every time you reboot the thermostat
// time is set to the time when you loaded the program into the arduino
//
Serial.println("RTC lost power, lets set the time!");
// following line sets the RTC to the date & time this sketch was compiled
rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
// This line sets the RTC with an explicit date & time, for example to set
// 2020 juli 24 20:15:00 you would call:
// rtc.adjust(DateTime(2020, 7, 24, 20, 15, 0));
}
drawmainscreen(); // jump to tab file drawmainscreen
tft.print(" ");
/*draw a grid
tft.fillRect(1, 1, 4, 4, YELLOW); // yellow origin xy
tft.fillRect(316, 236, 4, 4, GREEN); // green max xy
//draw gridlines 20x20pixels
for (int i = 0; i <= 320; i = i + 20) {
tft.fillRect(i, 1, 1, 319, 0x1111);
}
for (int i = 0; i <= 320; i = i + 20) {
tft.fillRect(1, i, 320, 1, 0x1111);
}
*/
tft.setTextColor(GREEN, BLACK);
tft.setCursor(15, 30);
WiFi.disconnect(); // not needed?
// WiFi.mode(WIFI_STA); // Connect to your wifi
WiFi.mode(WIFI_AP_STA); // Connect to your wifi access point an station mode
WiFi.softAP(soft_ap_ssid, soft_ap_password); // set access point wifi name broadcasted in the air
WiFi.begin(ssid, password); // Start the Wi-Fi services
Serial.println("Connecting to WiFi : " + String(ssid));
tft.println("Connecting to WiFi : " + String(ssid));
TempLong = millis(); // store millis() counter in variable TempLong
while (WiFi.waitForConnectResult() != WL_CONNECTED) { // Wait for WiFi to connect
tft.setCursor(20, 40);
tft.print(60 - ((millis() - TempLong) / 1000)); tft.print(" ");
if ((millis() - TempLong) > 60000)break; // timeout exit if it takes to lomg 60 seconds = nowifi
}
Serial.println(" Connected to : " + String(ssid)); // serial print broadcasted router wifi name
tft.setCursor(15, 30);
tft.println(" " + String(ssid) + " "); // tft print broadcasted router wifi name
tft.setCursor(120, 40);
tft.println(WiFi.localIP()); // tft print ip adres
Serial.print("Use IP address: ");
Serial.println(WiFi.localIP()); // IP address assigned to your ESP32
//----------------------------------------------------------------
server.on("/", handleRoot); // This displays the main webpage, when you open a client connection browser
server.on("/temp", handleTEMP); // To update Temperature called by the function getSensorData
server.on("/humid", handleHUMID); // To update Humidity called by the function getSensorData
server.on("/pressure", handlePRESS); // To update Pressure called by the function getSensorData
server.on("/modus", handlemodus); // To update modus called by the function getSensorData
server.on("/modus0", handlemodus0); // To update modus0 called by the function getSensorData
server.on("/modus1", handlemodus1); // To update modus1 called by the function getSensorData
server.on("/modus2", handlemodus2); // To update modus2 called by the function getSensorData
server.on("/modus3", handlemodus3); // To update modus3 called by the function getSensorData
//----------------------------------------------------------------
server.begin(); // Start the webserver
timeClient.begin(); // start NTP?
}
void loop() {
DateTime now = rtc.now(); // DS3231 RTC RealTimeClock
timeClient.update(); // NTP time
server.handleClient(); // webserver Keep checking for a client connection
unix_epoch = timeClient.getEpochTime(); // Get Unix epoch time from the NTP server
second_ = second(unix_epoch);
if (last_second != second_) { // do next only once each new second
Serial.print("GetFormattedTime "); Serial.println(timeClient.getFormattedTime()); // NTP
tft.setTextColor(GREEN, BLACK);
tft.setTextSize(1);
tft.setCursor(120, 50);
tft.println("NTP Time: " + timeClient.getFormattedTime());
Serial.print("DayOfWeek "); Serial.println(timeClient.getDay()); // ntp
Serial.print("seconds since 1-1-1970 "); Serial.println(timeClient.getEpochTime()); // ntp
Serial.print("hour "); Serial.println(hour(unix_epoch)); // ntp
Serial.print("minute "); Serial.println(minute(unix_epoch)); // ntp
Serial.print("second "); Serial.println(second(unix_epoch)); // ntp
Serial.print("day "); Serial.println(day(unix_epoch)); // ntp
Serial.print("month "); Serial.println(month(unix_epoch)); // ntp
Serial.print("year "); Serial.println(year(unix_epoch)); // ntp
Serial.print("Task running on core "); // am i using only 1 core of dual core ESP32?
Serial.println(xPortGetCoreID());
TempCelsius = BME280.readTemperature(); // get temp from BME280
TempCelsius = TempCelsius + CalibrationOffset;
// Serial.print("Fahrenheit = "); Serial.print(Tf, 1);
Serial.print(" Celsius = "); Serial.println(TempCelsius, 1);
// https://www.google.com/search?q=3+fahrenheit+to+celsius
tft.setCursor(165, 65);
tft.setTextColor(LIGHTGREY, BLACK);
tft.setTextSize(5);
tft.println(TempCelsius, 1); // print actual temperature to the screen
Serial.print("Temperature = ");
Serial.print(TempCelsius);
Serial.println(" *C");
// Convert temperature to Fahrenheit
// Serial.print("Temperature = ");
// Serial.print(1.8 * BME280.readTemperature() + 32);
// Serial.println(" *F");
Serial.print("Pressure = ");
Serial.print(BME280.readPressure() / 100.0F);
Serial.println(" hPa");
Serial.print("Approx. Altitude = ");
Serial.print(BME280.readAltitude(SEALEVELPRESSURE_HPA));
Serial.println(" m");
Serial.print("Humidity = ");
Serial.print(BME280.readHumidity());
Serial.println(" %");
Serial.println();
tft.setTextSize (2);
tft.setTextColor (LIGHTGREY, BLACK);
tft.setCursor(30, 100);
if (now.hour() < 10)tft.print(" "); // print 01 to 09 as 1 to 9
tft.print(now.hour());
tft.print(":");
if (now.minute() < 10)tft.print("0"); // print 1 to 9 as 01 to 09
tft.print(now.minute());
tft.print(":");
if (now.second() < 10)tft.print("0"); // print 1 to 9 as 01 to 09
tft.print(now.second());
tft.setTextSize (1);
tft.setTextColor (DARKGREY, BLACK);
tft.setCursor(15, 2);
tft.print("Day ");
tft.print(now.dayOfTheWeek()); // prints daynumber of the week, weekend sux, sunday=0, saturday=6
tft.print(" DOW ");
tft.print(DOW); // prints my DayOfWeek with a real weekend 1=monday ... 6=saturday 7=sunday
tft.setTextSize (2);
tft.setTextColor (LIGHTGREY, BLACK);
tft.setCursor(17, 130);
tft.print(dayname[now.dayOfTheWeek()]);
tft.print(now.day());
tft.print(" ");
tft.print(monthName[now.month() - 1]);
tft.print(" ");
//tft.print(now.year());
//tft.print(" ");
oldminute = now.minute();
last_second = second_;
} // end last_second not is second_
// Jo energy saving Backlight
if (now.hour() < 8) {
ledcWrite(ledChannel, 10);
} else {
ledcWrite(ledChannel, backgroundlightval);
}
if (now.hour() >= 23) {
ledcWrite(ledChannel, 10); // dim backround light display if hour >= 22uur //backgroundlightval);
}
if (((millis() - touchtime) / 1000) <= 60) {
ledcWrite(ledChannel, backgroundlightval); // if display is touched keep it bright for 60 seconds
}
while (! rtc.begin() || rtc.lostPower() == 1) { // lost RTC DS3231 Realtimeclock
// Glitch?
delay(100);
while (! rtc.begin() || rtc.lostPower() == 1) { // doublecheck try it again
tft.fillScreen(RED);
tft.setTextColor(YELLOW); tft.setTextSize(2);
delay(200);
Serial.println("Couldn't find RTC i2c realtimeclock not found");
tft.setCursor(0, 70);
tft.println (" RTC realtimeclock lost");
tft.println (" RTC i2c on SDA SCL 20 21");
tft.println (" or power on RTC lost ");
tft.println (" ");
tft.println (" ShutDown Heat relais ");
delay(500);
tft.fillScreen(BLACK);
tft.drawRoundRect(1, 1, 319, 239, 2, DARKGREY); // show screen size on bigger display
digitalWrite(heat_relais_pin, LOW); // heat output off
}
}
// alike arduino blink with no delay heartbeat not realy needed anymore, because there is seconds display now
currentMillis = millis();
if (currentMillis - previousMillis >= 500) { // half second on off
previousMillis = currentMillis;
if (BlinkState == 0) {
tft.setTextColor(RED, BLACK);
BlinkState = 1;
} else {
tft.setTextColor( BLACK, BLACK);
BlinkState = 0;
}
tft.setTextSize(1);
tft.setCursor(310, 3);
tft.println("o"); // tft.println(char(3)); // heart symbol // Alive HEARTBEAT
}
if (millis() - runTime >= 1000) { // Execute every 1000ms
runTime = millis(); // store millis() counter in variable runtime
server.handleClient(); // Keep checking for a client connection
time_in_minutes = (now.hour() * 60 + now.minute()); //time to minutes makes it easier to switch on a time
//test hardcoded switch on day / time array
// stupid start the week with sunday => no more weekends
// in The Netherlands the week starts with monday, we have weekends
// lets make real weekends
DOW = now.dayOfTheWeek(); // sux 0=sunday saturday=6 = only saturday weekend, that sux
if (DOW == 0) DOW = 7; // make sunday = 0 to sunday = 7 = yes = real weekends
// monday to friday
if (DOW >= 1 && DOW <= 5 ) { // 1=monday to 5=friday
Serial.println("it is a weekday");
// timeinminutes is more easy to work switch with versus hours:minutes
// timeinseconds is not needed minutes is accurate enough
// 24x60=1440 minutes a day
for (X = 0; X <= 2; X++) {
//Serial.println(X);
if (time_in_minutes >= HeatOFFhour[X] * 60 + HeatOFFminute[X] ) {
auto_setpoint = tempOFF[X];
}
if (time_in_minutes >= HeatONhour[X] * 60 + HeatONminute[X] && time_in_minutes < HeatOFFhour[X] * 60 + HeatOFFminute[X]) {
auto_setpoint = tempON[X];
goto JumpOver; // programmers do not like GOTO, i liked gwbasic ;-)
}
}
}// end weekday >=1 && <=5 mon...fri
// saturday sunday;
// stupid start the week with sunday => no more weekends
// in The Netherlands the week starts with monday, we have weekends
if (DOW == 6 || DOW == 7) { // 6=saturday 7=sunday;
Serial.println("hieperdepiep hoera weekend");
// timeinminutes is more easy to work switch with versus hours:minutes
// timeinseconds is not needed minutes is accurate enough
// 24x60=1440 minutes a day
for (X = 10; X <= 12; X++) { // <= smaller or equal, x++ means x=x+1
//Serial.println(X);
if (time_in_minutes >= HeatOFFhour[X] * 60 + HeatOFFminute[X] ) {
auto_setpoint = tempOFF[X];
}
if (time_in_minutes >= HeatONhour[X] * 60 + HeatONminute[X] && time_in_minutes < HeatOFFhour[X] * 60 + HeatOFFminute[X]) {
auto_setpoint = tempON[X];
goto JumpOver; // programmers do not like GOTO, i liked gwbasic ;-)
}
}
}// end DOW 6 || 7 sat sun
JumpOver:
Serial.println("i just jumped over");
redraw_modus_button();
OUTSUB();
} // end Execute every 1000ms=1second
tft.setTextColor (DARKGREY, BLACK);
tft.setTextSize(1);
tft.setCursor(250, 2);
tft.print(((millis() - touchtime) / 1000)); // last touch secondstoswitchtofullscreen seconds ago, go fullscreen
if ((millis() - touchtime) / 1000 < 2)tft.print(" "); // erase old countertext after reset counter
if ((fullscreenactive == 0) && (((millis() - touchtime) / 1000) >= secondstoswitchtofullscreen)) {
fullscreenactive = 1; // show fullscreen with milibar and humidity
oldmodus = modus; // if modus changes online redraw buttons
tft.fillRoundRect(5, 155, 310, 80, 1, BLACK); // erase buttons for fullscreen barometer en humidity text
}
if (tft.getTouch(&x, &y)) {
touchtime = millis(); // store touch time millis() for future screen aninmation if touch is longer as ?? time ago
//print touch xy position to serial monitor
Serial.print(x);
Serial.print(",");
Serial.println(y);
tft.setCursor(140 , 2);
tft.print("X="); tft.print(x); tft.print(" ");
tft.setCursor(180, 2);
tft.print("Y="); tft.print(y); tft.print(" ");
if (drawgreendot)tft.drawPixel(x, y, GREEN);
// press on mainscreen / top of screen opens settings menu
if (x > 0 && x < 320 && y > 0 && y < 140) {
settings_one_screen(); // open settings menu
fullscreenactive = 0;
drawmainscreen(); // restore main screen
}
if (fullscreenactive == 1) {
// touch in bottomscreen makes buttons visible and active
if (x > 0 && x < 320 && y > 165 && y < 240) {
fullscreenactive = 0; // show fullscreen with milibar and humidity
delay(250); // better should be wait for touchrelease
x = 0; y = 0; // otherwise it could be seen as a button press
tft.fillRoundRect(5, 155, 310, 80, 1, BLACK); // erase old barometer and humidity text
}
}
if (fullscreenactive == 0) { // if not fullscreen touch buttons should not react to touch when in fullscreen
// modus touch button
if (x > 100 && x < 200 && y > 165 && y < 240) {
modus = modus + 1; // if mode button is touched switch to next mode
if (modus > 3)modus = 0; // 0=normal 1=eco 2=auto 3=Cool
if (modus == 0) { // nomal continu modus at comfort temperature
tft.fillRoundRect(117, 162, 86, 66, 12, BLACK); // erase old button text
tft.setCursor(130, 173);
tft.setTextColor(LIGHTGREY); tft.setTextSize(2);
tft.println("NORMAL");
tft.setCursor(130, 200);
tft.println("modus");
tft.setTextSize(4);
delay(750);
OUTSUB();
}
if (modus == 1) { // eco continu modus at goosebumbs temperature
tft.fillRoundRect(117, 162, 86, 66, 12, BLACK); // erase old button text
tft.setCursor(144, 173);
tft.setTextColor(GREEN); tft.setTextSize(2);
tft.println("ECO");
tft.setCursor(130, 200);
tft.println("modus");
tft.setTextSize(4);
delay(750);
OUTSUB();
}
if (modus == 2) { // 2=automodus switch temperature by time program
tft.fillRoundRect(117, 162, 86, 66, 12, BLACK); // erase old button text
tft.setCursor(135, 173);
tft.setTextColor(dutchorange); tft.setTextSize(2);
tft.println("AUTO");
tft.setCursor(130, 200);
tft.println("modus");
tft.setTextSize(4);
delay(750);
OUTSUB();
}
if (modus == 3) { // 3=cool modus airco modus
tft.fillRoundRect(117, 162, 86, 66, 12, BLACK); // erase old button text
tft.setCursor(135, 173);
tft.setTextColor(iceblue); tft.setTextSize(2);
tft.println("COOL");
tft.setCursor(130, 200);
tft.println("modus");
tft.setTextSize(4);
delay(750);
OUTSUB();
}
}
// - touch button
if (x > 0 && x < 90 && y > 165 && y < 240) {
// 0=normal 1=eco 2=auto 3=Cool
tft.setTextSize(4); // 0=normal 1=eco 2=auto 3=Cool
tft.setCursor(35, 65);
if (modus == 0) { // normal
normal_setpoint = (normal_setpoint - decrement_step);
if (normal_setpoint < 10)normal_setpoint = 10;
tft.setTextColor(LIGHTGREY, BLACK);
tft.print(normal_setpoint, 1);
}
if (modus == 1) { // eco
eco_setpoint = (eco_setpoint - decrement_step);
if (eco_setpoint < 10)eco_setpoint = 10;
tft.setTextColor(GREEN, BLACK);
tft.print(eco_setpoint, 1);
}
if (modus == 2) { // auto
auto_setpoint = (auto_setpoint - decrement_step); // does not work in automode because it wil pop back to programmed value
if (auto_setpoint < 10)auto_setpoint = 10;
tft.setTextColor(dutchorange, BLACK);
tft.print(auto_setpoint, 1);
}
if (modus == 3) { // cool
cool_setpoint = (cool_setpoint - decrement_step);
if (cool_setpoint < 10)cool_setpoint = 10;
tft.setTextColor(iceblue, BLACK);
tft.print(cool_setpoint, 1);
}
delay(50);
}
// + touch button
if (x > 220 && x < 320 && y > 165 && y < 240) {
tft.setTextSize(4); // 0=normal 1=eco 2=auto 3=Cool
tft.setCursor(35, 65);
if (modus == 0) { // normal
normal_setpoint = (normal_setpoint + decrement_step);
if (normal_setpoint > 30)normal_setpoint = 30;
tft.setTextColor(LIGHTGREY, BLACK);
tft.print(normal_setpoint, 1);
}
if (modus == 1) { // eco
eco_setpoint = (eco_setpoint + decrement_step);
if (eco_setpoint > 30)eco_setpoint = 30;
tft.setTextColor(GREEN, BLACK);
tft.print(eco_setpoint, 1);
}
if (modus == 2) { // auto
auto_setpoint = (auto_setpoint + decrement_step); // does not work in automode because it wil pop back to programmed value
if (auto_setpoint > 30)auto_setpoint = 30;
tft.setTextColor(dutchorange, BLACK);
tft.print(auto_setpoint, 1);
}
if (modus == 3) { // cool
cool_setpoint = (cool_setpoint + decrement_step);
if (cool_setpoint > 30)cool_setpoint = 30;
tft.setTextColor(iceblue, BLACK);
tft.print(cool_setpoint, 1);
}
delay(50);
}
} // end if not fullscreen touch buttons should not react to touch when in fullscreen
} // end if (tft.getTouch(&x, &y))
} // end loop
void OUTSUB() {
runTime2 = millis();
// 0=normal 1=eco 2=auto 3=Cool
if (modus == 0) { // normal
CoolState = 0;
if (TempCelsius > (normal_setpoint + switchaboveset))HeatState = 0;
if (TempCelsius < (normal_setpoint - switchbelowset))HeatState = 1;
}
if (modus == 1) { // eco
CoolState = 0;
if (TempCelsius > (eco_setpoint + switchaboveset))HeatState = 0;
if (TempCelsius < (eco_setpoint - switchbelowset))HeatState = 1;
}
if (modus == 2) { // auto
CoolState = 0;
if (TempCelsius > (auto_setpoint + switchaboveset))HeatState = 0;
if (TempCelsius < (auto_setpoint - switchbelowset))HeatState = 1;
}
if (modus == 3) { // cool
HeatState = 0;
if (TempCelsius > (cool_setpoint + switchaboveset)) CoolState = 1;
if (TempCelsius < (cool_setpoint - switchbelowset)) CoolState = 0;
}
if (HeatState == 0 ) {
if (!fullscreenactive) {
tft.drawRoundRect(10, 10, 300, 140, 8, BLUE);
}
if (fullscreenactive) {
tft.drawRoundRect(10, 10, 300, 220, 8, BLUE);
}
tft.setTextSize (1);
tft.setTextColor (BLUE, BLACK);
tft.setCursor(130, 13);
tft.print(" ");
tft.print(rtc.getTemperature());
tft.print(char(247)); // C degree sign
tft.print(" C ");
digitalWrite(heat_relais_pin, HIGH); // HIGH = heat output relais off
}
if (HeatState == 1 ) {
bordercolor = dutchorange;
if (!fullscreenactive) {
tft.drawRoundRect(10, 10, 300, 140, 8, bordercolor);
}
if (fullscreenactive) {
tft.drawRoundRect(10, 10, 300, 220, 8, bordercolor);
}
tft.setTextSize (1);
tft.setTextColor (dutchorange, BLACK);
tft.setCursor(130, 13);
tft.print(" ");
tft.print(rtc.getTemperature());
tft.print(char(247)); // C degree sign
tft.print(" C ");
digitalWrite(heat_relais_pin, LOW); // LOW = heat output relais on
}
if (CoolState == 0 ) {
if (modus == 3) {