RTC clock and timers fixed
public
Mar 19, 2024
Never
30
1 /* Comment this out to disable prints and save space */ 2 #define BLYNK_PRINT Serial 3 4 /* Fill in information from Blynk Device Info here */ 5 #define BLYNK_TEMPLATE_ID "XXXXXX" 6 #define BLYNK_TEMPLATE_NAME "ota test" 7 #define BLYNK_AUTH_TOKEN "XXXXXX" 8 9 #define BLYNK_FIRMWARE_VERSION "1.9.5" 10 11 #include <SPI.h> 12 #include <ESP8266WiFi.h> 13 #include <BlynkSimpleEsp8266.h> 14 #include <TimeLib.h> 15 #include <WidgetRTC.h> 16 #include <Wire.h> 17 #include <Adafruit_GFX.h> 18 #include <SH1106Wire.h> 19 #include <espnow.h> 20 #include <WiFiClient.h> 21 #include <WiFiClientSecure.h> 22 #include <ESP8266HTTPClient.h> 23 #include <ESP8266httpUpdate.h> 24 #include <ESP8266HTTPUpdateServer.h> 25 #include <Preferences.h> 26 #include "HTTPSRedirect.h" 27 28 BlynkTimer timer; 29 30 WidgetRTC rtc; 31 32 const char* ssid = "AC/DC_P"; // Name of the Wi-Fi box 33 const char* password = "donttouchmywifi"; // MDP of the Wi-Fi box 34 35 // Declare the target date in dd/mm/yyyy format 36 String initialDate = "01/03/2024"; 37 struct tm lastIrriagationDate = {0}; 38 39 // Define a constant for the maximum allowed time gap in seconds (5 minutes = 300 seconds) 40 const unsigned long MAX_TIME_GAP = 300; 41 42 // Define an array to store the last received timestamps for each sensor 43 unsigned long lastReceivedTime[4] = {0}; // Initialize all elements to 0 44 45 int groundLevel=0; 46 int bgroundLevel; 47 int m1low = 3; 48 int m1high = 8; 49 int m2t =8; 50 int bm1low, bm1high, bm2t; 51 52 float s1c, s2c, s3c, s4c; 53 float bs1c, bs2c, bs3c, bs4c; 54 55 int activeSensorCount = 0; 56 String overTheAirURL = ""; 57 bool pumpauth=1; 58 59 #define SDA_PIN D2 60 #define SCL_PIN D1 61 62 SH1106Wire display(0x3c, SDA_PIN, SCL_PIN); 63 64 // Enter Google Script Deployment ID: 65 const char *GScriptId = "XXXXXX"; 66 67 // Enter command (insert_row or append_row) and your Google Sheets sheet name (default is Sheet1): 68 String payload_base = "{\"command\": \"insert_row\", \"sheet_name\": \"Sheet1\", \"values\": "; 69 String payload = ""; 70 71 // Google Sheets setup (do not edit) 72 const char* host = "script.google.com"; 73 const int httpsPort = 443; 74 const char* fingerprint = ""; 75 String url = String("/macros/s/") + GScriptId + "/exec"; 76 HTTPSRedirect* client = nullptr; 77 78 // Declare variables that will be published to Google Sheets 79 float value0 = 0; 80 float value1 = 0; 81 float value2 = 0; 82 float value3 = 0; 83 float value4 = 0; 84 bool value5 = 0; 85 bool value6 = 0; 86 float value7 = 0; 87 float value8 = 0; 88 float value9 = 0; 89 float value10 = 0; 90 float value11 = 0; 91 String value12 = initialDate; 92 float value13 = 0; 93 float value14 = 0; 94 float value15 = 0; 95 float value16 = 0; 96 float value17 = 0; 97 float value18 = 0; 98 float value19 = 0; 99 float value20 = 0; 100 101 double seconds_diff; 102 int days_diff, days_diff2 ; 103 104 // Relay pin 105 const int relayPin = D7; 106 107 float distance1, distance2, distance3, distance4, distanceAvg; 108 float wh1, wh2, wh3, wh4; 109 float waterHeight =0; 110 111 Preferences preferences; 112 113 typedef struct struct_message { 114 int id; 115 float distance; 116 } struct_message; 117 118 // Create a struct_message called myData 119 struct_message myData; 120 121 // Create a structure to hold the readings from each board 122 struct_message board1; 123 struct_message board2; 124 struct_message board3; 125 struct_message board4; 126 127 // Create an array with all the structures 128 struct_message boardsStruct[4] = {board1, board2, board3, board4}; 129 130 131 // Digital clock display of the time 132 void clockDisplay() 133 { 134 // You can call hour(), minute(), ... at any time 135 // Please see Time library examples for details 136 137 int hour_12h = hourFormat12(); 138 String am_pm = (hour() < 12) ? "AM" : "PM"; 139 140 String currentTime = String(hour_12h) + ":" + minute() + ":" + second() + " " + am_pm; 141 String currentDate = String(day()) + " " + month() + " " + year(); 142 Serial.print("Current time: "); 143 Serial.print(currentTime); 144 Serial.print(" "); 145 Serial.print(currentDate); 146 Serial.println(); 147 148 // Calculate the difference in days 149 int days_diff = calculatedays_difference(initialDate); 150 Serial.print("Days difference: "); 151 Serial.println(days_diff); 152 } 153 154 // Function to calculate the difference in days between target date and current date 155 int calculatedays_difference(String initialDate) 156 { 157 // Parse target date 158 int targetDay, targetMonth, targetYear; 159 const char* initialDateChar = initialDate.c_str(); 160 sscanf(initialDateChar, "%d/%d/%d", &targetDay, &targetMonth, &targetYear); 161 162 // Create tmElements_t structure 163 tmElements_t tm; 164 tm.Year = targetYear - 1970; // Years since 1970 165 tm.Month = targetMonth; 166 tm.Day = targetDay; 167 tm.Hour = 0; 168 tm.Minute = 0; 169 tm.Second = 0; 170 171 // Convert tmElements_t structure to time_t 172 time_t targetTime = makeTime(tm); 173 // Calculate current time 174 time_t currentTime = now(); 175 // Calculate difference in seconds 176 int secondsDiff = difftime(currentTime, targetTime); 177 // Convert seconds to days 178 int days_diff = secondsDiff / 86400; 179 return days_diff; 180 } 181 182 BLYNK_CONNECTED() { 183 // Synchronize time on connection 184 rtc.begin(); 185 } 186 187 void setup() 188 { 189 // Debug console 190 Serial.begin(9600); 191 loadpreferences(); 192 WiFi.mode(WIFI_AP_STA); 193 // Init ESP-NOW 194 if (esp_now_init() != 0) { 195 Serial.println("Error initializing ESP-NOW"); 196 return; 197 } 198 // Once ESPNow is successfully Init, we will register for recv CB to 199 // get recv packer info 200 esp_now_set_self_role(ESP_NOW_ROLE_SLAVE); 201 esp_now_register_recv_cb(OnDataRecv); 202 203 204 Blynk.begin(BLYNK_AUTH_TOKEN, ssid, password); 205 Blynk.syncAll(); 206 // Set relay pin as output 207 pinMode(relayPin, OUTPUT); 208 // Initialize relay to OFF 209 digitalWrite(relayPin, HIGH); 210 display.init(); 211 display.clear(); 212 gsheetsetup(); 213 setSyncInterval(10 * 60); // Sync interval in seconds (10 minutes) 214 // Display digital clock every 10 seconds 215 //timer.setInterval(10000L, clockDisplay); 216 timer.setInterval(1000L, mainloop); // call the take_sensor_reading() function every 5 seconds 217 timer.setInterval(10000L, gsheets); // call the take_sensor_reading() function every 5 seconds 218 timer.setInterval(1000L, blynkdash); 219 220 } 221 222 void loop() 223 { 224 Blynk.run(); 225 timer.run(); 226 } 227 228 void mainloop(){ 229 clockDisplay(); 230 // Calculate average distance from all sub-station sensors 231 distance1 = boardsStruct[0].distance; 232 distance2 = boardsStruct[1].distance; 233 distance3 = boardsStruct[2].distance; 234 distance4 = boardsStruct[3].distance; 235 236 // Assuming groundLevel, s1c, s2c, s3c, s4c are defined elsewhere in your code 237 238 if (distance1 == 0) { 239 wh1 = 0; 240 } else { 241 wh1 = groundLevel - distance1 + s1c; 242 } 243 if (distance2 == 0) { 244 wh2 = 0; 245 } else { 246 wh2 = groundLevel - distance2 + s2c; 247 } 248 if (distance3 == 0) { 249 wh3 = 0; 250 } else { 251 wh3 = groundLevel - distance3 + s3c; 252 } 253 if (distance4 == 0) { 254 wh4 = 0; 255 } else { 256 wh4 = groundLevel - distance4 + s4c; 257 } 258 activeSensorCount = countActiveSensors(); 259 Serial.print("Active Sensors: "); 260 Serial.println(activeSensorCount); 261 if (activeSensorCount !=0 ) { 262 distanceAvg = (distance1 + distance2 + distance3 + distance4) / activeSensorCount; 263 // Calculate water height 264 waterHeight = (wh1+wh2+wh3+wh4)/activeSensorCount; 265 } 266 else { 267 distanceAvg =100; 268 waterHeight=100; 269 } 270 Serial.print("Water height: "); 271 Serial.print(waterHeight); 272 Serial.println(" cm"); 273 274 if (days_diff >= 0 && days_diff <= 21) 275 { 276 if(waterHeight < m1low && digitalRead(relayPin) == HIGH && pumpauth == 1) 277 { 278 digitalWrite(relayPin, LOW); 279 Serial.println("Pump started"); 280 } 281 282 if(waterHeight < m1low && digitalRead(relayPin) == LOW && pumpauth == 0) 283 { 284 digitalWrite(relayPin, HIGH); 285 Serial.println("Pump stopped because of pumpauth"); 286 } 287 288 if(waterHeight > m1high && digitalRead(relayPin) == LOW) 289 { 290 digitalWrite(relayPin, HIGH); 291 Serial.println("Pump stopped"); 292 } 293 294 value15 = 1; 295 Blynk.virtualWrite(V6, "mode 1"); 296 } 297 298 else if (days_diff > 21 && days_diff <= 90) 299 { 300 if(waterHeight > m2t && digitalRead(relayPin) == LOW) 301 { 302 digitalWrite(relayPin, HIGH); 303 Serial.println("Pump stopped"); 304 } 305 306 307 if(waterHeight <= .5) 308 { 309 preferences.begin("irrigation", true); 310 int lastIrriagationDay = preferences.getInt("lastIrriagationDay",0); 311 preferences.end(); 312 if(lastIrriagationDay == 0) // means no data is stored 313 { 314 preferences.begin("irrigation", false); 315 preferences.putInt("lastIrriagationYear", year()); 316 preferences.putInt("lastIrriagationMon", month()); 317 preferences.putInt("lastIrriagationDay", day()); 318 preferences.putInt("lastIrriagationHr", hour()); 319 preferences.putInt("lastIrriagationMin", minute()); 320 preferences.putInt("lastIrriagationSec", second()); 321 preferences.end(); 322 Blynk.virtualWrite(V6, "pref input current date"); 323 } 324 } 325 326 if(waterHeight <m2t) 327 { 328 preferences.begin("irrigation", true); 329 // Load last irrigation time from preference memory 330 int lastYear = preferences.getInt("lastIrriagationYear", 0); 331 int lastMonth = preferences.getInt("lastIrriagationMon", 0); 332 int lastDay = preferences.getInt("lastIrriagationDay", 0); 333 int lastHour = preferences.getInt("lastIrriagationHr", 0); 334 int lastMinute = preferences.getInt("lastIrriagationMin", 0); 335 int lastSecond = preferences.getInt("lastIrriagationSec", 0); 336 preferences.end(); // Close the preferences 337 338 Serial.printf("Last irrigation time: %02d/%02d/%04d %02d:%02d:%02d\n", lastDay, lastMonth, lastYear, lastHour, lastMinute, lastSecond); 339 340 // Create tmElements_t structure for last irrigation time 341 tmElements_t lastIrrigationTime; 342 lastIrrigationTime.Year = lastYear - 1970; // Years since 1970 343 lastIrrigationTime.Month = lastMonth-1; 344 lastIrrigationTime.Day = lastDay; 345 lastIrrigationTime.Hour = lastHour; 346 lastIrrigationTime.Minute = lastMinute; 347 lastIrrigationTime.Second = lastSecond; 348 349 // Convert tmElements_t structure to time_t for last irrigation time 350 time_t lastIrrigationTime_t = makeTime(lastIrrigationTime); 351 352 // Calculate current time 353 time_t currentTime = now(); 354 355 // Calculate difference in seconds 356 int secondsDiff = difftime(currentTime, lastIrrigationTime_t); 357 358 // Convert seconds to days 359 int daysDiff2 = secondsDiff / 86400; 360 Blynk.virtualWrite(V7, "days_diff2: " + String(days_diff2)); 361 } 362 363 if(days_diff2 >= 3 && digitalRead(relayPin) == HIGH && pumpauth == 1) 364 { 365 digitalWrite(relayPin, LOW); 366 Serial.println("Pump started"); 367 368 preferences.begin("irrigation", false); 369 preferences.remove("lastIrriagationYear"); 370 preferences.remove("lastIrriagationMon"); 371 preferences.remove("lastIrriagationDay"); 372 preferences.remove("lastIrriagationHr"); 373 preferences.remove("lastIrriagationMin"); 374 preferences.remove("lastIrriagationSec"); 375 preferences.end(); 376 } 377 if(days_diff2 >= 3 && digitalRead(relayPin) == LOW && pumpauth == 0) 378 { 379 digitalWrite(relayPin, HIGH); 380 Serial.println("Pump stopped because of pumpauth"); 381 } 382 value15= 2; 383 Blynk.virtualWrite(V6, "mode 2"); 384 } 385 else 386 { 387 Serial.print("The unconditional case"); 388 Blynk.virtualWrite(V6, "mode 3"); 389 value15 =3; 390 } 391 if (digitalRead(relayPin) == HIGH){ 392 value6 = 0; 393 } 394 else { 395 value6 = 1; 396 } 397 displayValues(); 398 } 399 400 void blynkdash() 401 402 { 403 Blynk.virtualWrite(V0, wh1); 404 Blynk.virtualWrite(V1, wh2); 405 Blynk.virtualWrite(V2, wh3); 406 Blynk.virtualWrite(V3, wh4); 407 Blynk.virtualWrite(V4, waterHeight); 408 Blynk.virtualWrite(V8, value6); 409 Blynk.virtualWrite(V7, "Dis1: " + String(distance1) + " Dis2: " + String(distance2) + " Dis3: " + String(distance3) + " Dis4: " + String(distance4) + " DisAVG: " + String(distanceAvg)); 410 Blynk.virtualWrite(V7, "s1c: " + String(s1c) + " s2c: " + String(s2c) + " s3c: " + String(s3c) + " s4c: " + String(s4c)); 411 Blynk.virtualWrite(V7, "groundLevel: " + String(groundLevel)); 412 Blynk.virtualWrite(V7, "initialDate: " + String(initialDate)); 413 Blynk.virtualWrite(V7, "days_diff: " + String(days_diff)); 414 Blynk.virtualWrite(V7, "m1high: " + String(m1high) + " m1low: " + String(m1low) + " m2t: " + String(m2t)); 415 // Blynk.virtualWrite(V7, "days_diff2: " + String(days_diff2)); 416 } 417 void gsheets() 418 { 419 value0 = wh1; 420 value1 = wh2; 421 value2 = wh3; 422 value3 = wh4; 423 value4 = waterHeight; 424 value5 = pumpauth; 425 value7 = distance1; 426 value8 = distance2; 427 value9 = distance3; 428 value10 = distance4; 429 430 value11 = distanceAvg; 431 value12 = initialDate; 432 value13 = days_diff; 433 value14 = activeSensorCount; 434 value16 = groundLevel; 435 value17 = s1c; 436 value18 = s2c; 437 value19 = s3c; 438 value20 = s4c; 439 440 441 442 static bool flag = false; 443 if (!flag){ 444 client = new HTTPSRedirect(httpsPort); 445 client->setInsecure(); 446 flag = true; 447 client->setPrintResponseBody(true); 448 client->setContentTypeHeader("application/json"); 449 } 450 if (client != nullptr){ 451 if (!client->connected()){ 452 client->connect(host, httpsPort); 453 } 454 } 455 else{ 456 Serial.println("Error creating client object!"); 457 } 458 459 // Create json object string to send to Google Sheets 460 payload = payload_base + "\"" + \ 461 value12 + "," + value13 + "," + value15 + "," + value14 + "," + value5 + "," + \ 462 value6 + "," + value4 + "," + value0 + "," + value1 + "," + value2 + "," + \ 463 value3 + "," + value11 + "," + value7 + "," + value8 + "," + value9 + "," + \ 464 value10 + "," + value16 + "," + value17 + "," + value18 + "," + value19 + \ 465 "," + value20 + "\"}"; 466 467 468 // Publish data to Google Sheets 469 Serial.println("Publishing data..."); 470 //Serial.println(payload); 471 if(client->POST(url, host, payload)){ 472 // do stuff here if publish was successful 473 } 474 else{ 475 // do stuff here if publish was not successful 476 Serial.println("Error while connecting"); 477 } 478 } 479 480 void gsheetsetup(){ 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 displayValues() { 512 display.clear(); 513 // Print water heights 514 display.setFont(ArialMT_Plain_10); 515 display.drawString(0, 0, "wh1:" + String(wh1)); 516 display.drawString(0, 10, "wh2:" + String(wh2)); 517 display.drawString(0, 20, "wh3:" + String(wh3)); 518 display.drawString(0, 30, "wh4:" + String(wh4)); 519 520 // Print averages and other parameters 521 display.drawString(0, 40, "DisAvg: " + String(distanceAvg)); 522 display.drawString(0, 50, "whAvg: " + String(waterHeight)); 523 // Add more display statements for other parameters 524 display.drawString(70, 0, "Day:" + String(days_diff)); 525 display.drawString(70, 10, "Sensor:" + String(activeSensorCount)); 526 display.drawString(70, 20, "Pumpauth:" + String(pumpauth)); 527 display.drawString(70, 30, "Pump:" + String(value6)); 528 display.drawString(70, 50, "FW:" + String( BLYNK_FIRMWARE_VERSION)); 529 // Display the content 530 display.display(); 531 } 532 533 BLYNK_WRITE(InternalPinOTA) { 534 Serial.println("OTA Started"); 535 Blynk.virtualWrite(V6, "ota started"); 536 overTheAirURL = param.asString(); 537 Serial.print("overTheAirURL = "); 538 Serial.println(overTheAirURL); 539 otadisplay(); 540 WiFiClient my_wifi_client; 541 HTTPClient http; 542 http.begin(my_wifi_client, overTheAirURL); 543 544 545 t_httpUpdate_return ret = ESPhttpUpdate.update(my_wifi_client, overTheAirURL); 546 switch(ret) { 547 case HTTP_UPDATE_FAILED: 548 Serial.println("[update] Update failed."); 549 otafaileddisplay(); 550 break; 551 case HTTP_UPDATE_NO_UPDATES: 552 Serial.println("[update] Update no Update."); 553 otafaileddisplay(); 554 break; 555 case HTTP_UPDATE_OK: 556 Serial.println("[update] Update ok."); // may not be called since we reboot the ESP 557 break; 558 } 559 } 560 561 void OnDataRecv(uint8_t* mac_addr, uint8_t* incomingData, uint8_t len) { 562 563 564 char macStr[18]; 565 Serial.print("Packet received from: "); 566 snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x", 567 mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]); 568 569 570 Serial.println(macStr); 571 memcpy(&myData, incomingData, sizeof(myData)); 572 573 Serial.printf("Board ID %u: %u bytes\n", myData.id, len); 574 575 // Update the structures with the new incoming data 576 577 boardsStruct[myData.id - 1].distance = myData.distance; 578 579 Serial.printf("distance value: %f \n", boardsStruct[myData.id - 1].distance); 580 581 Serial.println(); 582 // Extract sensor ID from incoming data 583 uint8_t sensorID = incomingData[0]; // Assuming the first byte contains the sensor ID 584 585 // Update the timestamp for the corresponding sensor 586 lastReceivedTime[sensorID - 1] = millis() / 1000; // Store current time in seconds 587 } 588 589 BLYNK_WRITE(V5) { 590 int pinValue = param.asInt(); // Assigning incoming value from pin V3 to a variable 591 if (pinValue == 1) { 592 pumpauth=1; 593 } else { 594 pumpauth=0; 595 } 596 } 597 598 bool isSensorActive(int sensorID) { 599 unsigned long currentTime = millis() / 1000; // Current time in seconds 600 unsigned long lastReceived = lastReceivedTime[sensorID - 1]; // Last received time for the sensor 601 602 // Check if the time difference is within the allowed limit and the timestamp is non-zero 603 return (lastReceived != 0 && (currentTime - lastReceived) <= MAX_TIME_GAP); 604 } 605 606 // Function to count active sensors 607 int countActiveSensors() { 608 int activeCount = 0; 609 for (int i = 0; i < 4; ++i) { 610 if (isSensorActive(i + 1)) { 611 activeCount++; 612 } 613 } 614 return activeCount; 615 } 616 617 void otadisplay() { 618 display.clear(); 619 // Print water heights 620 display.setFont(ArialMT_Plain_10); 621 display.drawString(0, 0, "OTA Started from:" + String(overTheAirURL)); 622 display.drawString(0, 10, String(overTheAirURL)); 623 display.display(); 624 } 625 626 void otafaileddisplay(){ 627 display.clear(); 628 // Print water heights 629 display.setFont(ArialMT_Plain_10); 630 display.drawString(0, 0, "OTA failed"); 631 display.display(); 632 } 633 634 BLYNK_WRITE(V6) { 635 String command = param.asStr(); 636 637 if (command.startsWith("s1c")) { 638 bs1c = command.substring(4).toFloat(); 639 Blynk.virtualWrite(V6, "s1c is changed"); 640 } else if (command.startsWith("s2c")) { 641 bs2c = command.substring(4).toFloat(); 642 Blynk.virtualWrite(V6, "s2c is changed"); 643 } else if (command.startsWith("s3c")) { 644 bs3c = command.substring(4).toFloat(); 645 Blynk.virtualWrite(V6, "s3c is changed"); 646 } else if (command.startsWith("s4c")) { 647 bs4c = command.substring(4).toFloat(); 648 Blynk.virtualWrite(V6, "s4c is changed"); 649 } else if (command.startsWith("gl")) { 650 bgroundLevel = command.substring(3).toInt(); 651 Blynk.virtualWrite(V6, "groundLevel is changed"); 652 } else if (command.startsWith("m1l")) { 653 bm1low = command.substring(4).toFloat(); 654 Blynk.virtualWrite(V6, "mode 1 low threshold is changed"); 655 } else if (command.startsWith("m1h")) { 656 bm1high = command.substring(4).toFloat(); 657 Blynk.virtualWrite(V6, "mode 1 high threshold is changed"); 658 } else if (command.startsWith("m2t")) { 659 bm2t = command.substring(4).toFloat(); 660 Blynk.virtualWrite(V6, "mode 2 threshold is changed"); 661 } else if (command.startsWith("prefc")) { 662 preferences.begin("irrigation", false); 663 preferences.clear(); 664 preferences.end(); 665 Blynk.virtualWrite(V6, "pref is cleared"); 666 } else if (command.equals("reboot")) { 667 Blynk.virtualWrite(V6, "Restarting ESP8266..."); 668 //delay(1000); 669 ESP.restart(); 670 } else if (command.startsWith("idate")) { 671 String newDate = command.substring(6); 672 if (isValidDateFormat(newDate)) { 673 initialDate = newDate; 674 savepreferences(); 675 Blynk.virtualWrite(V6, "initialDate is changed"); 676 } else { 677 Blynk.virtualWrite(V6, "Invalid date format. Please use dd/mm/yyyy."); 678 } 679 } else if (command.startsWith("lidate")) { 680 String newDate2 = command.substring(7); 681 if (isValidDateFormat(newDate2)) { 682 int liday = newDate2.substring(0, 2).toInt(); 683 int limonth = newDate2.substring(3, 5).toInt()-1; 684 int liyear = newDate2.substring(6).toInt()-1900; 685 686 Serial.print("Last irrigation day: "); 687 Serial.println(liday); 688 Serial.print("Last irrigation month: "); 689 Serial.println(limonth); 690 Serial.print("Last irrigation year: "); 691 Serial.println(liyear); 692 693 preferences.begin("irrigation", false); 694 preferences.putInt("lastIrriagationDay", liday); 695 preferences.putInt("lastIrriagationMon", limonth); 696 preferences.putInt("lastIrriagationYear", liyear); 697 preferences.end(); 698 699 Blynk.virtualWrite(V6, "last irrigation Date is changed"); 700 } else { 701 Blynk.virtualWrite(V6, "Invalid date format. Please use dd/mm/yyyy."); 702 } 703 } else { 704 // Handle commands received from the Blynk Terminal widget 705 // Add your custom commands handling here 706 Blynk.virtualWrite(V6, "Not a command: " + command); 707 } 708 709 savepreferences(); 710 } 711 712 void savepreferences() { 713 preferences.begin("settings", false); // Open preferences with settings namespace 714 preferences.putString("initialDate", initialDate); 715 preferences.putFloat("s1c", s1c); 716 preferences.putFloat("s2c", s2c); 717 preferences.putFloat("s3c", s3c); 718 preferences.putFloat("s4c", s4c); 719 //preferences.putFloat("distanceAvg", distanceAvg); 720 preferences.putInt("groundLevel", bgroundLevel); 721 722 preferences.putFloat("m1high", m1high); 723 preferences.putFloat("m1low", m1low); 724 preferences.putFloat("m2t", m2t); 725 preferences.end(); // Close the preferences 726 Blynk.virtualWrite(V6, "savepref1"); 727 } 728 729 void loadpreferences() { 730 preferences.begin("settings", true); // Open preferences with settings namespace, read-only 731 initialDate = preferences.getString("initialDate", initialDate); 732 s1c = preferences.getFloat("s1c", 0); 733 s2c = preferences.getFloat("s2c", 0); 734 s3c = preferences.getFloat("s3c", 0); 735 s4c = preferences.getFloat("s4c", 0); 736 groundLevel = preferences.getInt("groundLevel", 0); 737 m1high = preferences.getFloat("m1high", m1high); 738 m1low = preferences.getFloat("m1low", m1low); 739 m2t = preferences.getFloat("m2t", m2t); 740 preferences.end(); // Close the preferences 741 Blynk.virtualWrite(V6, "loadpref1"); 742 } 743 744 745 bool isValidDateFormat(String date) { 746 if (date.length() != 10) { 747 return false; 748 } 749 if (date[2] != '/' || date[5] != '/') { 750 return false; 751 } 752 for (int i = 0; i < 10; i++) { 753 if (i != 2 && i != 5 && !isdigit(date[i])) { 754 return false; 755 } 756 } 757 return true; 758 }