Code
public
Mar 19, 2024
Never
46
1 #define BLYNK_TEMPLATE_ID "XXXXXXXX" 2 #define BLYNK_TEMPLATE_NAME "ota test" 3 #define BLYNK_AUTH_TOKEN "XXXXXXXXXXX" 4 5 #define BLYNK_FIRMWARE_VERSION "1.9.5" 6 7 #include <Wire.h> 8 #include <Adafruit_GFX.h> 9 #include <SH1106Wire.h> 10 #include <espnow.h> 11 #include <ESP8266WiFi.h> 12 #include <WiFiClient.h> 13 #include <WiFiClientSecure.h> 14 #include <ESP8266HTTPClient.h> 15 #include <ESP8266httpUpdate.h> 16 #include <ESP8266HTTPUpdateServer.h> 17 #include "time.h" 18 #include <Preferences.h> 19 #include "LittleFS.h" 20 #include <BlynkSimpleEsp8266.h> 21 #include "HTTPSRedirect.h" 22 //#include <ctime> 23 24 WidgetTerminal terminal(V6); 25 WidgetTerminal terminal2(V7); 26 27 // Define the watchdog timer interval in milliseconds 28 const unsigned long WATCHDOG_INTERVAL = 10000; // 10 seconds 29 30 // Initialize the previous millis value for watchdog timer 31 unsigned long previousWatchdogMillis = 0; 32 33 // Define a constant for the maximum allowed time gap in seconds (5 minutes = 300 seconds) 34 const unsigned long MAX_TIME_GAP = 300; 35 36 // Define an array to store the last received timestamps for each sensor 37 unsigned long lastReceivedTime[4] = {0}; // Initialize all elements to 0 38 39 int groundLevel=0; 40 int bgroundLevel; 41 int m1low = 3; 42 int m1high = 8; 43 int m2t =8; 44 int bm1low, bm1high, bm2t; 45 46 String initialDate="24/02/2024"; //please use exactly dd/mm/yyyy as date format 47 String binitialDate; 48 struct tm lastIrriagationDate = {0}; 49 50 //wh1 = groundLevel - distance1 + bs1c 51 float s1c, s2c, s3c, s4c; 52 float bs1c, bs2c, bs3c, bs4c; 53 54 int activeSensorCount = 0; 55 String overTheAirURL = ""; 56 bool pumpauth=1; 57 58 #define SDA_PIN D2 59 #define SCL_PIN D1 60 61 SH1106Wire display(0x3c, SDA_PIN, SCL_PIN); 62 63 #define BLYNK_PRINT Serial 64 65 // Enter Google Script Deployment ID: 66 const char *GScriptId = "XXXX"; 67 68 // Enter command (insert_row or append_row) and your Google Sheets sheet name (default is Sheet1): 69 String payload_base = "{\"command\": \"insert_row\", \"sheet_name\": \"Sheet1\", \"values\": "; 70 String payload = ""; 71 72 // Google Sheets setup (do not edit) 73 const char* host = "script.google.com"; 74 const int httpsPort = 443; 75 const char* fingerprint = ""; 76 String url = String("/macros/s/") + GScriptId + "/exec"; 77 HTTPSRedirect* client = nullptr; 78 79 // Declare variables that will be published to Google Sheets 80 float value0 = 0; 81 float value1 = 0; 82 float value2 = 0; 83 float value3 = 0; 84 float value4 = 0; 85 bool value5 = 0; 86 bool value6 = 0; 87 float value7 = 0; 88 float value8 = 0; 89 float value9 = 0; 90 float value10 = 0; 91 float value11 = 0; 92 String value12 = initialDate; 93 float value13 = 0; 94 float value14 = 0; 95 float value15 = 0; 96 float value16 = 0; 97 float value17 = 0; 98 float value18 = 0; 99 float value19 = 0; 100 float value20 = 0; 101 102 103 BlynkTimer timer, timer2, timer3;; 104 // BlynkTimer timer2; 105 // BlynkTimer timer3; 106 107 const char* ssid = "AC/DC_P"; // Name of the Wi-Fi box 108 const char* password = "donttouchmywifi"; // MDP of the Wi-Fi box 109 110 const char* ntpServer = "pool.ntp.org"; 111 const long gmtOffset_sec = 3600 * 6; 112 const int daylightOffset_sec = 3600 * 0; 113 114 struct tm initialDateTime = {0}; 115 116 double seconds_diff; 117 118 int days_diff, days_diff2 ; 119 // int days_diff2; 120 121 122 123 // Relay pin 124 125 const int relayPin = D7; 126 127 // Ground level constant 128 129 130 131 float distance1, distance2, distance3, distance4, distanceAvg; 132 133 float wh1, wh2, wh3, wh4; 134 float waterHeight =0; 135 136 137 Preferences preferences, preferences1; 138 // Preferences preferences1; 139 // Structure example to receive data 140 // Must match the sender structure 141 typedef struct struct_message { 142 int id; 143 float distance; 144 } struct_message; 145 146 // Create a struct_message called myData 147 148 struct_message myData; 149 150 // Create a structure to hold the readings from each board 151 152 153 154 struct_message board1; 155 struct_message board2; 156 struct_message board3; 157 struct_message board4; 158 159 // Create an array with all the structures 160 161 struct_message boardsStruct[4] = {board1, board2, board3, board4}; 162 163 // Define day and month names arrays 164 165 166 167 const char* dayNames[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; 168 const char* monthNames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; 169 170 void myTimer() 171 172 { 173 Blynk.virtualWrite(V0, wh1); 174 Blynk.virtualWrite(V1, wh2); 175 Blynk.virtualWrite(V2, wh3); 176 Blynk.virtualWrite(V3, wh4); 177 Blynk.virtualWrite(V4, waterHeight); 178 Blynk.virtualWrite(V8, value6); 179 Blynk.virtualWrite(V7, "Dis1: " + String(distance1) + " Dis2: " + String(distance2) + " Dis3: " + String(distance3) + " Dis4: " + String(distance4) + " DisAVG: " + String(distanceAvg)); 180 Blynk.virtualWrite(V7, "s1c: " + String(s1c) + " s2c: " + String(s2c) + " s3c: " + String(s3c) + " s4c: " + String(s4c)); 181 Blynk.virtualWrite(V7, "groundLevel: " + String(groundLevel)); 182 Blynk.virtualWrite(V7, "initialDate: " + String(initialDate)); 183 Blynk.virtualWrite(V7, "days_diff: " + String(days_diff)); 184 Blynk.virtualWrite(V7, "m1high: " + String(m1high) + " m1low: " + String(m1low) + " m2t: " + String(m2t)); 185 // Blynk.virtualWrite(V7, "days_diff2: " + String(days_diff2)); 186 } 187 void myTimer2() 188 { 189 value0 = wh1; 190 value1 = wh2; 191 value2 = wh3; 192 value3 = wh4; 193 value4 = waterHeight; 194 value5 = pumpauth; 195 value7 = distance1; 196 value8 = distance2; 197 value9 = distance3; 198 value10 = distance4; 199 200 value11 = distanceAvg; 201 value12 = initialDate; 202 value13 = days_diff; 203 value14 = activeSensorCount; 204 value16 = groundLevel; 205 value17 = s1c; 206 value18 = s2c; 207 value19 = s3c; 208 value20 = s4c; 209 210 211 212 static bool flag = false; 213 if (!flag){ 214 client = new HTTPSRedirect(httpsPort); 215 client->setInsecure(); 216 flag = true; 217 client->setPrintResponseBody(true); 218 client->setContentTypeHeader("application/json"); 219 } 220 if (client != nullptr){ 221 if (!client->connected()){ 222 client->connect(host, httpsPort); 223 } 224 } 225 else{ 226 Serial.println("Error creating client object!"); 227 } 228 229 // Create json object string to send to Google Sheets 230 payload = payload_base + "\"" + \ 231 value12 + "," + value13 + "," + value15 + "," + value14 + "," + value5 + "," + \ 232 value6 + "," + value4 + "," + value0 + "," + value1 + "," + value2 + "," + \ 233 value3 + "," + value11 + "," + value7 + "," + value8 + "," + value9 + "," + \ 234 value10 + "," + value16 + "," + value17 + "," + value18 + "," + value19 + \ 235 "," + value20 + "\"}"; 236 237 238 // Publish data to Google Sheets 239 Serial.println("Publishing data..."); 240 Serial.println(payload); 241 if(client->POST(url, host, payload)){ 242 // do stuff here if publish was successful 243 } 244 else{ 245 // do stuff here if publish was not successful 246 Serial.println("Error while connecting"); 247 } 248 } 249 250 void myTimer3() 251 { 252 253 struct tm timeinfo; 254 if (!getLocalTime(&timeinfo)) { 255 Serial.println("Failed to obtain time"); 256 } 257 258 //start 259 Serial.print("\t"); 260 // Print time in the desired format 261 Serial.print("Day: "); 262 Serial.print(dayNames[timeinfo.tm_wday]); 263 Serial.print(", Month: "); 264 Serial.print(monthNames[timeinfo.tm_mon]); 265 Serial.print(" "); 266 Serial.print(timeinfo.tm_mday); 267 Serial.print(" "); 268 Serial.print(timeinfo.tm_year + 1900); 269 Serial.print(" "); 270 Serial.print(timeinfo.tm_hour); 271 Serial.print(":"); 272 if (timeinfo.tm_min < 10) Serial.print("0"); // Leading zero for minutes < 10 273 Serial.print(timeinfo.tm_min); 274 Serial.print(":"); 275 if (timeinfo.tm_sec < 10) Serial.print("0"); // Leading zero for seconds < 10 276 Serial.println(timeinfo.tm_sec); 277 seconds_diff = difftime(mktime(&timeinfo), mktime(&initialDateTime)); 278 Serial.print("Seconds since Given date in the current timezone"); 279 Serial.print("\t"); 280 Serial.print(seconds_diff); 281 days_diff = seconds_diff / 86400; 282 Serial.print("\t"); 283 Serial.print("Number of days"); 284 Serial.print("\t"); 285 Serial.print(days_diff); 286 Serial.print("\t"); 287 //delay(1000); 288 // Calculate average distance from all sub-station sensors 289 distance1 = boardsStruct[0].distance; 290 distance2 = boardsStruct[1].distance; 291 distance3 = boardsStruct[2].distance; 292 distance4 = boardsStruct[3].distance; 293 294 // Assuming groundLevel, s1c, s2c, s3c, s4c are defined elsewhere in your code 295 296 if (distance1 == 0) { 297 wh1 = 0; 298 } else { 299 wh1 = groundLevel - distance1 + s1c; 300 } 301 302 if (distance2 == 0) { 303 wh2 = 0; 304 } else { 305 wh2 = groundLevel - distance2 + s2c; 306 } 307 308 if (distance3 == 0) { 309 wh3 = 0; 310 } else { 311 wh3 = groundLevel - distance3 + s3c; 312 } 313 314 if (distance4 == 0) { 315 wh4 = 0; 316 } else { 317 wh4 = groundLevel - distance4 + s4c; 318 } 319 320 321 activeSensorCount = countActiveSensors(); 322 Serial.print("Active Sensors: "); 323 Serial.println(activeSensorCount); 324 if (activeSensorCount !=0 ) { 325 distanceAvg = (distance1 + distance2 + distance3 + distance4) / activeSensorCount; 326 // Calculate water height 327 waterHeight = (wh1+wh2+wh3+wh4)/activeSensorCount; 328 } 329 else { 330 distanceAvg =100; 331 waterHeight=100; 332 } 333 334 // Print water height 335 336 337 Serial.print("Water height: "); 338 Serial.print(waterHeight); 339 Serial.println(" cm"); 340 341 if (days_diff >= 0 && days_diff <= 21) 342 { 343 if(waterHeight < m1low && digitalRead(relayPin) == HIGH && pumpauth == 1) 344 { 345 digitalWrite(relayPin, LOW); 346 Serial.println("Pump started"); 347 } 348 349 if(waterHeight < m1low && digitalRead(relayPin) == LOW && pumpauth == 0) 350 { 351 digitalWrite(relayPin, HIGH); 352 Serial.println("Pump stopped because of pumpauth"); 353 } 354 355 if(waterHeight > m1high && digitalRead(relayPin) == LOW) 356 { 357 digitalWrite(relayPin, HIGH); 358 Serial.println("Pump stopped"); 359 } 360 361 value15 = 1; 362 Blynk.virtualWrite(V6, "mode 1"); 363 } 364 else if (days_diff > 21 && days_diff <= 90) 365 { 366 if(waterHeight > m2t && digitalRead(relayPin) == LOW) 367 { 368 digitalWrite(relayPin, HIGH); 369 Serial.println("Pump stopped"); 370 } 371 372 373 if(waterHeight <= .5) 374 { 375 preferences.begin("irrigation", true); 376 int lastIrriagationDay = preferences.getInt("lastIrriagationDay",0); 377 preferences.end(); 378 if(lastIrriagationDay == 0) // means no data is stored 379 { 380 preferences.begin("irrigation", false); 381 preferences.putInt("lastIrriagationYear", timeinfo.tm_year); 382 preferences.putInt("lastIrriagationMon", timeinfo.tm_mon); 383 preferences.putInt("lastIrriagationDay", timeinfo.tm_mday); 384 preferences.putInt("lastIrriagationHr", timeinfo.tm_hour); 385 preferences.putInt("lastIrriagationMin", timeinfo.tm_min); 386 preferences.putInt("lastIrriagationSec", timeinfo.tm_sec); 387 preferences.end(); 388 Blynk.virtualWrite(V6, "pref input current date"); 389 } 390 } 391 392 if(waterHeight <m2t) 393 { 394 preferences.begin("irrigation", true); 395 lastIrriagationDate.tm_year = preferences.getInt("lastIrriagationYear",0); 396 lastIrriagationDate.tm_mon = preferences.getInt("lastIrriagationMon",0); 397 lastIrriagationDate.tm_mday = preferences.getInt("lastIrriagationDay",0); 398 lastIrriagationDate.tm_hour = preferences.getInt("lastIrriagationHr",0); 399 lastIrriagationDate.tm_min = preferences.getInt("lastIrriagationMin",0); 400 lastIrriagationDate.tm_sec = preferences.getInt("lastIrriagationSec",0); 401 preferences.end(); 402 403 double seconds_diff2 = difftime(mktime(&timeinfo),mktime(&lastIrriagationDate)); 404 days_diff2 = seconds_diff2/86400; 405 Blynk.virtualWrite(V7, "days_diff2: " + String(days_diff2)); 406 407 if(days_diff2 >= 3 && digitalRead(relayPin) == HIGH && pumpauth == 1) 408 { 409 digitalWrite(relayPin, LOW); 410 Serial.println("Pump started"); 411 preferences.clear(); 412 } 413 if(days_diff2 >= 3 && digitalRead(relayPin) == LOW && pumpauth == 0) 414 { 415 digitalWrite(relayPin, HIGH); 416 Serial.println("Pump stopped because of pumpauth"); 417 //preferences.clear(); 418 } 419 } 420 value15= 2; 421 Blynk.virtualWrite(V6, "mode 2"); 422 } 423 424 else 425 { 426 Serial.print("The unconditional case"); 427 Blynk.virtualWrite(V6, "mode 3"); 428 value15 =3; 429 } 430 431 432 if (digitalRead(relayPin) == HIGH){ 433 value6 = 0; 434 } 435 else { 436 value6 = 1; 437 } 438 displayValues(); 439 getlastirrigationdate(); 440 } 441 442 443 void setup() { 444 Serial.begin(115200); 445 446 // Set relay pin as output 447 pinMode(relayPin, OUTPUT); 448 449 // Initialize relay to OFF 450 digitalWrite(relayPin, HIGH); 451 452 display.init(); 453 display.clear(); 454 455 WiFi.mode(WIFI_AP_STA); 456 // Init ESP-NOW 457 458 if (esp_now_init() != 0) { 459 Serial.println("Error initializing ESP-NOW"); 460 return; 461 } 462 // Once ESPNow is successfully Init, we will register for recv CB to 463 // get recv packer info 464 esp_now_set_self_role(ESP_NOW_ROLE_SLAVE); 465 esp_now_register_recv_cb(OnDataRecv); 466 //preferences.begin("irrigation", false); 467 //preferences1.begin("values", false); 468 loadPreferences1(); 469 Blynk.begin(BLYNK_AUTH_TOKEN, ssid, password); 470 Blynk.syncAll(); 471 timer.setInterval(1000L, myTimer); 472 timer2.setInterval(60000L,myTimer2); 473 timer3.setInterval(1000L,myTimer3); 474 475 // We configure the NTP server 476 477 configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); 478 479 480 GetDateTime(initialDate); 481 // Use HTTPSRedirect class to create a new TLS connection 482 client = new HTTPSRedirect(httpsPort); 483 client->setInsecure(); 484 client->setPrintResponseBody(true); 485 client->setContentTypeHeader("application/json"); 486 487 Serial.print("Connecting to "); 488 Serial.println(host); 489 490 // Try to connect for a maximum of 5 times 491 bool flag = false; 492 for (int i=0; i<5; i++){ 493 int retval = client->connect(host, httpsPort); 494 if (retval == 1){ 495 flag = true; 496 Serial.println("Connected"); 497 break; 498 } 499 else 500 Serial.println("Connection failed. Retrying..."); 501 } 502 if (!flag){ 503 Serial.print("Could not connect to server: "); 504 Serial.println(host); 505 return; 506 } 507 delete client; // delete HTTPSRedirect object 508 client = nullptr; // delete HTTPSRedirect object 509 } 510 511 void loop() { 512 513 //preferences1.end(); 514 Blynk.run(); 515 timer.run(); 516 timer2.run(); 517 timer3.run(); 518 ESP.wdtFeed(); 519 520 // Check if it's time to reset the watchdog timer 521 unsigned long currentMillis = millis(); 522 if (currentMillis - previousWatchdogMillis >= WATCHDOG_INTERVAL) { 523 // Reset the watchdog timer 524 ESP.wdtFeed(); 525 // Update the previous millis value 526 previousWatchdogMillis = currentMillis; 527 } 528 529 } 530 531 void displayValues() { 532 display.clear(); 533 // Print water heights 534 display.setFont(ArialMT_Plain_10); 535 display.drawString(0, 0, "wh1:" + String(wh1)); 536 display.drawString(0, 10, "wh2:" + String(wh2)); 537 display.drawString(0, 20, "wh3:" + String(wh3)); 538 display.drawString(0, 30, "wh4:" + String(wh4)); 539 540 // Print averages and other parameters 541 display.drawString(0, 40, "DisAvg: " + String(distanceAvg)); 542 display.drawString(0, 50, "whAvg: " + String(waterHeight)); 543 // Add more display statements for other parameters 544 display.drawString(70, 0, "Day:" + String(days_diff)); 545 display.drawString(70, 10, "Sensor:" + String(activeSensorCount)); 546 display.drawString(70, 20, "Pumpauth:" + String(pumpauth)); 547 display.drawString(70, 30, "Pump:" + String(value6)); 548 display.drawString(70, 50, "FW:" + String( BLYNK_FIRMWARE_VERSION)); 549 // Display the content 550 display.display(); 551 } 552 553 BLYNK_WRITE(InternalPinOTA) { 554 Serial.println("OTA Started"); 555 Blynk.virtualWrite(V6, "ota started"); 556 overTheAirURL = param.asString(); 557 Serial.print("overTheAirURL = "); 558 Serial.println(overTheAirURL); 559 otadisplay(); 560 WiFiClient my_wifi_client; 561 HTTPClient http; 562 http.begin(my_wifi_client, overTheAirURL); 563 564 565 t_httpUpdate_return ret = ESPhttpUpdate.update(my_wifi_client, overTheAirURL); 566 switch(ret) { 567 case HTTP_UPDATE_FAILED: 568 Serial.println("[update] Update failed."); 569 otafaileddisplay(); 570 break; 571 case HTTP_UPDATE_NO_UPDATES: 572 Serial.println("[update] Update no Update."); 573 otafaileddisplay(); 574 break; 575 case HTTP_UPDATE_OK: 576 Serial.println("[update] Update ok."); // may not be called since we reboot the ESP 577 break; 578 } 579 } 580 581 // callback function that will be executed when data is received 582 583 void OnDataRecv(uint8_t* mac_addr, uint8_t* incomingData, uint8_t len) { 584 585 586 char macStr[18]; 587 Serial.print("Packet received from: "); 588 snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", 589 mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); 590 591 592 Serial.println(macStr); 593 memcpy(&myData, incomingData, sizeof(myData)); 594 595 Serial.printf("Board ID %u: %u bytes\n", myData.id, len); 596 597 // Update the structures with the new incoming data 598 599 boardsStruct[myData.id - 1].distance = myData.distance; 600 601 Serial.printf("distance value: %f \n", boardsStruct[myData.id - 1].distance); 602 603 Serial.println(); 604 // Extract sensor ID from incoming data 605 uint8_t sensorID = incomingData[0]; // Assuming the first byte contains the sensor ID 606 607 // Update the timestamp for the corresponding sensor 608 lastReceivedTime[sensorID - 1] = millis() / 1000; // Store current time in seconds 609 } 610 611 void GetDateTime(String initialDate) { 612 613 String strs[3]; 614 int StringCount = 0; 615 while (initialDate.length() > 0) { 616 int index = initialDate.indexOf('/'); 617 if (index == -1) // No slash found 618 { 619 strs[StringCount++] = initialDate; 620 break; 621 } 622 else { 623 strs[StringCount++] = initialDate.substring(0, index); 624 initialDate = initialDate.substring(index + 1); 625 } 626 627 628 } 629 630 631 initialDateTime.tm_hour = 0; initialDateTime.tm_min = 0; initialDateTime.tm_sec = 0; 632 initialDateTime.tm_year = (strs[2].toInt() - 1900); initialDateTime.tm_mon = (strs[1].toInt() - 1); initialDateTime.tm_mday = strs[0].toInt(); 633 634 } 635 636 // This function will be called every time button Widget 637 // in Blynk app writes values to the Virtual Pin V3 638 BLYNK_WRITE(V5) { 639 int pinValue = param.asInt(); // Assigning incoming value from pin V3 to a variable 640 if (pinValue == 1) { 641 pumpauth=1; 642 } else { 643 pumpauth=0; 644 } 645 } 646 647 // Function to check if a sensor has sent data within the allowed time gap and has a non-zero timestamp 648 bool isSensorActive(int sensorID) { 649 unsigned long currentTime = millis() / 1000; // Current time in seconds 650 unsigned long lastReceived = lastReceivedTime[sensorID - 1]; // Last received time for the sensor 651 652 // Check if the time difference is within the allowed limit and the timestamp is non-zero 653 return (lastReceived != 0 && (currentTime - lastReceived) <= MAX_TIME_GAP); 654 } 655 656 // Function to count active sensors 657 int countActiveSensors() { 658 int activeCount = 0; 659 for (int i = 0; i < 4; ++i) { 660 if (isSensorActive(i + 1)) { 661 activeCount++; 662 } 663 } 664 return activeCount; 665 } 666 667 void otadisplay() { 668 display.clear(); 669 // Print water heights 670 display.setFont(ArialMT_Plain_10); 671 display.drawString(0, 0, "OTA Started from:" + String(overTheAirURL)); 672 display.drawString(0, 10, String(overTheAirURL)); 673 display.display(); 674 } 675 void otafaileddisplay(){ 676 display.clear(); 677 // Print water heights 678 display.setFont(ArialMT_Plain_10); 679 display.drawString(0, 0, "OTA failed"); 680 display.display(); 681 } 682 683 BLYNK_WRITE_DEFAULT() { 684 String command = param.asStr(); 685 686 if (command.startsWith("s1c")) { 687 bs1c = command.substring(4).toFloat(); 688 Blynk.virtualWrite(V6, "s1c is changed"); 689 } else if (command.startsWith("s2c")) { 690 bs2c = command.substring(4).toFloat(); 691 Blynk.virtualWrite(V6, "s2c is changed"); 692 } else if (command.startsWith("s3c")) { 693 bs3c = command.substring(4).toFloat(); 694 Blynk.virtualWrite(V6, "s3c is changed"); 695 } else if (command.startsWith("s4c")) { 696 bs4c = command.substring(4).toFloat(); 697 Blynk.virtualWrite(V6, "s4c is changed"); 698 } else if (command.startsWith("gl")) { 699 bgroundLevel = command.substring(3).toInt(); 700 Blynk.virtualWrite(V6, "groundLevel is changed"); 701 } else if (command.startsWith("m1l")) { 702 bm1low = command.substring(4).toFloat(); 703 Blynk.virtualWrite(V6, "mode 1 low threshold is changed"); 704 } else if (command.startsWith("m1h")) { 705 bm1high = command.substring(4).toFloat(); 706 Blynk.virtualWrite(V6, "mode 1 high threshold is changed"); 707 } else if (command.startsWith("m2t")) { 708 bm2t = command.substring(4).toFloat(); 709 Blynk.virtualWrite(V6, "mode 2 threshold is changed"); 710 } else if (command.startsWith("prefc")) { 711 preferences.begin("irrigation", false); 712 preferences.clear(); 713 preferences.end(); 714 Blynk.virtualWrite(V6, "pref is cleared"); 715 } else if (command.equals("reboot")) { 716 Blynk.virtualWrite(V6, "Restarting ESP8266..."); 717 //delay(1000); 718 ESP.restart(); 719 } else if (command.startsWith("idate")) { 720 String newDate = command.substring(6); 721 if (isValidDateFormat(newDate)) { 722 binitialDate = newDate; 723 GetDateTime(initialDate); 724 savePreferences1(); 725 Blynk.virtualWrite(V6, "initialDate is changed"); 726 } else { 727 Blynk.virtualWrite(V6, "Invalid date format. Please use dd/mm/yyyy."); 728 } 729 } else if (command.startsWith("lidate")) { 730 String newDate2 = command.substring(7); 731 if (isValidDateFormat(newDate2)) { 732 int liday = newDate2.substring(0, 2).toInt(); 733 int limonth = newDate2.substring(3, 5).toInt()-1; 734 int liyear = newDate2.substring(6).toInt()-1900; 735 736 Serial.print("Last irrigation day: "); 737 Serial.println(liday); 738 Serial.print("Last irrigation month: "); 739 Serial.println(limonth); 740 Serial.print("Last irrigation year: "); 741 Serial.println(liyear); 742 743 preferences.begin("irrigation", false); 744 preferences.putInt("lastIrriagationDay", liday); 745 preferences.putInt("lastIrriagationMon", limonth); 746 preferences.putInt("lastIrriagationYear", liyear); 747 preferences.end(); 748 749 Blynk.virtualWrite(V6, "last irrigation Date is changed"); 750 } else { 751 Blynk.virtualWrite(V6, "Invalid date format. Please use dd/mm/yyyy."); 752 } 753 } else { 754 // Handle commands received from the Blynk Terminal widget 755 // Add your custom commands handling here 756 Blynk.virtualWrite(V6, "Not a command: " + command); 757 } 758 759 savePreferences1(); 760 } 761 762 763 764 void savePreferences1() { 765 preferences1.begin("settings", false); // Open preferences with settings namespace 766 preferences1.putString("initialDate", initialDate); 767 preferences1.putFloat("s1c", bs1c); 768 preferences1.putFloat("s2c", bs2c); 769 preferences1.putFloat("s3c", bs3c); 770 preferences1.putFloat("s4c", bs4c); 771 //preferences1.putFloat("distanceAvg", distanceAvg); 772 preferences1.putInt("groundLevel", bgroundLevel); 773 774 preferences1.putFloat("m1high", bm1high); 775 preferences1.putFloat("m1low", bm1low); 776 preferences1.putFloat("m2t", bm2t); 777 preferences1.end(); // Close the preferences 778 Blynk.virtualWrite(V6, "savepref1"); 779 } 780 781 void loadPreferences1() { 782 preferences1.begin("settings", true); // Open preferences with settings namespace, read-only 783 initialDate = preferences1.getString("initialDate", initialDate); 784 s1c = preferences1.getFloat("s1c", 0); 785 s2c = preferences1.getFloat("s2c", 0); 786 s3c = preferences1.getFloat("s3c", 0); 787 s4c = preferences1.getFloat("s4c", 0); 788 //distanceAvg = preferences1.getFloat("distanceAvg", 0); 789 groundLevel = preferences1.getInt("groundLevel", 0); 790 m1high = preferences1.getFloat("m1high", m1high); 791 m1low = preferences1.getFloat("m1low", m1low); 792 m2t = preferences1.getFloat("m2t", m2t); 793 preferences1.end(); // Close the preferences 794 // Blynk.virtualWrite(V6, m1high); 795 // Blynk.virtualWrite(V6, m1low); 796 // Blynk.virtualWrite(V6, m2t); 797 Blynk.virtualWrite(V6, "loadpref1"); 798 } 799 800 801 bool isValidDateFormat(String date) { 802 if (date.length() != 10) { 803 return false; 804 } 805 if (date[2] != '/' || date[5] != '/') { 806 return false; 807 } 808 for (int i = 0; i < 10; i++) { 809 if (i != 2 && i != 5 && !isdigit(date[i])) { 810 return false; 811 } 812 } 813 return true; 814 } 815 816 void getlastirrigationdate() 817 { 818 preferences.begin("irrigation", true); 819 lastIrriagationDate.tm_year = preferences.getInt("lastIrriagationYear",0); // Years since 1900 820 lastIrriagationDate.tm_mon = preferences.getInt("lastIrriagationMon",0); // Months since January 821 lastIrriagationDate.tm_mday = preferences.getInt("lastIrriagationDay",0); 822 lastIrriagationDate.tm_hour = preferences.getInt("lastIrriagationHr",0); 823 lastIrriagationDate.tm_min = preferences.getInt("lastIrriagationMin",0); 824 lastIrriagationDate.tm_sec = preferences.getInt("lastIrriagationSec",0); 825 826 char date_str[20]; // Assuming 20 characters are sufficient 827 // Set the values for lastIrriagationDate as you have done 828 // Convert the date to a string 829 strftime(date_str, sizeof(date_str), "%d/%m/%Y", &lastIrriagationDate); 830 // Print the formatted date string 831 Serial.print("Last irrigation date: "); 832 Serial.println(date_str); 833 Blynk.virtualWrite(V7, "Last irrigation date: " + String(date_str)); 834 preferences.end(); 835 }