Components and supplies
Soil Moisture Sensor YL-69
1.8" Serial SPI 128x160 Color TFT LCD Module Display (Driver IC ST7735)
QR30E DC 12V 4.2W 240L/H Flow Rate Waterproof Brushless Pump
DS18B20 1-Wire Digital Temperature Sensor
Solenoid Valve ZE-4F180 NC DC 12V
Light Intensity Sensor Module 5528 Photo Resistor
Arduino 101
Tools and machines
Soldering iron (generic)
Apps and platforms
Arduino IDE
Project description
Code
Irrigation system
code
Irrigation system
code
Irrigation system
code
IrrigationSystem.ino
arduino
1/* 2 Irrigation system for plants home use 3 by Rami. eventsur@gmail.com 4 5 components: 6 Arduino or Genuino 101 7 Solenoid Valve ZE-4F180 NC DC 12V 8 Soil Moisture Sensor YL-69 9 Light Intensity Sensor Module 5528 Photo Resistor 10 1.8" Serial SPI 128x160 Color TFT LCD Module Display (Driver IC ST7735) 11 DS18B20 1-Wire Digital Temperature Sensor 12 QR30E DC 12V 4.2W 240L/H Flow Rate Waterproof Brushless Pump 13 14 Moisture soil reading : 15 1000 ~1023 dry soil 16 901 ~999 humid soil 17 0 ~900 in water 18 19 Light reading : 20 no Light 0 - 214 21 light 214 - 1023 22 23 Measures soil moisture and lighting, 24 watering plants when humidity is low and no sun through valve control. 25 Measures and records irrigation time and moisture and lighting values to SD card 26*/ 27#include <CurieTime.h> 28#include <CurieBLE.h> 29#include <ArduinoJson.h> // version 6.16.1 30#include <OneWire.h> 31#include <DallasTemperature.h> 32#include <SPI.h> 33#include <TFT.h> // Arduino LCD library 34#include <SD.h> 35 36// pin definition for sensors 37#define moistureSensorPin A0 // input from moisture sensor 38#define lightSensorPin A1 // input from Light sensor 39#define Valve_Output1_PIN 7 // select the pin for the solenoid valve control 40 41// pin definition for the tft display 42#define cs 10 43#define dc 9 44#define rst 8 45/* 46 The circuit: 47 SD card attached to SPI bus as follows: 48 ** MOSI - pin 11 49 ** MISO - pin 12 50 ** CLK - pin 13 51 ** CS - pin 4 (for MKRZero SD: SDCARD_SS_PIN) 52*/ 53// pin definition for the SD card 54#define SDchipSelect 4 55 56// pin definition for buttons control 57#define sensorButton 0 58#define modeButton 5 59#define okButton 6 60 61// controls the pump motor speed using Pulse Width Modulation 62// duty cycle: between 0 (always off) and 255 (always on). 63// due to power supply limitation DutyCycleOn set to 160 64#define pumpPwmPin 3 65#define pumpPwmDutyCycleOn 255 66#define pumpPwmDutyCycleOff 0 67 68boolean serialOut = true; // use for printing lcd display output message to terminal for debug 69 70// create an instance of TFT library 71TFT TFTscreen = TFT(cs, dc, rst); 72 73// Data wire is plugged into port (pin) 2 on the Arduino 74#define ONE_WIRE_BUS 2 75// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs) 76OneWire oneWire(ONE_WIRE_BUS); 77// Pass our oneWire reference to Dallas Temperature. 78DallasTemperature sensors(&oneWire); 79int numberOfDevices; // Number of temperature devices found 80DeviceAddress tempDeviceAddress; // We'll use this variable to store a found device address 81 82// irrigation timeing 83unsigned long startTime = 0, stopTime = 0, elapseTime = 0; 84unsigned long timeZone = 10800 ; // 10800 utc +3 hours in israel +2 7200 85 86// watering Solenoid Valve stat 87boolean ValveOutput1Stat = false; 88 89// use for display clear old clock value 90char clockPrintout[20] = ""; 91 92struct Config { 93 unsigned long lastWateringDate; // manual Mode 94 unsigned long sensorLastWateringDate; // Sensor Mode 95 int moistureWateringThreshhold; // Sensor mode, moisture value threshhold 96 int lightWateringThreshhold; // Sensor mode, light value threshhold 97 unsigned long wateringTime; // Sensor mode, watering time and rest watering time in sec. 98 unsigned long schWateringTime; // schedule mode, long watering time in sec. 99 unsigned long schLastWateringDate; // schedule mode, Last Watering Date in sec. 100 unsigned long schWateringFrequency; // schedule mode, time between Watering in sec. 101 float flowRate; // L/s 102 float waterReservoirState; // waterReservoirSize - elapseTime * flowRate 103 byte defaultMode; // set the default working mode 104}; 105 106const char *configFileName = "/config.txt"; // <- SD library uses 8.3 filenames 107Config config; // <- global configuration object 108 109byte showSensorSelect = 0; 110byte modeSelect = 0; 111byte okSelect = 0; 112 113BLEService irrigationService("19B10000"); // BLE Irrigation Service 114 115// BLE Irrigation moisture light tempeture sensors level and ValveOutput1Stat Characteristic 116// custom 128-bit UUID, 117// remote clients will be able to get notifications if this characteristic changes 118BLEUnsignedCharCharacteristic moistureCharacteristic("19B10001", BLERead | BLENotify); 119BLEUnsignedCharCharacteristic lightCharacteristic("19B10002", BLERead | BLENotify); 120BLEFloatCharacteristic tempetureCharacteristic("19B10003", BLERead | BLENotify); 121BLECharCharacteristic ValveOutput1StatCharacteristic("19B10004", BLERead | BLENotify); 122 123 124void setup() { 125 // initialize serial communication at 9600 bits per second: 126 Serial.begin(9600); 127 while (!Serial) { 128 // wait for serial port to connect. Needed for native USB port only 129 delay (5000); 130 break; 131 } 132 133 startTime = now(); 134 stopTime = now(); 135 136 setupDisplay(); 137 setupSDcard(); 138 oneWireSetup(); 139 140 // declare the inputs and outputs: 141 pinMode(moistureSensorPin, INPUT); 142 pinMode(lightSensorPin, INPUT); 143 pinMode(Valve_Output1_PIN, OUTPUT); 144 pinMode(pumpPwmPin, OUTPUT); 145 146 // watering Off 147 digitalWrite(Valve_Output1_PIN, LOW); // stop the solenoid 148 analogWrite(pumpPwmPin, pumpPwmDutyCycleOff); // stop the pump 149 150 sdConfig(); 151 buttonSetup(); 152 bleSetup(); 153 154 modeSelect = config.defaultMode; 155} 156 157 158void loop() { 159 clockDisplay(getStrTime(now()), 0, 110, 2); 160 buttonMenu(); 161 bleConnect(); 162} 163 164 165// bluetooth le setup 166void bleSetup() { 167 // begin initialization 168 BLE.begin(); 169 170 // Set a local name for the BLE device 171 // This name will appear in advertising packets 172 // and can be used by remote devices to identify this BLE device 173 // The name can be changed but maybe be truncated based on space left in advertisement packet 174 BLE.setLocalName("Irrigation"); 175 // BLE.setDeviceName("IrrigationSys"); // GENUINO 101-E860 176 // BLE.setAppearance(384); 177 BLE.setAdvertisedService(irrigationService); // add the service UUID 178 179 // add the sensors level characteristic 180 irrigationService.addCharacteristic(moistureCharacteristic); 181 irrigationService.addCharacteristic(lightCharacteristic); 182 irrigationService.addCharacteristic(tempetureCharacteristic); 183 irrigationService.addCharacteristic(ValveOutput1StatCharacteristic); 184 185 BLE.addService(irrigationService); // Add the BLE irrigation service 186 moistureCharacteristic.setValue(getMoisture()); // initial value for this characteristic 187 lightCharacteristic.setValue(getLightValue()); // initial value for this characteristic 188 tempetureCharacteristic.setValue(getTemperatures()); // initial value for this characteristic 189 ValveOutput1StatCharacteristic.setValue(ValveOutput1Stat); // initial value for this characteristic 190 191 // Start advertising BLE. It will start continuously transmitting BLE 192 // advertising packets and will be visible to remote BLE central devices 193 // until it receives a new connection 194 195 // start advertising 196 BLE.advertise(); 197 198 Serial.println("Bluetooth device active, waiting for connections..."); 199} 200 201 202void bleConnect() { 203 // listen for BLE peripherals to connect: 204 BLEDevice central = BLE.central(); 205 206 // if a central is connected to peripheral: 207 if (central) { 208 Serial.print("Connected to central: "); 209 // print the central's MAC address: 210 Serial.println(central.address()); 211 212 // while the central is still connected to peripheral: 213 if (central.connected()) { 214 // set the moisture value for the characeristic: 215 moistureCharacteristic.setValue(getMoisture()); 216 lightCharacteristic.setValue(getLightValue()); 217 tempetureCharacteristic.setValue(getTemperatures()); 218 ValveOutput1StatCharacteristic.setValue(ValveOutput1Stat); 219 220 } else { 221 // when the central disconnects, print it out: 222 Serial.print(F("Disconnected from central: ")); 223 Serial.println(central.address()); 224 } 225 226 } 227} 228 229 230void clockDisplay(String PrintOut, int xPos, int yPos, int fontSize) { 231 // char array to print to the screen 232 char sensorPrintout[20]; 233 String sensorVal = PrintOut; 234 235 // erase the text you just wrote 236 TFTscreen.stroke(0, 0, 0); 237 TFTscreen.text(clockPrintout, xPos, yPos); 238 239 // convert the reading to a char array 240 sensorVal.toCharArray(sensorPrintout, 20); 241 242 // set the font color 243 TFTscreen.stroke(255, 255, 0); 244 // set the font size very large for the loop 245 TFTscreen.setTextSize(fontSize); 246 // print the sensor value 247 TFTscreen.text(sensorPrintout, xPos, yPos); 248 // save current time for clear display and write the new time 249 sensorVal.toCharArray(clockPrintout, 20); 250} 251 252 253void buttonMenu() { 254 bool cls = false; 255 bool clsTxt = false; 256 257 // get control button stat 258 bool sensorButtonVal = digitalRead(sensorButton); 259 bool modeButtonVal = digitalRead(modeButton); 260 bool okButtonVal = digitalRead(okButton); 261 262 int moistureSensorVal = getMoisture(); 263 int lightSensorVal = getLightValue(); 264 float tempC = getTemperatures(); 265 266 serialCommandInterface(); 267 268 // in force show water state for filling indicator 269 if (config.waterReservoirState <= 0) { 270 showSensorSelect = 3; 271 cls = false; 272 clsTxt = true; 273 } 274 275 if ((sensorButtonVal == LOW) ) { 276 showSensorSelect += 1; 277 cls = true; 278 clsTxt = true; 279 } 280 281 if ((modeButtonVal == LOW) ) { 282 modeSelect += 1; 283 cls = true; 284 clsTxt = true; 285 if (modeSelect > 3) modeSelect = 0; 286 } 287 288 if ((okButtonVal == LOW) ) { 289 okSelect += 1; 290 } 291 292 serialOut = false; 293 if (ValveOutput1Stat) { 294 sensorDisplay("Watering ON", 0, 55, 2, 2, 0, cls, false, serialOut); 295 } else { 296 sensorDisplay("Watering OFF", 0, 55, 2, 4, 0, cls, false, serialOut); 297 } 298 serialOut = true; 299 300 // switch info between sensors display 301 switch (showSensorSelect) { 302 case 0: 303 serialOut = false; 304 if (cls) { 305 sensorDisplay("humidity\ 306" + String(moistureSensorVal) + " %", 0, 0, 3, 4, 0, cls, true, serialOut); 307 cls = false; 308 } else if (moistureSensorVal == getMoisture()) { 309 sensorDisplay("humidity\ 310" + String(moistureSensorVal) + " %", 0, 0, 3, 4, 0, false, false, serialOut); 311 } else if (moistureSensorVal != getMoisture()) { 312 sensorDisplay("humidity\ 313" + String(moistureSensorVal) + " %", 0, 0, 3, 4, 0, true, true, serialOut); 314 } 315 serialOut = true; 316 break; 317 case 1: 318 serialOut = false; 319 if (cls) { 320 sensorDisplay("light\ 321" + String(lightSensorVal) + " %", 0, 0, 3, 5, 0, cls, true, serialOut); 322 cls = false; 323 } else if (lightSensorVal == getLightValue()) { 324 sensorDisplay("light\ 325" + String(lightSensorVal) + " %", 0, 0, 3, 5, 0, false, false, serialOut); 326 } else if (lightSensorVal != getLightValue()) { 327 sensorDisplay("light\ 328" + String(lightSensorVal) + " %", 0, 0, 3, 5, 0, true, false, serialOut); 329 } 330 serialOut = true; 331 break; 332 case 2: 333 serialOut = false; 334 if (cls) { 335 sensorDisplay("temp\ 336" + String(tempC), 0, 0, 3, 3, 0, cls, true, serialOut); 337 cls = false; 338 } else if (tempC == getTemperatures()) { 339 sensorDisplay("temp\ 340" + String(tempC), 0, 0, 3, 3, 0, false, false, serialOut); 341 } else if (tempC != getTemperatures()) { 342 sensorDisplay("temp\ 343" + String(tempC), 0, 0, 3, 3, 0, true, false, serialOut); 344 } 345 serialOut = true; 346 break; 347 case 3: 348 serialOut = false; 349 sensorDisplay("waterReservoirState\ 350" + String(config.waterReservoirState), 0, 0, 3, 6, 0, false, false, serialOut); 351 serialOut = true; 352 break; 353 default: 354 showSensorSelect = 0; 355 break; 356 } 357 358 // switch working mode 359 switch (modeSelect) { 360 case 0: // sensor mode and reservoir refilled init 361 serialOut = false; 362 sensorDisplay("Sensor Mode", 0, 80, 2, 4, 0, cls, clsTxt, serialOut); 363 serialOut = true; 364 cls = false; 365 sensorMode(); 366 tankRefilled(); //reservoir refilled init by ok button press 367 break; 368 case 1: 369 serialOut = false; 370 sensorDisplay("Schedule Mode", 0, 80, 2, 7, 0, cls, clsTxt, serialOut); 371 serialOut = true; 372 cls = false; 373 scheduleMode(); 374 tankRefilled(); //reservoir refilled init by ok button press 375 break; 376 case 2: 377 serialOut = false; 378 sensorDisplay("Manual Mode", 0, 80, 2, 7, 0, cls, clsTxt, serialOut); 379 serialOut = true; 380 cls = false; 381 manualMode(); 382 tankRefilled(); //reservoir refilled init by ok button press 383 break; 384 case 3: // setup mode 385 serialOut = false; 386 sensorDisplay("Setup Mode", 0, 80, 2, 7, 0, cls, clsTxt, serialOut); 387 serialOut = true; 388 cls = false; 389 if (okSelect) { // load config from sd json config.txt 390 sensorDisplay("Load config values from file", 0, 80, 2, 4, 1000, true, true, serialOut); 391 loadConfiguration(configFileName, config); 392 printConfigValues(); 393 // Dump Irrigation activity file to consol 394 Serial.println("Print Irrigation activity file..."); 395 printFile("datalog.csv"); 396 okSelect = 0; 397 } 398 break; 399 default: 400 modeSelect = config.defaultMode; 401 break; 402 } 403} 404 405 406// Evaluate the moisture sensor and light values and turn on valves as necessary 407void sensorMode() { 408 int moistureSensorVal = getMoisture(); 409 int lightSensorVal = getLightValue(); 410 411 // moistureSensorVal 100% fully dry, 0% fully wet 412 if ( (moistureSensorVal >= config.moistureWateringThreshhold) && 413 (lightSensorVal <= config.lightWateringThreshhold) && 414 (ValveOutput1Stat == false) && 415 ( (now() - config.sensorLastWateringDate) >= config.wateringTime) && 416 (config.waterReservoirState > 0) ) 417 { 418 wateringOn(); 419 okSelect = 0; 420 do { 421 elapseTime = now() - startTime; 422 moistureSensorVal = getMoisture(); 423 424 // read button state while watering for cancel 425 int okButtonVal = digitalRead(okButton); 426 if ((okButtonVal == LOW) ) { 427 okSelect += 1; 428 } 429 430 float WaterReservoirState = getWaterReservoirState( getWateringVolume(elapseTime) ); 431 432 if ( (moistureSensorVal <= config.moistureWateringThreshhold) 433 || (okSelect > 1) 434 || (WaterReservoirState <= 0) ) 435 { 436 okSelect = 0; 437 sensorDisplay("Watering canceled", 0, 80, 2, 2, 1000, true, true, serialOut); 438 break; 439 } 440 441 sensorDisplay("Sensor Mode", 0, 0, 1, 7, 0, false, false, serialOut); 442 sensorDisplay("Moisture Thld " + String(config.moistureWateringThreshhold), 0, 15, 1, 7, 0, false, false, serialOut); 443 sensorDisplay("Light Thld " + String(config.lightWateringThreshhold), 0, 30, 1, 7, 0, false, false, serialOut); 444 sensorDisplay("wateringTime " + String(config.wateringTime), 0, 45, 1, 7, 0, false, false, serialOut); 445 sensorDisplay("ElpsTime ", 0, 75, 2, 2, 0, false, false, serialOut); 446 sensorDisplay("% Dry is " + String(getMoisture()), 0, 95, 1, 4, 0, false, false, serialOut); 447 sensorDisplay(String(elapseTime) + " sec", 100, 75, 2, 2, 500, false, true, serialOut); 448 clockDisplay(getStrTime(now()), 0, 110, 2); 449 bleConnect(); 450 } while ( elapseTime <= config.wateringTime ); 451 wateringOff(); 452 config.sensorLastWateringDate = now(); 453 saveConfiguration(configFileName, config); 454 } 455} 456 457 458// watering for preset time every periodic preset frequency 459// schWateringTime, schWateringFrequency, schLastWateringDate saved to config file 460void scheduleMode() { 461 bool isRainy = rainIndicator(); 462 463 if ( (now() >= (config.schLastWateringDate + config.schWateringFrequency)) 464 && (ValveOutput1Stat == false) 465 && (config.waterReservoirState > 0) ) 466 { 467 okSelect = 0; 468 wateringOn(); 469 do { 470 elapseTime = now() - startTime; 471 isRainy = rainIndicator(); 472 473 int okButtonVal = digitalRead(okButton); 474 if ((okButtonVal == LOW) ) { 475 okSelect += 1; 476 } 477 478 float WaterReservoirState = getWaterReservoirState( getWateringVolume(elapseTime) ); 479 480 // cancel watering when rainy or ok button press or water empty 481 if ( (isRainy) || (okSelect > 1) || (WaterReservoirState <= 0) ) 482 { 483 okSelect = 0; 484 sensorDisplay("Watering canceled", 0, 80, 2, 2, 1000, true, true, serialOut); 485 break; 486 } 487 sensorDisplay("Schedule Mode", 0, 0, 1, 7, 0, false, false, serialOut); 488 sensorDisplay("LastWateringDate " + getStrTime(config.schLastWateringDate), 0, 15, 1, 7, 0, false, false, serialOut); 489 sensorDisplay("WateringFrequency " + String(config.schWateringFrequency), 0, 30, 1, 7, 0, false, false, serialOut); 490 sensorDisplay("wateringTime " + String(config.schWateringTime), 0, 45, 1, 7, 0, false, false, serialOut); 491 sensorDisplay("ElpsTime ", 0, 75, 2, 2, 0, false, false, serialOut); 492 sensorDisplay("% Dry is " + String(getMoisture()), 0, 95, 1, 4, 0, false, false, serialOut); 493 sensorDisplay(String(elapseTime) + " sec", 100, 75, 2, 2, 1000, false, true, serialOut); 494 clockDisplay(getStrTime(now()), 0, 110, 2); 495 bleConnect(); 496 } while ( elapseTime <= config.schWateringTime ); 497 wateringOff(); 498 config.schLastWateringDate = now(); 499 saveConfiguration(configFileName, config); 500 } 501} 502 503 504// watering for preset time long and returns to sensor mode 505void manualMode() { 506 bool isRainy = rainIndicator(); 507 508 if ( (ValveOutput1Stat == false) 509 && (okSelect > 1) 510 && (config.waterReservoirState > 0) ) 511 { 512 okSelect = 0; 513 wateringOn(); 514 do 515 { 516 elapseTime = now() - startTime; 517 518 int okButtonVal = digitalRead(okButton); 519 if ((okButtonVal == LOW) ) { 520 okSelect += 1; 521 } 522 523 float WaterReservoirState = getWaterReservoirState( getWateringVolume(elapseTime) ); 524 // stop watering on Ok button true or moisture Threshhold or Water Reservoir empty 525 if ( (isRainy) || (okSelect > 1) || (WaterReservoirState <= 0) ) 526 { 527 okSelect = 0; 528 sensorDisplay("Watering canceled", 0, 80, 2, 2, 1000, true, true, serialOut); 529 break; 530 } 531 532 // sensorVal, xPos, yPos, fontSize, fontColorVal, delayVal, cls, clsTxt, serialOut 533 sensorDisplay("Manual Mode", 0, 0, 1, 7, 0, false, false, serialOut); 534 // sensorDisplay("Watering ON", 0, 55, 2, 2, 0, true, false, serialOut); 535 sensorDisplay(String(WaterReservoirState) + " Liter remaining", 0, 75, 2, 2, 1000, false, true, serialOut); 536 sensorDisplay(String(elapseTime) + " sec elapsed", 0, 90, 2, 2, 1000, false, true, serialOut); 537 538 isRainy = rainIndicator(); 539 clockDisplay(getStrTime(now()), 0, 110, 2); 540 bleConnect(); 541 } while (elapseTime <= config.wateringTime); 542 wateringOff(); 543 config.lastWateringDate = now(); 544 saveConfiguration(configFileName, config); 545 modeSelect = config.defaultMode; // return to sensor mode 546 } 547} 548 549 550/* cli command 551 log -> print log file to terminal 552 log.del -> delete log file 553 cfg -> print config info to terminal 554 time.unixtime -> set time 555 moisture.% -> sets moisture Watering Threshhold 556*/ 557void serialCommandInterface() { 558 String command = "" ; // for incoming serial data 559 String param = ""; 560 561 // send data only when you receive data: 562 while (Serial.available() > 0) { 563 // read the incoming byte: 564 command = Serial.readStringUntil('\n'); 565 566 param = command.substring(command.indexOf('.') + 1); 567 command = command.substring(0, command.indexOf('.')); 568 // Serial.println(command); 569 // Serial.println(param); 570 571 if ( command.equals("log") ) { 572 if (param.equals("del")) { 573 delFile("datalog.csv"); 574 } 575 // Dump Irrigation activity file to consol 576 Serial.println("Print Irrigation activity file..."); 577 printFile("datalog.csv"); 578 } else if (command.equals("cfg")) { 579 Serial.println(command); 580 printConfigValues(); 581 } else if (command.equals("time")) { 582 cliSetTime(param); 583 } else if (command.equals("moisture")) { 584 cliSetMoistureTh(param); 585 } else { 586 Serial.println("Unknown command"); 587 } 588 } 589} 590 591 592void cliSetMoistureTh(String moistureThreshhold) { 593 594 if ( ! ((moistureThreshhold.equals("moisture")) 595 || (moistureThreshhold.equals("moisture."))) ) 596 { 597 config.moistureWateringThreshhold = moistureThreshhold.toInt(); 598 saveConfiguration(configFileName, config); 599 Serial.println("moisture Watering Threshhold is set"); 600 } 601 Serial.println("moisture is " + String(config.moistureWateringThreshhold) ); 602} 603 604 605// set system time by sending utc unix time number through serial 606// unix time url https://www.unixtimestamp.com/index.php 607void cliSetTime(String unixTimeStamp) { 608 unsigned long timeZone = 10800 ; // 10800 utc +3 hours in israel +2 7200 609 610 if ( ! (unixTimeStamp.equals("time")) ) { 611 setTime(unixTimeStamp.toInt() + timeZone); 612 serialOut = true; 613 sensorDisplay("time is set", 0, 80, 2, 1, 500, true, true, serialOut); 614 serialOut = false; 615 } 616 Serial.println(getStrTime(now())); 617} 618 619 620int getMoisture() { 621 int moistureSensorVal = analogRead(moistureSensorPin); 622 return map(moistureSensorVal, 0, 1023, 0, 100); 623} 624 625 626int getLightValue() { 627 int lightSensorVal = analogRead(lightSensorPin); 628 return map(lightSensorVal, 0, 1023, 0, 100); 629} 630 631 632float getTemperatures(void) { 633 float tempC; // Temperature 634 sensors.requestTemperatures(); // Send the command to get temperatures 635 /* 636 // Loop through each device, print out temperature data 637 for (int i = 0; i < numberOfDevices; i++) { 638 // Search the wire for address 639 if (sensors.getAddress(tempDeviceAddress, i)) { 640 // Output the device ID 641 Serial.print("Temperature for device: "); 642 Serial.println(i, DEC); 643 // Print the data 644 tempC = sensors.getTempC(tempDeviceAddress); 645 } 646 } 647 */ 648 tempC = sensors.getTempC(tempDeviceAddress); 649 return tempC; 650} 651 652 653String getStrTime(unsigned long unixTime) { 654 String timeStr, dateStr; 655 656 timeStr = print2digits(hour(unixTime)) + ":" + print2digits(minute(unixTime)) + ":" + print2digits(second(unixTime)); 657 dateStr = String(day(unixTime)) + "/" + String(month(unixTime)) + "/" + String(year(unixTime)); 658 String dateTimeStr = timeStr + " " + dateStr; 659 return dateTimeStr; 660} 661 662 663String print2digits(int number) { 664 String numStr; 665 if (number >= 0 && number < 10) { 666 numStr = "0" + String(number) ; 667 } 668 else { 669 numStr = String(number) ; 670 } 671 return numStr; 672} 673 674 675void writeDataToSDcard() { 676 // make a string for assembling the data to log: 677 String dataString = ""; 678 // read three sensors and append to the string: 679 dataString = getStrTime(now()) 680 + "," + String(getTemperatures()) + "" 681 + "," + String(getMoisture()) + "% moisture" 682 + "," + String(getLightValue()) + "% light" 683 + "," + getStrTime(startTime) 684 + "," + getStrTime(stopTime) 685 + "," + String(stopTime - startTime) + " sec" 686 + "," + String(modeSelect) + " mode"; 687 688 // open the file. note that only one file can be open at a time, 689 // so you have to close this one before opening another. 690 File dataFile = SD.open("datalog.csv", FILE_WRITE); 691 692 // if the file is available, write to it: 693 if (dataFile) { 694 dataFile.println(dataString); 695 dataFile.close(); 696 // print to the serial port too: 697 Serial.println(dataString); 698 } 699 else { // if the file isn't open, pop up an error: 700 Serial.println("error opening datalog.csv file !"); 701 setupSDcard(); 702 } 703} 704 705 706// sensorVal, xPos, yPos, fontSize, fontColorVal, delayVal, cls, clsTxt, serialOut 707// print text on display 708void sensorDisplay(String sensorVal, int xPos, int yPos, int fontSize, int fontColorVal, 709 int delayVal, bool cls, bool clsTxt, bool serialOut) { 710 // char array to print to the screen 711 char sensorPrintout[30]; 712 byte colorCode[8][3] = 713 { // (red, green, blue); 714 {0, 0, 0}, //Black 0 715 {0, 0, 255}, //Blue 1 716 {255, 0, 0}, //Red 2 717 {255, 0, 255}, //Magenta 3 718 {0, 255, 0}, //Green 4 719 {0, 255, 255}, //Cyan 5 720 {255, 255, 0}, //Yellow 6 721 {255, 255, 255} //White 7 722 }; 723 724 // clear the screen with a black background 725 if (cls) { 726 TFTscreen.background(0, 0, 0); 727 } 728 729 // convert the reading to a char array 730 sensorVal.toCharArray(sensorPrintout, 30); 731 732 // set the font color 733 TFTscreen.stroke(colorCode[fontColorVal][2], colorCode[fontColorVal][1], colorCode[fontColorVal][0]); 734 735 // set the font size very large for the loop 736 TFTscreen.setTextSize(fontSize); 737 738 // print the sensor value 739 TFTscreen.text(sensorPrintout, xPos, yPos); 740 if (serialOut) Serial.println(sensorPrintout); 741 742 // wait for a moment 743 delay(delayVal); 744 745 // erase the text you just wrote 746 if (clsTxt) { 747 TFTscreen.stroke(0, 0, 0); 748 TFTscreen.text(sensorPrintout, xPos, yPos); 749 } 750} 751 752 753void wateringOn() { 754 digitalWrite(Valve_Output1_PIN, HIGH); 755 analogWrite(pumpPwmPin, pumpPwmDutyCycleOn); // run the pump 756 ValveOutput1Stat = true; 757 startTime = now(); 758 if (ValveOutput1Stat) { 759 sensorDisplay("Watering ON", 0, 55, 2, 2, 0, true, false, serialOut); 760 } else { 761 sensorDisplay("Watering OFF", 0, 55, 2, 4, 0, true, false, serialOut); 762 } 763} 764 765 766void wateringOff() { 767 digitalWrite(Valve_Output1_PIN, LOW); // stop the solenoid 768 analogWrite(pumpPwmPin, pumpPwmDutyCycleOff); // stop the pump 769 ValveOutput1Stat = false; 770 stopTime = now(); 771 if (ValveOutput1Stat) { 772 sensorDisplay("Watering ON", 0, 55, 2, 2, 0, true, false, serialOut); 773 } else { 774 sensorDisplay("Watering OFF", 0, 55, 2, 4, 0, true, false, serialOut); 775 } 776 writeDataToSDcard(); 777 config.waterReservoirState = getWaterReservoirState( getWateringVolume(elapseTime) ); 778} 779 780 781/* 782 fluid flow rate = area of the pipe or channelvelocity of the liquid 783 Q = Av 784 Q = liquid flow rate (m3/s or L/s) liters per second 785 A = area of the pipe or channel (m2) area is A = r2 786 v = velocity of the liquid (m/s) 787*/ 788float getWateringVolume(unsigned long wateringElapseTime) { 789 float wateringVolume = 0; 790 wateringVolume = wateringElapseTime * config.flowRate; 791 return wateringVolume; 792} 793 794 795float getWaterReservoirState(float wateringVolume) { 796 float waterInReservoir = 0; 797 waterInReservoir = config.waterReservoirState - wateringVolume; 798 return waterInReservoir; 799} 800 801 802void setupDisplay() { 803 char printout[30]; 804 805 // Put this line at the beginning of every sketch that uses the GLCD: 806 TFTscreen.begin(); 807 // clear the screen with a black background 808 TFTscreen.background(0, 0, 0); 809 // write the static text to the screen 810 // set the font color to white 811 TFTscreen.stroke(255, 255, 255); 812 // set the font size 813 TFTscreen.setTextSize(2); 814 // clear screen 815 TFTscreen.fillScreen(0); 816 // write the text to the top left corner of the screen 817 String headLineStr = String( "Rami's\ 818 Irrigation\ 819 system\ 820"); 821 headLineStr.toCharArray(printout, 30); 822 // TFTscreen.text(printout, 0, 10); 823 // set the font size very large for the loop 824 TFTscreen.setTextSize(1); 825 sensorDisplay(headLineStr, 0, 0, 1, 7, 0, false, true, serialOut); 826} 827 828 829void setupSDcard() { 830 sensorDisplay("Initializing SD card...", 0, 0, 1, 7, 0, false, true, serialOut); 831 // see if the card is present and can be initialized: 832 if (!SD.begin(SDchipSelect)) { 833 sensorDisplay("Card failed, or not present", 0, 10, 1, 7, 0, false, true, serialOut); 834 // don't do anything more: 835 // while (1); 836 loadDefaultConfigValues(); 837 delay (5000); 838 839 } 840 else { 841 sensorDisplay("card initialized.", 0, 10, 1, 7, 0, false, true, serialOut); 842 } 843} 844 845 846// tempeture setup 847// device 0 with address: 28FFAFD3741604CB 848void oneWireSetup(void) { 849 // Start up the library 850 sensors.begin(); 851 // Grab a count of devices on the wire 852 numberOfDevices = sensors.getDeviceCount(); 853 // locate devices on the bus 854 Serial.print("Locating tempeture sensor devices..."); 855 Serial.print("Found "); 856 Serial.print(numberOfDevices, DEC); 857 Serial.println(" devices."); 858 // Loop through each device, print out address 859 for (int i = 0; i < numberOfDevices; i++) { 860 // Search the wire for address 861 if (sensors.getAddress(tempDeviceAddress, i)) { 862 Serial.print("Found device "); 863 Serial.print(i, DEC); 864 Serial.print(" with address: "); 865 printAddress(tempDeviceAddress); 866 Serial.println(); 867 } else { 868 Serial.print("Found ghost device at "); 869 Serial.print(i, DEC); 870 Serial.print(" but could not detect address. Check power and cabling"); 871 } 872 } 873} 874 875 876// function to print a device address 877void printAddress(DeviceAddress deviceAddress) { 878 for (uint8_t i = 0; i < 8; i++) { 879 if (deviceAddress[i] < 16) Serial.print("0"); 880 Serial.print(deviceAddress[i], HEX); 881 } 882} 883 884 885// json file config.txt format 886void sdConfig() { 887 // Should load default config if run for the first time 888 sensorDisplay("Loading configuration...", 0, 55, 2, 2, 0, true, true, serialOut); 889 loadConfiguration(configFileName, config); 890 // Dump config file 891 sensorDisplay("Print config file...", 0, 55, 2, 2, 0, true, true, serialOut); 892 printFile(configFileName); 893 printConfigValues(); 894} 895 896 897// Loads the configuration from a file 898void loadConfiguration(const char *filename, Config & config) { 899 // Open file for reading 900 File file = SD.open(filename); 901 if (!file) { 902 sensorDisplay("reading file fail, check sd card !", 0, 55, 2, 2, 0, true, true, serialOut); 903 Serial.println(filename); 904 setupSDcard(); 905 return; 906 } 907 908 // Allocate a temporary JsonDocument 909 // Don't forget to change the capacity to match your requirements. 910 // Use arduinojson.org/v6/assistant to compute the capacity. 911 StaticJsonDocument<512> doc; 912 // Deserialize the JSON document 913 DeserializationError error = deserializeJson(doc, file); 914 if (error) { 915 sensorDisplay("fail,goto default!", 0, 55, 2, 2, 0, true, true, serialOut); 916 Serial.println(F("Failed to read file, using default configuration")); 917 Serial.println(error.c_str()); 918 // Load default config values 919 loadDefaultConfigValues(); 920 saveConfiguration(configFileName, config); 921 } else { 922 // Copy values from the JsonDocument to the Config 923 config.lastWateringDate = doc["lastWateringDate"]; 924 config.sensorLastWateringDate = doc["sensorLastWateringDate"]; 925 config.moistureWateringThreshhold = doc["moistureWateringThreshhold"]; 926 config.lightWateringThreshhold = doc["lightWateringThreshhold"]; 927 config.wateringTime = doc["wateringTime"]; //sec 928 config.schWateringTime = doc["schWateringTime"]; 929 config.schWateringFrequency = doc["schWateringFrequency"]; // 1 day 930 config.schLastWateringDate = doc["schLastWateringDate"]; 931 config.waterReservoirState = doc["waterReservoirState"]; //liters 932 config.flowRate = doc["flowRate"]; // liters/sec 1/3600 240 L/H 1/120 0.01 933 config.defaultMode = doc["defaultMode"]; 934 935 sensorDisplay("Config load complete", 0, 55, 2, 2, 0, true, true, serialOut); 936 } 937 // Close the file (Curiously, File's destructor doesn't close the file) 938 file.close(); 939} 940 941 942// Saves the configuration to a file 943void saveConfiguration(const char *filename, const Config & config) { 944 // Delete existing file, otherwise the configuration is appended to the file 945 SD.remove(filename); 946 947 // Open file for writing 948 File file = SD.open(filename, FILE_WRITE); 949 if (!file) { 950 Serial.println(F("Failed to create file Config.txt...Try again")); 951 setupSDcard(); 952 return; 953 } 954 // Allocate a temporary JsonDocument 955 // Don't forget to change the capacity to match your requirements. 956 // Use arduinojson.org/assistant to compute the capacity. 957 StaticJsonDocument<512> doc; 958 959 // Set the values in the document 960 doc["lastWateringDate"] = config.lastWateringDate; 961 doc["sensorLastWateringDate"] = config.sensorLastWateringDate; 962 doc["moistureWateringThreshhold"] = config.moistureWateringThreshhold; 963 doc["lightWateringThreshhold"] = config.lightWateringThreshhold; 964 doc["wateringTime"] = config.wateringTime; 965 966 doc["schWateringTime"] = config.schWateringTime; 967 doc["schWateringFrequency"] = config.schWateringFrequency; 968 doc["schLastWateringDate"] = config.schLastWateringDate; 969 970 doc["waterReservoirState"] = config.waterReservoirState; 971 doc["flowRate"] = config.flowRate; 972 doc["defaultMode"] = config.defaultMode; 973 974 // Serialize JSON to file 975 if (serializeJson(doc, file) == 0) { 976 Serial.println(F("Failed to write to file")); 977 } 978 // Close the file 979 file.close(); 980} 981 982// DEL file name 983void delFile(const char *filename) { 984 // Check to see if the file exists: 985 Serial.println(filename); 986 if (SD.exists(filename)) { 987 Serial.println(" Exists."); 988 // delete the file: 989 Serial.println(" Removing..."); 990 SD.remove(filename); 991 } else { 992 Serial.println("Doesn't exist."); 993 } 994} 995 996 997// Prints the content of a file to the Serial 998void printFile(const char *filename) { 999 1000 if (SD.exists(filename)) { 1001 // Open file for reading 1002 File file = SD.open(filename); 1003 if (!file) { 1004 Serial.println(F("Failed to read file")); 1005 Serial.println(F(filename)); 1006 Serial.println(F("Try again...")); 1007 setupSDcard(); 1008 return; 1009 } 1010 // Extract each characters by one by one 1011 while (file.available()) { 1012 Serial.print((char)file.read()); 1013 } 1014 Serial.println(); 1015 // Close the file 1016 file.close(); 1017 } else { 1018 Serial.println(F(filename)); 1019 Serial.println(" Doesn't exist."); 1020 } 1021} 1022 1023 1024void buttonSetup() { 1025 //configure pin 3 5 6 as an input and enable the internal pull-up resistor 1026 pinMode(sensorButton, INPUT_PULLUP); 1027 pinMode(modeButton, INPUT_PULLUP); 1028 pinMode(okButton, INPUT_PULLUP); 1029} 1030 1031 1032void loadDefaultConfigValues() { 1033 // load default config values 1034 config.moistureWateringThreshhold = 25; // 100% fully dry , 0% fully wet 1035 config.lightWateringThreshhold = 100; // 100% fully light, 0% fully dark 1036 config.wateringTime = 60 ; // manual and sensor mode Duration of watering in seconds 1037 config.lastWateringDate = now() + timeZone; // manual mode date of last time watering 1038 config.sensorLastWateringDate = now() + timeZone; // sensor mode date of last time watering 1039 // sch. mode 1040 config.schLastWateringDate = now() + timeZone; // date of last time watering 1041 config.schWateringTime = 180; // Duration of watering in seconds 1042 config.schWateringFrequency = 86400; // Watering frequency in seconds, day is 86400 sec 1043 config.waterReservoirState = 3.3; // 3.70 liters 1044 config.flowRate = 0.01; // liters/sec 1/3600 0.016666667 1045 config.defaultMode = 1; // Sensor Mode 0 ,Schedule Mode 1 ,Manual Mode 2 1046 sensorDisplay("Load complete Default Values !", 0, 55, 2, 2, 0, true, true, serialOut); 1047} 1048 1049 1050// logic in case of water reservoir refilled to the full 1051void tankRefilled() { 1052 if (okSelect && showSensorSelect == 3) { 1053 config.waterReservoirState = 3.3; 1054 saveConfiguration(configFileName, config); 1055 sensorDisplay("Reservoir refilled", 0, 80, 2, 4, 1000, true, true, serialOut); 1056 okSelect = 0; 1057 } 1058} 1059 1060 1061void printConfigValues() { 1062 1063 Serial.println("=====Print Loaded Config Values====="); 1064 Serial.print("lastWateringDate "); 1065 Serial.println( getStrTime(config.lastWateringDate) ); 1066 Serial.print("sensorLastWateringDate "); 1067 Serial.println( getStrTime(config.sensorLastWateringDate) ); 1068 Serial.print("moistureWateringThreshhold "); 1069 Serial.println(config.moistureWateringThreshhold); 1070 Serial.print("lightWateringThreshhold "); 1071 Serial.println(config.lightWateringThreshhold); 1072 Serial.print("wateringTime "); 1073 Serial.println(config.wateringTime); 1074 Serial.print("schWateringTime "); 1075 Serial.println(config.schWateringTime); 1076 Serial.print("schWateringFrequency "); 1077 Serial.println(config.schWateringFrequency); 1078 Serial.print("schLastWateringDate "); 1079 Serial.println( getStrTime(config.schLastWateringDate) ); 1080 Serial.print("waterReservoirState "); 1081 Serial.println(config.waterReservoirState); 1082 Serial.print("flowRate "); 1083 Serial.println(config.flowRate); 1084 Serial.print("defaultMode "); 1085 Serial.println(config.defaultMode); 1086 1087 Serial.println(); 1088} 1089 1090 1091// uses moisture Sensor for indicat rain (return true) to alow stop watering. 1092// moistureSensorVal 100% fully dry, 0% fully wet 1093bool rainIndicator() { 1094 int moistureSensorVal; 1095 moistureSensorVal = getMoisture(); 1096 if (moistureSensorVal >= 20) return false; 1097 return true; 1098} 1099
Downloadable files
irrigationschematic_schem_VWoRF2Aysz.png
irrigationschematic_schem_VWoRF2Aysz.png
Irrigation system
code and schematic
https://github.com/ramiev/IrrigationSystem.git
irrigationschematic_schem_VWoRF2Aysz.png
irrigationschematic_schem_VWoRF2Aysz.png
Comments
Only logged in users can leave comments
Rami1
0 Followers
•0 Projects
Table of contents
Intro
5
0