Advertisement
mayerm001

ToroSwitch

Mar 30th, 2023 (edited)
426
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.20 KB | Source Code | 0 0
  1. //
  2. // Toro Watering Controller (c) Mihaly Mayer 2021-May
  3. // version 3.5
  4. // Update: 2021.06.06 Cancel Watering
  5. //
  6.  
  7. ADC_MODE(ADC_TOUT);
  8.  
  9. #include <NTPClient.h>
  10. #include <ESP8266WiFiMulti.h>
  11. #include <ESP8266HTTPClient.h>
  12. #include <DHT.h>
  13. #include <Wire.h>
  14. #include <WiFiUdp.h>
  15. #include <ArduinoJson.h>
  16. #include <Wire.h>
  17. #include <ESP8266WebServer.h>
  18.  
  19. #define DEBUG 0
  20. #define moistureDry 1024
  21. #define moistureWet 16
  22. #define HTTP_OK 200
  23. #define MILLISEC 1000
  24. #define ACTIVE "1"
  25. #define DELAY 15000
  26. unsigned long startmillis, currentmillis;
  27.  
  28. int temperateMin = 15;
  29. int moistureMax = 512;
  30. int moisturePin = A0;
  31. int device_id = 5;
  32. float temperature = 0.0;
  33. float humidity = 0.0;
  34. float heat_index = 0.0;
  35. int soil = 0;
  36. int rain = 0;
  37. int moisure = 0;
  38. boolean watering = false;
  39. boolean actually_watering = false;
  40. int DHT_PIN = 2;    // D4
  41. int RAIN_PIN = 5;   // D1
  42.  
  43. #define AVG_NOZZLE 4
  44. #define AVG_LITER 0.16
  45.  
  46. #define MAX_RELAYS 6
  47. #define WATER_R1 4   // D2
  48. #define WATER_R2 0   // D3
  49. #define WATER_R3 12  // D6
  50. #define WATER_R4 13  // D7
  51. #define WATER_R5 15  // D8  
  52. #define WATER_R6 16  // D5
  53. int water_relays[MAX_RELAYS] = {WATER_R1, WATER_R2, WATER_R3, WATER_R4, WATER_R5, WATER_R6};
  54. String water_relays_name[MAX_RELAYS] = {"WATER_R1", "WATER_R2", "WATER_R3", "WATER_R4", "WATER_R5", "WATER_R6"};
  55.  
  56. #define MAX_TIMES 6
  57. String water_times[MAX_TIMES][3] = {{"07:00","1","1"},{"13:00","1","1"},{"15:00","1","1"},
  58.                               {"17:00","0","0"},{"18:00","0","0"},{"19:00","0","0"}};
  59. #define MAX_PROGRAMS 6
  60. int water_programs[MAX_PROGRAMS][MAX_RELAYS] = {{120,120,120,120,120,0},{0,120,120,0,0,0},{0,0,0,0,120,0},
  61.                                                 {120,120,120,120,120,0},{0,60,60,0,0,0},{30,30,0,0,30,0}};
  62. String router_name;
  63. String localip;
  64. long rssi_value = 0;
  65. float vcc_value = 0.0;
  66. String apiKeyValue = "...";
  67. const char* serverWeather = "http://192.168.0.23:8585/post-weather-extra-ip.php";
  68. const char* serverParams = "http://192.168.0.23:8585/rain_params.php";
  69. const char* serverWaterParams = "http://192.168.0.23:8585/water_params.php";
  70. const char* serverWaterUpdate = "http://192.168.0.23:8585/post_water_update.php";
  71. const char* serverWater = "http://192.168.0.23:8585/post-water.php";
  72.  
  73. ESP8266WebServer ESPServer(9595);
  74. ESP8266WiFiMulti wifiMulti;
  75. IPAddress ip(192, 168, 0, 95);
  76. IPAddress gateway(192, 168, 0, 1);
  77. IPAddress dns(8,8,8,8);
  78. IPAddress subnet(255, 255, 255, 0);
  79. char WiFiPassword[] = "...";
  80. WiFiUDP ntpUDP;
  81. int GTMOffset = 2;
  82. NTPClient timeClient(ntpUDP, "pool.ntp.org", GTMOffset*60*60);
  83.  
  84. boolean connectToWifi()
  85. {
  86.   WiFi.config(ip, gateway, subnet, dns);
  87.   while (wifiMulti.run() != WL_CONNECTED) delay(500);
  88.   if (wifiMulti.run() == WL_CONNECTED)
  89.   {
  90.     Serial.println("WIFI ON");
  91.     localip = WiFi.localIP().toString();
  92.     timeClient.begin();
  93.     return true;
  94.   } else
  95.   {
  96.     Serial.println("WIFI OFF");
  97.     return false;
  98.   }
  99. }
  100.  
  101. void get_sensor_Values()
  102. {
  103.   DHT dht(DHT_PIN, DHT11);
  104.   dht.begin();
  105.   for (int index=0; index<5; index++)
  106.   {
  107.     humidity = dht.readHumidity();
  108.     temperature = dht.readTemperature();
  109.     heat_index = dht.computeHeatIndex();
  110.     if (isnan(humidity) && isnan(temperature))
  111.     {
  112.       humidity = 0.0; temperature = 0.0; heat_index = 0.0;
  113.     } else
  114.     {
  115.       heat_index = dht.computeHeatIndex(temperature,humidity, false);
  116.       break;
  117.     }
  118.     delay(500);
  119.   }
  120.   getRainParams(serverParams);
  121.   soil = analogRead(moisturePin);
  122.   Serial.println("Temperature: " + String(temperature) + " - Humidity: " + String(humidity) + " - Soil: " + String(soil));
  123.   if (rain == 1 || temperature <= temperateMin || soil <= moistureMax) {
  124.     digitalWrite(RAIN_PIN,HIGH); // Rain Sensor ON (No watering)
  125.     Serial.println("Relay HIGH - watering disable");
  126.     watering = false;
  127.   } else {
  128.     Serial.println("Relay LOW - watering enable");
  129.     digitalWrite(RAIN_PIN,LOW); // Rain Sensor OFF (Watering)
  130.     watering = true;
  131.   }
  132. }
  133.  
  134. void getRainParams(String server)
  135. {
  136.   WiFiClient client;
  137.   HTTPClient http;
  138.   String payload;
  139.   DynamicJsonDocument doc(512);
  140.      
  141.   http.begin(client, server);
  142.   int httpResponseCode = http.GET();
  143.   if (httpResponseCode == HTTP_OK) {
  144.     payload = http.getString();        
  145.     deserializeJson(doc, payload);
  146.     JsonObject root = doc.as<JsonObject>();
  147.     moistureMax = root["soil_param"].as<int>();
  148.     rain = root["rain"].as<int>();
  149.     temperateMin = root["temp_param"].as<int>();
  150. #ifdef DEBUG
  151.     Serial.println("MoisureMax = " + String(moistureMax) + " - TemperateMin = " + String(temperateMin) + " - RainSet = " + String(rain));
  152. #endif
  153.   }
  154.   http.end();
  155. }
  156.  
  157. void sendValues_to_database(String server, String key, float temp, float hum,
  158.   float heat, float pres, float alt, int moisure, float soil, int device, String router, String localip, long rsi, float vcc)
  159. {
  160.   WiFiClient client;
  161.   HTTPClient http;
  162.   http.begin(client, server);
  163.   http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  164.   String httpRequestData = "api_key=" + key
  165.                            + "&temperature=" + String(temp)
  166.                            + "&humidity=" + String(hum)
  167.                            + "&heat=" + String(heat)                                    
  168.                            + "&device=" + String(device)                          
  169.                            + "&pressure=" + String(pres)
  170.                            + "&altitude=" + String(alt)                        
  171.                            + "&moisure=" + String(moisure)                                            
  172.                            + "&soil=" + String(soil)
  173.                            + "&router=" + router
  174.                            + "&ip=" + localip
  175.                            + "&rssi=" + String(rsi)
  176.                            + "&vcc=" + String(vcc);
  177.   int httpResponseCode = http.POST(httpRequestData);
  178.   http.end();
  179. #ifdef DEBUG
  180.   Serial.println(httpRequestData);
  181.   Serial.println(httpResponseCode);
  182. #endif
  183. }
  184.  
  185. void sendWater_to_database(String server, String key, int wtime, float liter)
  186. {
  187.   WiFiClient client;
  188.   HTTPClient http;
  189.   http.begin(client, server);
  190.   http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  191.   String httpRequestData = "api_key=" + key
  192.                            + "&time=" + String(wtime) +
  193.                            + "&liter=" + String(liter);
  194.   int httpResponseCode = http.POST(httpRequestData);
  195.   http.end();
  196. #ifdef DEBUG
  197.   Serial.println(httpRequestData);
  198.   Serial.println(httpResponseCode);
  199. #endif
  200. }
  201.  
  202. void updateWater_to_database(String server, String key, int water)
  203. {
  204.   WiFiClient client;
  205.   HTTPClient http;
  206.   http.begin(client, server);
  207.   http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  208.   String httpRequestData = "api_key=" + key
  209.                            + "&water=" + String(water);
  210.   int httpResponseCode = http.POST(httpRequestData);
  211.   http.end();
  212. #ifdef DEBUG
  213.   Serial.println(httpRequestData);
  214.   Serial.println(httpResponseCode);
  215. #endif
  216. }
  217.  
  218. void relaysINIT()
  219. {
  220.   for (int i = 0; i < MAX_RELAYS; i++)
  221.   {
  222.     pinMode(water_relays[i], OUTPUT);
  223.     digitalWrite(water_relays[i], INPUT_PULLUP);
  224.     digitalWrite(water_relays[i], HIGH);  
  225.   }
  226. }
  227.  
  228. void send_sensor_Values()
  229. {
  230.     router_name = WiFi.SSID();
  231.     rssi_value = WiFi.RSSI();
  232.     vcc_value = 5.00; // ((float)ESP.getVcc()/1000);
  233.     sendValues_to_database(serverWeather, apiKeyValue, temperature, humidity, heat_index, 0.0, 0.0, rain ,soil,
  234.       device_id, router_name, localip, rssi_value, vcc_value);
  235. }
  236.  
  237. String getValue(String data, char separator, int index)
  238. {
  239.   int found = 0;
  240.   int strIndex[] = {0, -1};
  241.   int maxIndex = data.length()-1;
  242.   for(int i=0; i<= maxIndex && found <= index; i++){
  243.     if(data.charAt(i) == separator || i == maxIndex){
  244.         found++;
  245.         strIndex[0] = strIndex[1]+1;
  246.         strIndex[1] = (i == maxIndex) ? i+1 : i;
  247.     }
  248.   }
  249.   return found>index ? data.substring(strIndex[0], strIndex[1]) : "";
  250. }
  251.  
  252. void get_water_Values(String server)
  253. {
  254.   WiFiClient client;
  255.   HTTPClient http;
  256.   String payload = "";
  257.   DynamicJsonDocument doc(1024);    
  258.   http.begin(client, server);
  259.   int httpResponseCode = http.GET();
  260.   if (httpResponseCode == HTTP_OK)
  261.     payload = http.getString();
  262.   http.end();
  263.  
  264.   if (payload != "")
  265.   {  
  266.     String times = getValue(payload,';',0);
  267.     deserializeJson(doc, times);
  268.     JsonArray times_root = doc.as<JsonArray>();
  269.     for (int i=0; i < MAX_TIMES; i++) {
  270.       JsonObject obj = times_root[i];
  271.       water_times[i][0] = obj["timestamp"].as<String>();  
  272.       water_times[i][1] = obj["program"].as<String>();
  273.       water_times[i][2] = obj["active"].as<String>();
  274.       Serial.println("Timestamp: " + water_times[i][0] +
  275.           " - Program: " + water_times[i][1] +
  276.           " - Active: " + water_times[i][2]);
  277.     }
  278.    
  279.     String programs = getValue(payload,';',1);
  280.     deserializeJson(doc, programs);
  281.     JsonArray programs_root = doc.as<JsonArray>();
  282.     for (int i=0; i < MAX_PROGRAMS; i++) {
  283.        JsonObject obj = programs_root[i];
  284.        water_programs[i][0] = obj["R1"].as<int>();
  285.        water_programs[i][1] = obj["R2"].as<int>();
  286.        water_programs[i][2] = obj["R3"].as<int>();
  287.        water_programs[i][3] = obj["R4"].as<int>();
  288.        water_programs[i][4] = obj["R5"].as<int>();
  289.        water_programs[i][5] = obj["R6"].as<int>();
  290.     }
  291.    
  292.     for (int i = 0; i < MAX_PROGRAMS; i++)
  293.     {
  294.       Serial.print("Program: " + String(i) + " - ");
  295.       for (int j = 0; j < MAX_RELAYS; j++)
  296.         Serial.print("R" + String(j+1) + ": " + String(water_programs[i][j]) + " second, ");
  297.       Serial.println();
  298.     }
  299.   }
  300. }
  301.  
  302. String get_actually_time(boolean sec)
  303. {
  304.   timeClient.update();
  305.   String times = leadingZero(String(timeClient.getHours())) + ":" + leadingZero(String(timeClient.getMinutes()));
  306.   if (sec == true) times = times + ":" +  leadingZero(String(timeClient.getSeconds()));
  307.   return times;
  308. }
  309.  
  310. String leadingZero(String value)
  311. {
  312.   value.trim();
  313.   if (value.length() == 1) return "0" + value;
  314.   else return value;
  315. }
  316.  
  317.  
  318. void watering_program()
  319. {
  320.   int wtime = 0;
  321.   float wwater = 0.0;
  322.   watering = false;
  323.   String actually_time = get_actually_time(false);
  324.   Serial.println("Time is: " + actually_time);
  325.   for (int i = 0; i < MAX_TIMES; i++)
  326.   {
  327.     if (water_times[i][0].equals(actually_time) && water_times[i][2].equals(ACTIVE)) // watering time
  328.     {
  329.       int actually_program = water_times[i][1].toInt()-1;
  330.       Serial.println("Actually program: " + String(actually_program));
  331.       for (int j = 0; j < MAX_RELAYS; j++)
  332.       {
  333.         if ((watering == false) && (water_programs[actually_program][j] != 0))
  334.         {
  335.           updateWater_to_database(serverWaterUpdate, apiKeyValue, 1);
  336.           actually_watering = true;
  337.           relaysON(j, water_programs[actually_program][j]);
  338.           actually_watering = false;
  339.           wtime = wtime + water_programs[actually_program][j];
  340.           wwater = wwater + ((water_programs[actually_program][j] * AVG_LITER) * AVG_NOZZLE);
  341.           updateWater_to_database(serverWaterUpdate, apiKeyValue, 0);
  342.           if (digitalRead(RAIN_PIN) == HIGH) j = MAX_RELAYS; // cancel Watering
  343.         }
  344.       }
  345.     }
  346.   }
  347.   if (wtime != 0)
  348.   {
  349.     Serial.println(String(wtime) + " - " + String(wwater));
  350.     sendWater_to_database(serverWater, apiKeyValue, wtime, wwater);
  351.   }
  352.   watering = true;
  353. }
  354.  
  355.  
  356. void relaysON(int relay, int time_min)
  357. {
  358.   relaysINIT();
  359.   switch (relay)
  360.   {
  361.     case 0:
  362.       digitalWrite(WATER_R1, LOW);
  363.       break;
  364.     case 1:
  365.       digitalWrite(WATER_R2, LOW);
  366.       break;
  367.     case 2:  
  368.       digitalWrite(WATER_R3, LOW);
  369.       break;
  370.     case 3:
  371.       digitalWrite(WATER_R4, LOW);
  372.       break;
  373.     case 4:  
  374.       digitalWrite(WATER_R5, LOW);
  375.       break;
  376.     case 5:
  377.       digitalWrite(WATER_R6, LOW);
  378.       break;              
  379.   }
  380.   Serial.println("Watering start with " + water_relays_name[relay] + " at " + get_actually_time(true) + " for " + String(time_min) +  " second");
  381.   unsigned long etime = timeClient.getEpochTime() + time_min;
  382.   while (timeClient.getEpochTime() <= etime)
  383.   {
  384.     ESPServer.handleClient();
  385.   }
  386.   //delay(time_min * MILLISEC);
  387.   Serial.println("Watering end with " + water_relays_name[relay] + " at " + get_actually_time(true));
  388.   relaysINIT();
  389. }
  390.  
  391. void handleRoot() {
  392.     String html = "<html><head><meta http-equiv='refresh' content='60'><title>Watering System</title></head>";
  393.     html = html + "<body>TORO Watering System (c) Mayer Mihaly 2021-Apr<br><b>Ready</b>";
  394.     html = html + "<br><br>Time is " + get_actually_time(true);
  395.     html = html + "<br><br>Watering ";
  396.     if (watering)
  397.       html = html + "ON";
  398.     else
  399.       html = html + "OFF";
  400.     if (actually_watering)
  401.       html = html + "<p style='color:#FF0000'><b>Actually is *** running ***</b></p>";
  402.     else
  403.       html = html + "<br>Actually is <b>not running</b><br>";
  404.     html = html + "Temperature = " + String(temperature) + " (" + String(heat_index) + ")" +
  405.       ", Humidity = " + String(humidity) +
  406.       ", Soil = " + String(soil) +
  407.       ", Rain = " + String(rain);
  408.     html = html + "<br>";
  409.    
  410.     for (int i=0; i < MAX_TIMES; i++) {
  411.       html = html + "<br>Timestamp: " + water_times[i][0] +
  412.           " - Program: " + water_times[i][1] + " - Active: " + water_times[i][2];
  413.     }
  414.    
  415.     html = html + "<br>";
  416.     for (int i = 0; i < MAX_PROGRAMS; i++)
  417.     {
  418.       html = html + "<br>Program: " + String(i+1) + " - ";
  419.       for (int j = 0; j < MAX_RELAYS; j++)
  420.         html = html + "R" + String(j+1) + ": " + String(water_programs[i][j]) + " second, ";
  421.     }
  422.     html = html + "</body></html>";    
  423.     ESPServer.send(200, "text/html", html);
  424. }
  425.  
  426. void handleOFF() {
  427.     ESPServer.send(200, "text/html", "TORO Watering System<br>Watering is <b>OFF</b>");
  428.     digitalWrite(RAIN_PIN,HIGH); // Rain Sensor ON (No watering)
  429.     watering = true;
  430. }
  431. void handleON() {
  432.     ESPServer.send(200, "text/html", "TORO Watering System<br>Watering is <b>ON</b>");
  433.     digitalWrite(RAIN_PIN,LOW); // Rain Sensor OFF (Watering)
  434.     watering = false;
  435. }
  436.  
  437. void setup() {
  438.   Serial.begin(115200);
  439.   wifiMulti.addAP("thome2", WiFiPassword);
  440.   wifiMulti.addAP("TP-LINK", WiFiPassword);
  441.   wifiMulti.addAP("TP-LINK-2", WiFiPassword);
  442.   connectToWifi();
  443.   localip = WiFi.localIP().toString();
  444.   pinMode(RAIN_PIN,OUTPUT);
  445.   relaysINIT();
  446.   startmillis = millis();
  447.   ESPServer.on("/", HTTP_GET, handleRoot);
  448.   ESPServer.on("/on", HTTP_GET, handleON);
  449.   ESPServer.on("/off", HTTP_GET, handleOFF);
  450.   timeClient.update();
  451.   Serial.println("Time is: " + get_actually_time(false));
  452.  
  453. }
  454.  
  455. void loop() {
  456.   if (wifiMulti.run() != WL_CONNECTED) connectToWifi();
  457.   timeClient.update();
  458.   ESPServer.begin();
  459.   ESPServer.handleClient();
  460.   currentmillis = millis();
  461.   if ((currentmillis - startmillis) >=  DELAY) {
  462.     get_sensor_Values();  
  463.     send_sensor_Values();
  464.     get_water_Values(serverWaterParams);
  465.     Serial.println("watering=" + String(watering));  
  466.     if (watering == true)
  467.     {
  468.       watering_program();
  469.       digitalWrite(RAIN_PIN,LOW); // Watering ON
  470.     }
  471.     startmillis = currentmillis;
  472.   }
  473.   if ((get_actually_time(true) >= "00:00:00") && (get_actually_time(true) <= "00:00:02"))
  474.     ESP.restart();
  475. }
  476.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement