-
Notifications
You must be signed in to change notification settings - Fork 0
/
ESP32WeatherServer_final_display.ino
1188 lines (1048 loc) · 51.2 KB
/
ESP32WeatherServer_final_display.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
/*
Server program koji upravlja merenjem jedne meteo stanic u mom dvoristu.
Hardwer servera je ESP32 koji se nalazi u kuci u blizini wifi rutera i
24h je dostupan direktno preko ip adrese : http://109.94.233.37:3003/ ili
putem redirektovanog domena : http://meteostanica-sid.ddns.net/.
Drugi modul koji je ESP8266 nalazi se u samoj meteo kucici i radi kao klijent
koji svakih 10 min salje izmerene meteoroloske podatke na server a server ih
cini dostupnim za pristup putem interneta preko navedenih linkova.
Ovaj projekat je nadogradnja projekta sa upotrebom display-a
Program se moze koristitu i u neke vase svrhe koje su slicnog karaktera i
namene bez da morate bilo koga da obavestite o tome.
Copyright (C) 2021. me[R]a
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/
*/
//#define ESP8266
#if defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPClient.h>
#else
#include <WiFi.h>
#include <WebServer.h>
#include <HTTPClient.h>
#endif
// Ako ne zelis da ti se bilo sta ispisuje u Serijskom terminalu onda stavis pod komentar #define DEBUG
//------------------------------------------------------------------------------------------------------
#define DEBUG
#ifdef DEBUG
#define spln(x) Serial.println(x)
#define sp(x) Serial.print(x)
#define spf(x,y) Serial.printf(x,y)
#else
#define spln(x)
#define sp(x)
#define spf(x,y)
#endif
#include <ArduinoJson.h>
#include <TimeLib.h>
#include <WiFiClient.h>
#include <MySQL_Connection.h>
#include <MySQL_Cursor.h>
#include <time.h>
// #include za display
//--------------------------------
#include "ani.h"
#include <SPI.h>
#include <TFT_eSPI.h>
#include "Orbitron_Medium_20.h"
TFT_eSPI tft = TFT_eSPI(135,240);
#define TFT_GREY 0x5AEB
#define lightblue 0x01E9
#define darkred 0xA041
#define blue 0x5D9B
const int pwmFreq = 5000;
const int pwmResolution = 8;
const int pwmLedChannelTFT = 0;
String town="Sid"; //EDDIT
String Country="RS"; //EDDIT
int backlight[5] = {10,30,60,120,220};
byte b=1;
int count=0;
bool inv=1;
int press1=0;
int press2=0;////
int frame=0;
String curSeconds="";
// Moji #include fajlovi
//--------------------------------
#include "style_css.h"
#include "index_html.h"
// Izbor web servera za ESP8266 ili ESP32
//-----------------------------------------
#if defined(ESP8266)
ESP8266WebServer server(3003);
#else
WebServer server(3003);
#endif
// Open Weather Map, API, server name
//--------------------------------------------------------------------------------------------------
#define unit_type "metric" // or "imperial"
#define lat 45.130914 // latitude for Sid,RS
#define lon 19.242530 // longitude for Sid,RS
String url_ow = ""; // URL for HTTP get weather data
String url_uv = ""; // URL for HTTP get uv index data
String url_air = ""; // URL for Air Pollution
const char *server_ow = "api.openweathermap.org";
unsigned long id_city = 3190922;// Id za Sid
const char *api_key = "d8b774acf13f2ea889a3950c2c2a89c1";// REPLACE_WITH_YOUR_API_KEY;
// ThingSpeak information
//--------------------------------------------------------------------------------------------------
const char *thingSpeakAddress = "http://api.thingspeak.com";
unsigned long channelID = 1365442;
const char *readAPIKey = "OC8ZG5H8MA0A28HG";
const char *writeAPIKey = "4DQ2VAVQSEYQJ8KS";
//const unsigned long postingInterval = 120L * 1000L;
// Soft Ap variables
//--------------------------------------------------------------------------------------------------
const char *APssid = "MeteoStanica-MERA";
const char *APpassword = "NeveNa91"; // "" prazni navodnici No password
IPAddress APlocal_IP(192, 168, 4, 1);
IPAddress APgateway(192, 168, 4, 1);
IPAddress APsubnet(255, 255, 255, 0);
// Client
//--------------------------------------------------------------------------------------------------
WiFiClient client;
// MySQL Connection
//--------------------------------------------------------------------------------------------------
MySQL_Connection conn(&client);
MySQL_Cursor *cursor;
IPAddress server_addr(37,59,55,185); // remotemysql.com IP of the MySQL *server* here
char *user = "nUm8euijbj"; // MySQL user login username
char *password = "85LoYraODw"; // MySQL user login password/
// Station variables
//--------------------------------------------------------------------------------------------------
const char *ssid = "YuMERA1"; // Network to be joined as a station SSID
const char *passphrase = "NeveNa91"; // Network to be joined as a station password
const char *host = "192.168.1.5"; // Connection to my Visual APP over TCP 3001
const int MyAppPort = 3001;
IPAddress mystaticip(192, 168, 1, 50);
IPAddress mygateway(192, 168, 1, 1);
IPAddress mysubnet(255, 255, 255, 0);
IPAddress myDNS(8, 8, 8, 8);
// General Variables
//--------------------------------------------------------------------------------------------------
#define Alt "132" // Altitude
unsigned long previousMillis = 0; // memorisanje prethodnog vremena
const long interval = 50000; // interval sa kojim zelimo da citamo sensor
String content; // html kod servera
String cIp="(null)"; // string IP adresa za svakog klijenta koji preko veba pristupi weatherstanici
String Tem="(null)"; // izmerena temperatura
String Hum="(null)"; // vlaznost
String Pre="(null)"; // pritisak
String Win="(null)"; // brzina vetra (jos nije implementirano na mojoj meteo stanici)
String Slp="(null)"; // nadmorska visina na osnovu izmereneog pritiska i pritiska na nivou mora
String Win1="(null)"; // privremeno za brzinu vetra dok ne zavrsim moj anemometar
String symbolWindDir=""; // oznaka za smer vetra
String Vcc="(null)"; // napon ba bateriji
String Rsi="(null)"; // jacina WiFi signala izmedju ESP meteo stanice i ESP web servera
String Tmb="(null)"; // temperatura na BME280 koji se nalazi u kucistu meteo stanice
char lastTime[25] = "--:--"; // vreme poslednjeg merenja
String uv_index_description = ""; // Vrednost UV indexa
// Klimerko variable
//--------------------------------------------------------------------------------------------------
String pm1_kli = "0"; // PM1 cestice izmerene na klimerku
String pm25_kli = "0"; // PM2.5 cestice
String pm10_kli = "0"; // PM10 cestice
String tem_kli = "0"; // temperatura na klimerku
String hum_kli = "0"; // vlaznost
String pre_kli = "0"; // pritisak
char lastTimeKli[25] = "--:--"; // vreme zadnjeg azuriranja podataka sa klimerka
String airQuality = "n/a"; // kvalitet vazduha engleski
String _airQuality = "Nema ažuriranja";// kvalitet vazduha srpski
String _color = "Black"; // kolor teksta za kvaliret vazduha
//#define klima // Ako je klimerko u funkciji ako nije onda reemitujem preuzete podatke
// Air Pollution
//--------------------------------------------------------------------------------------------------
float cmp_co; // Сoncentration of CO (Carbon monoxide)
float cmp_no; // Сoncentration of NO (Nitrogen monoxide)
float cmp_no2; // Сoncentration of NO2 (Nitrogen dioxide)
float cmp_o3; // Сoncentration of O3 (Ozone)
float cmp_so2; // Сoncentration of SO2 (Sulphur dioxide)
float cmp_pm25; // Сoncentration of PM2.5 (Fine particles matter)
float cmp_pm10; // Сoncentration of PM10 (Coarse particulate matter)
float cmp_nh3; // Сoncentration of NH3 (Ammonia)
long cmp_dt; // Date and time, Unix, UTC
// Time variable
//--------------------------------------------------------------------------------------------------
#define UTC (0) // time zone "+01:00"
byte tz = 1; // Time zone +1 default. Letnje racunjanje vremena +2
// Set offset time in seconds to adjust for your timezone, for example:
// GMT +1 = 3600
int timezone = 1 * 3600; // 3600 za +1 i 7200 za +2 (letnje racunjanje vremena)
int dst = 1; // 1 - aktivno, 0 - neaktivno letnje racunjanje vremena
// Variable from Json data
//--------------------------------------------------------------------------------------------------
int nowID; // Brojcana oznaka trenutnog stanja [weather][id]
String dan_noc;
String weather_main = ""; // Sadasnje stanje vremena
String wind_deg=""; // Smer vetra na osnovi degress
String txtIconWeather = ""; // Naziv ikone u zavisnosti od stanja trenutnog meteo stanja
String txtWindDir= ""; // smer vetra
char sunrise[32],sunset[32]; // Izlazak i zalazak sunca(UTC unix time)
byte clouds; // Oblacnost u %
String uv_index; // UV index zracenja
int humidity; // Vlaznost sa bazne stanice
// Promenljiva za memorisanje trenutnog vremena pri izracuno koliko je proteklo vremena
//--------------------------------------------------------------------------------------------------
unsigned long prevMillis;
// Variable Json data from ip-api
//--------------------------------------------------------------------------------------------------
String ip_query = ""; // root["query"]
String ip_status = ""; // root["status"]
String ip_country = ""; // root["country"]
String ip_countryCode = ""; // root["countryCode"]
String ip_region = ""; // root["region"]
String ip_regionName = ""; // root["regionName"]
String ip_city = ""; // root["city"]
String ip_timezone = ""; // root["timezone"]
String ip_isp = ""; // root["isp"]
String ip_message = ""; // root["message"]
void setup() {
//TFT Display
//-----------------------------------------------------------
pinMode(0,INPUT_PULLUP);
pinMode(35,INPUT);
tft.init();
tft.setRotation(0);
tft.fillScreen(TFT_BLACK);
tft.setTextColor(TFT_WHITE,TFT_BLACK);
tft.setTextSize(1);
ledcSetup(pwmLedChannelTFT, pwmFreq, pwmResolution);
ledcAttachPin(TFT_BL, pwmLedChannelTFT);
ledcWrite(pwmLedChannelTFT, backlight[b]);
//------------------------------------------------------------
delay(5000);
Serial.begin(115200);
// obavest o programu i garanciji !!!
Serial.println("\n\n...................................................................");
Serial.println(". MeteoMera v2.1 Copyright (C) 2021. me[R]a .");
Serial.println(". This program comes with ABSOLUTELY NO WARRANTY .");
Serial.println(". This is free software, and you are welcome to redistribute .");
Serial.println(". it under certain conditions .");
Serial.println("...................................................................\n\n");
for(uint8_t t = 4; t > 0; t--) {
spf(" [StartUp] WAIT %d...\n", t);
tft.printf (" WAIT -> %d...\n", t);
Serial.flush();
delay(1000);
}
// Start wifi konekcije sa mojim ruterom
//------------------------------------------------------------------
WiFi.config(mystaticip, mygateway, mysubnet, mygateway);
WiFi.mode(WIFI_AP_STA);//WiFi.mode(WIFI_STA);
WiFi.begin(ssid, passphrase);
tft.print("Connecting to ");
tft.println(ssid);
spf("\n Station connecting to %s SSID\n", ssid);
if (testWifi()){
spln(" success!");
spln(" -------------------------------------------------------");
sp(" Station connected, IP address: ");
spln(WiFi.localIP());
spf(" Signal Strength: %d dBm\n", WiFi.RSSI());
sp(" ESP Board MAC Address: ");
spln(WiFi.macAddress());
tft.println("IP address: ");
tft.println(WiFi.localIP());
delay(500);
tft.setTextColor(TFT_WHITE,TFT_BLACK);
tft.setTextSize(1);
tft.fillScreen(TFT_BLACK);
tft.setSwapBytes(true);
tft.setTextColor(blue, TFT_BLACK);
tft.setCursor(30, 232, 1);
tft.println(WiFi.localIP());
tft.setTextColor(TFT_GREEN, TFT_BLACK);
tft.setCursor(80, 198, 1);
tft.println("BRIGHT");
tft.setCursor(4, 152, 2);
tft.println("tmp C");
tft.setCursor(4, 192, 2);
tft.println("hum %");
tft.setCursor(80, 152, 2);
tft.println("pre hPa");
tft.setTextColor(TFT_WHITE,TFT_BLACK);
tft.setFreeFont(&Orbitron_Medium_20);
tft.setCursor(6, 82);
tft.println(town + ", " + Country);
tft.fillRect(1,1,148,45,TFT_RED);
tft.setTextColor(TFT_WHITE,TFT_RED);
tft.setCursor(24,30);
tft.println("m e r a");
tft.fillRect(65,151,1,74,TFT_GREY);
for(int i=0;i<b+1;i++)
tft.fillRect(78+(i*7),216,3,10,blue);
}else{
spln(" failed!");
spln(" ESP goes to restart");
ESP.restart();
}
// Configure the Soft Access Point.
//---------------------------------------------------------------------------------------------------------------------
sp(" Soft-AP configuration ... ");
spln(WiFi.softAPConfig(APlocal_IP, APgateway, APsubnet) ? "OK" : "Failed!"); // configure network
sp(" Setting soft-AP ... ");
spln(WiFi.softAP(APssid, APpassword , 1, 1, 1) ? "OK" : "Failed!"); // Setup the Access Point chanel 1 and SSID hide
sp(" Soft-AP IP address = ");
spln(WiFi.softAPIP()); // Confirm AP IP address
spln(" -------------------------------------------------------");
// Kreiram url na weather server sa kojeg preuzimam podatatke u JSON formatu
//------------------------------------------------------------------------------------------------------------------------------------------------------
url_ow += "http://" + String(server_ow) + "/data/2.5/weather?lat=" + String(lat,6) + "&lon=" + String(lon,6) + "&units=" + unit_type + "&appid=" + api_key;
url_uv += "http://" + String(server_ow) + "/data/2.5/uvi?appid=" + api_key + "&lat=" + String(lat,2) + "&lon=" + String(lon,2);
url_air += "http://" + String(server_ow) + "/data/2.5/air_pollution?lat=" + String(lat,2) + "&lon=" + String(lon,2) + "&appid=" + api_key;
// Odgovar web servera u zavisnosti od pristupa nekoj od strana
//---------------------------------------------------------------------------------------
server.on("/", handleRoot); // root
server.on("/input", handleInput); // pristigli izmereni podaci sa meteo stanice
server.on("/map.html", handleMap); // prikaz google map pozicije moje meteo stanice
server.on("/about.html", handleAbout);// nesto o samoj meteo stanici
server.on("/json.html", handleJson); // kreiram JSON podatke sa prosledjivanje drugima
server.on("/min.html", handleMin); // minimizovani prikaz izmerenih podataka
server.on("/gra.html",handleGra); // Graficki prikaz podataka
server.on("/kli", handleKli); // podaci koje saljem na klimerka.org
server.on("/style.css",handleCss); //
server.onNotFound(handleNotFound);// Not Found
server.begin();
spln(" HTTP web server started\n");
configTime(timezone, dst, "pool.ntp.org","time.nist.gov"); // uzimam vreme sa interneta na osnovu moje vremenske zone
sp(" Waiting for Internet time "); // i da li se koristi letnje racunjanje vremena
while(!time(nullptr)){
sp(".");
delay(100);
}
spln("\n Response requires time is OK!\n");
delay(100);
getWeatherCondition();
delay(1000);
}
// Funkcija za testiranje izabranog ili snimljenog WiFi-a
//----------------------------------------------------------------
bool testWifi(void){
int c = 0;
sp(" Waiting for connection data ");
while ( c < 20 ) {
if (WiFi.status() == WL_CONNECTED)
{
return true;
}
delay(500);
sp(".");
c++;
}
spln("");
sp(" Connection timed out.");
return false;
}
void loop(){
tft.pushImage(0, 88, 135, 65, ani[frame]);
frame++;
if(frame>=10)
frame=0;
if(digitalRead(35)==0){
if(press2==0){
press2=1;
tft.fillRect(78,216,44,12,TFT_BLACK);
b++;
if(b>=5)
b=0;
for(int i=0;i<b+1;i++)
tft.fillRect(78+(i*7),216,3,10,blue);
ledcWrite(pwmLedChannelTFT, backlight[b]);
}
}else press2=0;
if(digitalRead(0)==0){
if(press1==0){
press1=1;
inv=!inv;
tft.invertDisplay(inv);
}
}else press1=0;
if(count==0)
count++;
if(count>2000)
count=0;
server.handleClient();
delay (200);
}
void getIpCondition(){
ip_query = ""; ip_status = ""; ip_country = ""; ip_countryCode = ""; ip_region = "";
ip_regionName = ""; ip_city = ""; ip_timezone = ""; ip_isp = ""; ip_message = "";
// JSon data za IP client-a
//------------------------------------------------------------------------
if (WiFi.status() == WL_CONNECTED) {
//http://ip-api.com/docs/api:json#test
char url_ip_api[128];
sprintf(url_ip_api,"http://ip-api.com/json/%s?fields=country,countryCode,region,regionName,city,timezone,isp,query,status,message",cIp.c_str());
spln (" Json URL for ip-api: " + String(url_ip_api));
HTTPClient http; // Deklarisanje objekta na class HTTPClient
#if defined(ESP8266)
WiFiClient client;
http.begin(client, url_ip_api);
#else
http.begin(url_ip_api);
#endif
int httpCode = http.GET();
spln(" Response : " + ((httpCode == 200) ? "Ok! {code:200}" : String(httpCode)));
if (httpCode > 0) {
String payload = http.getString();
const size_t bufferSize = JSON_OBJECT_SIZE(9) + 308;
DynamicJsonDocument doc(bufferSize);
const char* json = payload.c_str();
spln(" Json data : " + String(json));
deserializeJson(doc, json);
// Root object
ip_query = doc["query"].as<String>(); // "109.245.39.10"
ip_status = doc["status"].as<String>(); // "success"
if(ip_status == "success") {
ip_country = doc["country"].as<String>(); // "Serbia"
ip_countryCode = doc["countryCode"].as<String>(); // "RS"
ip_region = doc["region"].as<String>(); // "00"
ip_regionName = doc["regionName"].as<String>(); // "Vojvodina"
ip_city = doc["city"].as<String>(); // "Šid"
ip_timezone = doc["timezone"].as<String>(); // "Europe/Belgrade"
ip_isp = doc["isp"].as<String>(); // "CETIN Ltd. Belgrade"
}else{
ip_message = doc["message"].as<String>();
}
spln(" JSon data from IP client");
spln(" -------------------------------------------------------");
spln(" Query : " + ip_query);
spln(" Status : " + ip_status);
spln(" Country : " + ip_country);
spln(" Country code: " + ip_countryCode);
spln(" Region : " + ip_region);
spln(" Region name : " + ip_regionName);
spln(" City : " + ip_city);
spln(" Time zone : " + ip_timezone);
spln(" ISP : " + ip_isp);
spln(" Message : " + ip_message);
spln(" -------------------------------------------------------");
}
http.end(); // Close connection
}
if(ip_status == "success"){
char buf[400];
sprintf(buf,"INSERT INTO nUm8euijbj.ip_client (ip_query,ip_status,ip_country,ip_countryCode,ip_region,ip_regionName,ip_city,ip_timezone,ip_isp,ip_message) "
"VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s')" ,
ip_query.c_str(), ip_status, ip_country, ip_countryCode, ip_region, ip_regionName.c_str(), ip_city, ip_timezone.c_str(), ip_isp.c_str(), ip_message.c_str());
spln("\n Send client data to MySQL database.");
MySQL_connect(); // Connecting to SQL...
if (conn.connected()){
cursor->execute("SET character_set_client = 'UTF8MB4';");
cursor->execute("SET character_set_connection='UTF8MB4';");
cursor->execute("SET character_set_results='UTF8MB4';");
spln(" SQL Query : " + String(buf));
if(cursor->execute(buf)){
spln(" Success stored IP condition data to MySQL database.\n");
}else{
spln(" IP data record failed!");
}
delay(50);
delete cursor;
}else{
spln(" Connection failed.\n");
conn.close();
}
}
}
void getWeatherCondition(){// Json podaci koje preuzimam sa drugih meteo servera. Jos uvek nisam zavrsio kompletna merenja kod mene na stanici
if (WiFi.status() == WL_CONNECTED) {
spln(" Weather data processing");
spln(" Connected to json data with API " + url_ow);
HTTPClient http; // Declare an object of class HTTPClient
#if defined(ESP8266)
WiFiClient client;
http.begin(client,url_ow);
#else
http.begin(url_ow);
#endif
int httpCode = http.GET();
spln(" Response : " + ((httpCode == 200) ? "Ok! {code:200}" : String(httpCode)));
if (httpCode > 0) {
String payload = http.getString();// Get payload
const size_t bufferSize = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 2*JSON_OBJECT_SIZE(2) + // JSON buffer
JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(12) + 355;
DynamicJsonDocument doc(bufferSize);
// Parse JSON data
//------------------------------------------------------------------------------------------------------------------------------
const char* json = payload.c_str();
spln(" Json data : " + String(json));
deserializeJson(doc, json);
// Root object
//------------------------------------------------------------------------------------------------------------------------------
nowID = doc["weather"][0]["id"]; // Opis trenutnog meteo (ne)vremena
txtIconWeather = getMeteoconIcon(nowID); // Opis trenutnog meteo (ne)vremena prevedeno na srpski
dan_noc = doc["weather"][0]["icon"].as<String>(); // Na osnovu icone znamo dali je dan ili noc
Win1 = doc["wind"]["speed"].as<String>(); // Brzina vetra u m/s
weather_main = doc["weather"][0]["main"].as<String>(); // Trenutno stanje vremena
clouds = doc["clouds"]["all"]; // Oblacnost u %
int deg = doc["wind"]["deg"]; // Smer vetra
wind_deg = WindDir(deg); // Smer vetra prevod srpski
unsigned long sr = doc["sys"]["sunrise"]; // Izlazak sunca
unsigned long ss = doc["sys"]["sunset"]; // Zalazak sunca
sr = sr + tz * 3600; // Dodajem time zone +2 (7200 a za +1 3600) u secundama
ss = ss + tz * 3600;
sprintf(sunrise, "%02d:%02d:%02d",hour(sr),minute(sr),second(sr));// kreiram lokal time HH:MM:SS od UTC time za izlazak sunca
sprintf(sunset, "%02d:%02d:%02d",hour(ss),minute(ss),second(ss)); // za zalazak sunca
String city = doc["name"]; // Ime mesta za koje prikupljamo podatke
float tempNow = doc["main"]["temp"]; // Temperatura (pruzeti podataka)
humidity = doc["main"]["humidity"]; // Vlaznost (preuzet podataka)
String iconcode = doc["weather"][0]["icon"]; // ID ikone koju prikazujem
String TodayIcon = "http://openweathermap.org/img/w/" + iconcode + ".png";// Link sa kojeg pruzima sliku za ID
spln(" -------------------------------------------------------");
spln(" City : " + city);
spln(" Temp : " + String(tempNow,2));
spln(" Hum : " + String(humidity));
spln(" Icona : " + txtIconWeather);
spln(" Slika : " + TodayIcon);
spln(" Sunrise : " + (String)sunrise);
spln(" Sunset : " + (String)sunset);
spln(" -------------------------------------------------------\n");
}else{
spln(" No response from the Weather server.\n");
}
http.end(); // Close connection
}
// Air Pollution - API
//---------------------------------------------------------------
spln(" Air Pollution data processing");
spln(" Connected to json data with API " + url_air);
HTTPClient http; // Deklaracija objekta na class HTTPClient
#if defined(ESP8266)
WiFiClient client;
http.begin(client,url_air);
#else
http.begin(url_air);
#endif
int httpCode = http.GET();
spln(" Response : " + ((httpCode == 200) ? "Ok! {code:200}" : String(httpCode)));
if (httpCode > 0) {
String payload = http.getString();
StaticJsonDocument<384> doc;
// Parse JSON data
//--------------------------------------------------------------------
const char* json = payload.c_str();
spln( " Json data : " + String(json));
DeserializationError error = deserializeJson(doc, json);
if (error) {
sp(F(" deserializeJson() failed: "));
spln(error.f_str());
} else{
// Root object
// Get main report
//----------------------------------
JsonObject list = doc["list"][0];
JsonObject components = list["components"];
// Parse Json data -
//----------------------------------
cmp_co = components["co"];
cmp_no = components["no"];
cmp_no2 = components["no2"];
cmp_o3 = components["o3"];
cmp_so2 = components["so2"];
cmp_pm25 = components["pm2_5"];
cmp_pm10 = components["pm10"];
cmp_nh3 = components["nh3"];
cmp_dt = list["dt"];
char dt[32];
sprintf(dt, "%02d.%02d.%02d %02d:%02d", day(cmp_dt), month(cmp_dt), year(cmp_dt), hour(cmp_dt), minute(cmp_dt));
spln(" -------------------------------------------------------");
spln(" Concentration of:");
spln(" -------------------------------------------------------");
spln(" CO : " + String(cmp_co,2) + " μg/m3");
spln(" NO : " + String(cmp_no,2) + " μg/m3");
spln(" NO2 : " + String(cmp_no2,2) + " μg/m3");
spln(" 03 : " + String(cmp_o3,2) + " μg/m3");
spln(" SO2 : " + String(cmp_so2,2) + " μg/m3");
spln(" PM2.5: " + String(cmp_pm25,2) + " μg/m3");
spln(" PM10 : " + String(cmp_pm10,2) + " μg/m3");
spln(" NH3 : " + String(cmp_nh3,2) + " μg/m3");
spln(" -------------------------------------------------------");
spln(" Time last measurement : " + String(dt));
spln(" -------------------------------------------------------\n");
#if defined(klima)
pm25_kli = String(cmp_pm25,0);
pm10_kli = String(cmp_pm10,0);
sprintf(lastTimeKli,dt);
int pm10 = pm10_kli.toInt();
if (pm10 <= 20) {
airQuality = "Excellent"; // Kvalitet vazduha
_airQuality = "Odličan"; // Kvalitet srpski prevod
_color = "MediumSeaGreen"; // Boja prikaza kvaliteta
} else if (pm10 >= 21 && pm10 <= 40) {
airQuality = "Good";
_airQuality = "Dobar";
_color = "Coral";
} else if (pm10 >= 41 && pm10 <= 50) {
airQuality = "Acceptable";
_airQuality = "Prihvatljiv";
_color = "Tomato";
} else if (pm10 >= 51 && pm10 <= 100) {
airQuality = "Polluted";
_airQuality = "Zagađen";
_color = "OrangeRed";
} else if (pm10 > 100) {
airQuality = "Very Polluted";
_airQuality = "Jako Zagađen";
_color = "Red";
}
#endif
}
}
http.end();
// UV index
//---------------------------------------------------------------
spln(" UV Index data processing");
spln(" Connected to json data with API " + url_uv);
//HTTPClient http; // Deklaracija objekta na class HTTPClient
#if defined(ESP8266)
WiFiClient client;
http.begin(client,url_uv);
#else
http.begin(url_uv);
#endif
httpCode = http.GET();
spln(" Response : " + ((httpCode == 200) ? "Ok! {code:200}" : String(httpCode)));
if (httpCode > 0) {
String payload = http.getString();// Get payload
const size_t bufferSize = JSON_OBJECT_SIZE(5) + 172;// JSON buffer
DynamicJsonDocument doc(bufferSize);
// Parse JSON data
//--------------------------------------------------------------------
const char* json = payload.c_str();
spln( " Json data : " + String(json));
deserializeJson(doc, json);
// Root object
// Get main report
//----------------------------------
uv_index = doc["value"].as<String>();// Pruzeti uv index kao string
spln(" -------------------------------------------------------");
spln(" UV Index : " + uv_index);
spln(" -------------------------------------------------------\n");
// Vrednost UV indexa http://www.hidmet.gov.rs/ciril/prognoza/uv1.php
if (uv_index.toInt() >= 11)
uv_index_description = "Ekstremno visok";
else if(uv_index.toInt() >= 8 && uv_index.toInt() <= 10)
uv_index_description = "Vrlo visok";
else if(uv_index.toInt() >= 6 && uv_index.toInt() <= 7)
uv_index_description = "Visok";
else if(uv_index.toInt() >= 3 && uv_index.toInt() <= 5)
uv_index_description = "Umeren";
else if(uv_index.toInt() >= 0 && uv_index.toInt() <= 2)
uv_index_description = "Nizak";
}
http.end();
}
void handleJson(){// Kreiram stranu na kojoj je samo text po Json standardu. Ovo za preuzimanje izmerenih vrednosti za potrebe trece strane
char content[1280];
int statusCode = 200;
sprintf(content, "{\n"
" \"station\": {\n"
" \"name\": \"Meteo Station MERA\",\n"
" \"city\": \"Šid\",\n"
" \"link\": \"http://109.72.53.172:3003/\",\n"
" \"lat\": %f,\n"
" \"lon\": %f,\n"
" \"alt\": %s\n"
" },\n"
" \"weather\": {\n"
" \"basic\": {\n"
" \"temperature\": {\n"
" \"value\": %s,\n"
" \"units\": \"°C\"\n"
" },\n"
" \"humadity\": {\n"
" \"value\": %s,\n"
" \"units\": \"%%\"\n"
" },\n"
" \"pressure\": {\n"
" \"value\": %s,\n"
" \"units\": \"hPa\"\n"
" }\n"
" },\n"
" \"extend\": {\n"
" \"airquality\": {\n"
" \"pm1\": %s,\n"
" \"pm2.5\": %s,\n"
" \"pm10\": %s,\n"
" \"units\": \"µg/m³\"\n"
" },\n"
" \"uvindex\": %s,\n"
" \"wind\": {\n"
" \"direction\": \"%s\",\n"
" \"speed\": %s,\n"
" \"units\": \"m/s\"\n"
" },\n"
" \"cloudines\": %s,\n"
" \"sunrise\": \"%s\",\n"
" \"sunset\": \"%s\"\n"
" },\n"
" \"time\": \"%s\"\n"
" }\n"
"}",lat,lon,Alt,Tem,Hum,Pre,pm1_kli,pm25_kli,pm10_kli,uv_index,symbolWindDir,Win1,String(clouds),sunrise,sunset,lastTime);
server.sendHeader("Access-Control-Allow-Origin", "*");
server.send(statusCode, "application/json; charset=UTF-8", content);
}
void handleKli() { // Kad stignu podaci sa klimerka
time_t now = time(nullptr);
struct tm* p_tm = localtime(&now);
sprintf(lastTimeKli,"%2d:%02d - %02d.%02d.%04d.", (p_tm->tm_hour + UTC) % 24, p_tm->tm_min, ((p_tm->tm_hour + UTC) % 24 == 0) ? p_tm->tm_mday + 1 : p_tm->tm_mday,
p_tm->tm_mon+1,(p_tm->tm_year + 1900));
String message = " Number of args received from klimerko : ";
message += server.args(); // Ukupan broj svih parametara koji se potrazuju
message += "\n";
message += " -------------------------------------------------------------------\n";
for (int i = 0; i < server.args(); i++) {
message += " Arg nº" + (String)i + " -> ";// Redni broj parametra
message += server.argName(i) + ": "; // Naziv za parametar
message += server.arg(i) + "\n"; // Vrednost parametra
delay(10);
}
message += " -------------------------------------------------------------------";
spln(message);
spln(" Vreme zadnjeg merenja klimerka : " + String(lastTimeKli) + "\n");
pm1_kli = server.arg("PM1"); // server.arg(0);
pm25_kli = server.arg("PM25"); // server.arg(1);
pm10_kli = server.arg("PM10"); // server.arg(2);
tem_kli = server.arg("Temperature"); // server.arg(3);
hum_kli = server.arg("Humidity"); // server.arg(4);
pre_kli = server.arg("Pressure"); // server.arg(5);
int pm10 = pm10_kli.toInt();
// tekstualna vrednost kvalitea vazduha po standardu
// http://www.amskv.sepa.gov.rs/kriterijumi.php
if (pm10 <= 20) {
airQuality = "Excellent"; // Kvalitet vazduha
_airQuality = "Odličan"; // Kvalitet srpski prevod
_color = "MediumSeaGreen"; // Boja prikaza kvaliteta
} else if (pm10 >= 21 && pm10 <= 40) {
airQuality = "Good";
_airQuality = "Dobar";
_color = "Coral";
} else if (pm10 >= 41 && pm10 <= 50) {
airQuality = "Acceptable";
_airQuality = "Prihvatljiv";
_color = "Tomato";
} else if (pm10 >= 51 && pm10 <= 100) {
airQuality = "Polluted";
_airQuality = "Zagađen";
_color = "OrangeRed";
} else if (pm10 > 100) {
airQuality = "Very Polluted";
_airQuality = "Jako Zagađen";
_color = "Red";
}
server.send(200, "text/plain", "OK!"); // Send HTTP status 200 (Ok) and send some text to the browser/client
}
void handleInput() {// Ovde se hendluje strana kada dolaze izmerene vrednosti
time_t now = time(nullptr);
struct tm* p_tm = localtime(&now);
sprintf(lastTime,"%2d:%02d - %02d.%02d.%04d.", (p_tm->tm_hour+UTC)%24, p_tm->tm_min, ((p_tm->tm_hour+UTC)%24 == 0) ? p_tm->tm_mday +1 : p_tm->tm_mday,
p_tm->tm_mon+1,(p_tm->tm_year + 1900));
String message = " Number of args received : ";
message += server.args(); // Ukupan broj svih parametara koji se potrazuju
message += "\n";
message += " -------------------------------------------------------------------\n";
for (int i = 0; i < server.args(); i++) {
message += " Arg nº" + (String)i + " -> ";// Redni broj parametra
message += server.argName(i) + ": "; // Naziv za parametar
message += server.arg(i) + "\n"; // Vrednost parametra
delay(10);
}
message += " -------------------------------------------------------------------";
spln(message);
spln(" Vreme zadnjeg merenja : " + String(lastTime) + "\n");
Tem = server.arg("Temperature"); // Temperatura DS18B20
//Hum = server.arg("Humidity"); // Vlaznost (moj BME)
//Hum = String(humidity); // Vlaznost preuzet podataka (ovako sam morao jer BME280 brljavi sa vlaznosti)
Hum = hum_kli; // Vlaznost uzimam sa klimerka kad je u funkciji
Pre = server.arg("Pressure"); // Pritisak
Win = server.arg("WinSpeed"); // Brzina vetra (preuzet podatak)
Vcc = server.arg("Voltage"); // Napon na bateriji
Rsi = server.arg("RSSI"); // Jacina wifi signala
Tmb = server.arg("TempInCase"); // Temperatura u kucistu sa BME280
Slp = server.arg("SeaLevelPressure"); // Nadmoraka visina na osnovu pritiska
tft.setFreeFont(&Orbitron_Medium_20);
tft.setTextColor(TFT_RED,TFT_BLACK);
tft.fillRect(1,167,62,20,TFT_BLACK);
tft.setCursor(2, 187);
String temperatura = String(round(Tem.toFloat()),0);
temperatura.trim();
tft.println(temperatura);
tft.setTextColor(TFT_WHITE,TFT_BLACK);
tft.fillRect(1,207,62,20,TFT_BLACK);
tft.setCursor(2, 227);
tft.println(Hum);
tft.fillRect(70,167,85,20,TFT_BLACK);
tft.setCursor(70, 187);
String pritisak = String(round(Pre.toFloat()),0);
pritisak.trim();
tft.println(pritisak);
server.send(200, "text/plain", "OK!");// Send HTTP status 200 (Ok) and send some text to the browser/client
// Slanje podataka na moj kanal na ThingSpeak
//-----------------------------------------------------------
char thingSpeak[256];
sprintf(thingSpeak,"%s/update?api_key=%s&field1=%s&field2=%s&field3=%s&field4=%s&field5=%s&field6=%s&field71=%s",
thingSpeakAddress,writeAPIKey,Tem,Hum,Pre,Win1,uv_index,Vcc,Rsi);
spln (" Send data to ThingSpeak my channel");
spln (" Link : " + String(thingSpeak));
HTTPClient http;
#if defined(ESP8266)
WiFiClient client;
http.begin(client,thingSpeak);
#else
http.begin(thingSpeak);
#endif
int httpCode = http.GET();
spln(" Response : " + ((httpCode == 200) ? "Ok! {code:200}" : String(httpCode)));
if (httpCode > 0) {
spln(" Data sent successfully\n");
}else{
spln(" Failure! Data not sent successfully.\n");
}
http.end();
// Insert MySQL
//------------------------------------------------------------
char buf[512];
sprintf(buf, "INSERT INTO nUm8euijbj.meteo_data (Temperature,Humidity,Pressure,WinSpeed,UVindex,Voltage,RSSI,TempInCase,wMain,wIcon,PM10,PM1,PM25,K_Tem,K_Hum,K_Pre) "
"VALUES ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %s, %s, %s, %s, %s, %s)" ,
Tem, Hum, Pre, Win1, String(uv_index.toFloat(),1), Vcc, Rsi, Tmb, weather_main, txtIconWeather.c_str(), pm10_kli, pm1_kli, pm25_kli, tem_kli, Hum, pre_kli);
// Connecting to SQL
//---------------------------------------------------------------
spln(" Send measured meteo data to MySQl database.");
MySQL_connect();
if (conn.connected()){// ako je konekcija na bazu uspesna
//cursor->execute("SET time_zone = '+02:00';");//("SET @@session.time_zone = '+02:00'");//Setovanje time zone za citanje podataka zbog vremenske razlike sa serverom
cursor->execute("SET character_set_client = 'UTF8MB4';");
cursor->execute("SET character_set_connection = 'UTF8MB4';");
cursor->execute("SET character_set_results = 'UTF8MB4';");
spln(" SQL Query : " + String(buf));
if(cursor->execute(buf)) {// SQL upit uspesan
spln(" Recording data to MySQL server successfully.\n");
}else{ // SQL upit ne uspesan
spln(" An attempt to save data to the database failed!");
}
delay(50);
delete cursor;
}else{// konekcija na bazu ne uspesna
spln("Connection failed.\n");
conn.close();
}
}
void handleRoot() {// Osnovna starnica web sajta
cIp = server.client().remoteIP().toString();
spln(" Remote client IP : " + String(cIp));
getIpCondition();
getWeatherCondition();
String ow_f;
if (nowID == 800 || nowID == 801 || nowID == 802){// Za ova tri ID-a mogu da biram ikonu dan-noc
ow_f = "-" + dan_noc.substring(dan_noc.length()-1);
}else{
ow_f = "";
}
String s = index_html;
// Tabela
//---------------------------------------------------------------------------
s.replace("@@h_tem@@",Tem); // Temperatura
s.replace("@@h_hum@@",Hum); // Vlaznost vazduha (preuzimam sa klimerkovog BME jer u meteo kucici drugi bme ne pokazuje dobro)
s.replace("@@h_pre@@",Pre); // Atmosferski pritisak
s.replace("@@h_winsm@@",Win1); // Brzina vetra
s.replace("@@h_wins@@",wind_deg); // Smer vetra
s.replace("@@h_wind@@",symbolWindDir);// Smer vetra oznaka
s.replace("@@h_obl@@",String(clouds));// Intezitet oblacnosti
s.replace("@@h_izl@@",sunrise); // Izlazak sunca
s.replace("@@h_zal@@",sunset); // Zalazak sunca
s.replace("@@h_uv@@",String(uv_index.toFloat(),1));// UV index
s.replace("@@h_uvd@@",uv_index_description);// Descriptionm uv index-a
s.replace("@@h_alt@@",Alt); // Altitude
s.replace("@@h_vcc@@",Vcc); // Vcc Battery
s.replace("@@h_rsi@@",Rsi); // RSI
s.replace("@@h_mes@@",lastTime); // Poslednje merenje
s.replace("@@h_pm0@@",pm1_kli); // PM1 suspend
s.replace("@@h_pm1@@",pm25_kli); // PM2.5 suspend
s.replace("@@h_pm2@@",pm10_kli); // PM10 suspend
// Widgets
//---------------------------------------------------------------------------