Simple irrigation controller



  • Description
    This project born from a necessity of water my domestic vegetable garden. Lettuces needs water all day and many times I forgot or don’t have time. There are other projects for irrigation but I have special requirements, it’s just one valve and valves that are sold in my country are AC24V for commercial controllers.
    So I build a controller to add to my existing Mysensors/Domoticz network that can handle an AC24V with 12V to 3V volt DC . +/-3 Volts it’s how power this AC24V volts solenoids because AC24V transformers are difficult to find and expensive for what they are(ferromagnetic). And once solenoids(coils) warms up a lot especially with DC,with 3 volt they run cold and its the minimum that my valve requires to stay open.

    How it works?
    Watering can be set on Arduino, 2 times per day ,morning and at evening. Or even once per day.
    Or can be added timers on gateway (my case Domoticz) and everything stays remotely. Personally I prefer have it hard coded on Arduino in case of transmission fail.
    I add a switch (one per valve) to turn it on every time I want and it automatically shuts down on timer that it’s set on code ,in “VALVE_TIME”. 1 hour by default.
    So there this timeout work in any of the timers(switch,gateway or internal timer).

    On code ,I set to “225”(100% or DC12v) on mosfet (IRLZ44N) during 400ms to kick the solenoid to open and then is set to “90” the rest of time to have around 3V on valve terminals. The entire project it’s powered with a standard electronic DC12V/2A transformer that powers the Arduino and the water valve.

    There are 2 leds. One "Valve Power On" and other is TX/RX,note that blink time was slowed down for better understand when is communicating or its just retrying in loop and can't reach the gateway (for example). I have really good result with RFM69H(868mhz) communications. My garden its 40m/50m of my house or GW an never realize that were lost communications.

    What I used:
    Arduino (any 328P), I used pro mini 3.3v because the RFM69
    RFM69H
    LM2596 Voltage step down 12v→3.3V (or equivalent)
    IRLZ44N or any logic level mosfet that work on 3.3V(one per valve that you use)
    x2 leds
    x2 screw terminal (2 wires)
    Push Switch (Normally open)
    Resistors x2 - 10K and x2 – 220ohm
    Protoboard (that green ones from ebay are awesome)
    wire…

    Some thoughts : On my prototypes, I rarely make a dedicated pcb, I use thin ,wire to bridge components on protoboards. They are easy to build and easy to repair or remake in case of some issue. Never had an unexpected shot-circuit. And when my board are outdoor ,I use nail polish or transparent spray paint to cover the entire board. that makes an water prof board. And believe me even ip67 outdoor cases sometimes let water get in.
    This is an example of wiring , of course in this our project we have many less wires :example

    Schematic
    0_1570911079939_f35f0b64-983b-4015-8fcd-81dc770eacf2-image.png

    Note: each extra valve(Zone) needs an extra led, switch and mosfet.

    Don’t let your garden dry! 🙂

    Code

    // Set blinking period (in milliseconds)
    #define MY_DEFAULT_LED_BLINK_PERIOD 500
    #define MY_WITH_LEDS_BLINKING_INVERSE
    //#define MY_DEFAULT_ERR_LED_PIN 17
    #define MY_DEFAULT_TX_LED_PIN 17
    #define MY_DEFAULT_RX_LED_PIN 17
    
    //#define MY_DEBUG
    #define MY_RADIO_RFM69
    //#define MY_REPEATER_FEATURE
    
    #include <TimeLib.h>
    #include <SPI.h>
    #include <OneWire.h>
    #include <DallasTemperature.h>
    #include <MySensors.h>
    
    
    #define ONE_WIRE_BUS 6
    OneWire oneWire(ONE_WIRE_BUS);
    DallasTemperature sensors(&oneWire);
    //#define CHILD_ID_MOISTURE 4
    #define CHILD_ID_TEMP 21
    #define CHILD_ID_VALV1 10
    //#define CHILD_ID_VALV2 11
    
    
    #define RELAY_PIN  3  // Arduino Digital I/O pin number for relay  VALV 1 
    #define RELAY_PIN2  5  // Arduino Digital I/O pin number for relay VALV 2
    #define BUTTON_PIN  4  // Arduino Digital I/O pin number for button 
    #define LEDR1   16  // LED A2 pin
    #define LEDR2  15// LED A1 pin
    //#define LEDERRO 17  // LED A3  pin
    
    
    
    #define VALVE_TIME 3600000UL    //selenoid 1 goes off after () time  (7200000UL)-2HOUR
    #define readtime 1800000UL  //time between read TEMPERATURE (3600000UL) - 1HOUR
    
    //xxxxxxxxxxxxxxxxxxxxxxxxxxxxx |SET TIME HERE|     - valve1-  xxxxxxxxxxxxxxxxxxxxxxxx |
    //TIME1
    const int H1 = 17; //HOURS START PROGRAM     //time to start  selenoid1                 |
    const int M1 = 00; //MINUTES START PROGRAM                                              |
    //TIME2
    const int H2 = 8; //HOURS START PROGRAM     //time to start  selenoid1                 |
    const int M2 = 00; //MINUTES START PROGRAM
    //----------------------------------------valve2--------------------------------------- |
    
    unsigned long startMillis = 0;
    unsigned long startMillisA = 0;
    
    int reading;// the current reading from the input pin
    bool RH = false;
    int previous = LOW;
    int timer = false;
    bool timeReceived = false;
    unsigned long  lastRequest = 0;
    
    MyMessage msg1(CHILD_ID_TEMP, V_TEMP);
    MyMessage msg2(CHILD_ID_VALV1, V_LIGHT);
    
    bool state;
    
    
    void before()
    {
      // Startup up the OneWire library
      sensors.begin();  //DS18B20 LIBRARY START
    }
    
    void setup()
    {
      //request time from gw
      requestTime(receiveTime);
    
      // Setup the button
      pinMode(BUTTON_PIN, INPUT);
      pinMode(RELAY_PIN, OUTPUT);
      pinMode(RELAY_PIN2, OUTPUT);
    
      pinMode(LEDR1, OUTPUT);
      pinMode(LEDR2, OUTPUT);
      sensors.begin();  //DS18B20 LIBRARY START
    
    
      // Make sure relays are off when starting up
      digitalWrite(RELAY_PIN, LOW);
    
    }
    
    
    
    void presentation()
    {
      sendSketchInfo("irrigation_temp_soilMoisture", "2.0");
      present(CHILD_ID_TEMP, S_TEMP);
      present(CHILD_ID_VALV1, S_LIGHT);
    }
    void receiveTime(unsigned long time)
    {
      // Ok, set incoming time
      setTime(time);
      timeReceived = true;
    
      Serial.print("Time now is: ");
    
      Serial.print(hour());
      Serial.print(":");
      Serial.print(minute());
      Serial.print(":");
      Serial.print(second());
    }
    //#################################################################################################
    void VALV1_ON()
    {
      analogWrite(RELAY_PIN, 255);
      delay(400);
      analogWrite(RELAY_PIN, 90);
      digitalWrite(LEDR1, HIGH);
      send(msg2.set(true), false);
    
    }
    
    void VALV1_OFF()
    {
      analogWrite(RELAY_PIN, LOW);
      digitalWrite(LEDR1, LOW);
      send(msg2.set(false), false);
    }
    //#########################################################################################################3
    // ✓ ORDER RECEIVED FROM GW  # 
    
    void receive(const MyMessage &message) {
      // We only expect one type of message from controller. But we better check anyway.
      if (message.isAck()) {
        // Serial.println("This is an ack from gateway");
      }
    
      if (message.type == V_LIGHT) {
        // Change relay state
        state = message.getBool();
    
        if (state == 1)
        {
          VALV1_ON();
        }
    
        else if (state == 0)
        {
          VALV1_OFF();
        }
    
      }
    }
    void loop()                 //loop   
    {
    
    
      unsigned long nows = millis();
      // If no time has been received yet, request it every 10 second from controller
      // When time has been received, request update every 12h
      if ((!timeReceived && (nows - lastRequest) > (10UL * 1000UL))
          || (timeReceived && (nows - lastRequest) > (43200000UL)))
      {
        // Request time from controller.
        //   Serial.println("requesting time");
        requestTime(receiveTime);
        lastRequest = nows;
      }
    
      
      //toogle  switch----------selenoid 1-------------------------------
    
      reading = digitalRead(BUTTON_PIN);
    
    
      if (reading == HIGH && RH == false)
      {
        VALV1_ON();
        RH = true;
        timer = true;
        delay(400);
      }
      else if (reading == HIGH && RH == true)
      {
        VALV1_OFF();
        RH = false;
        timer = false;
        delay(400);
      }
    
      // ✓ time out 
      unsigned long nowMillis = millis();
    
      if ((timer == true) && (nowMillis - startMillis >= VALVE_TIME))
      {
        startMillis =  nowMillis ;
        VALV1_OFF();
        timer = false;
    
      }
    
      //✓ ON by time 
      if ((hour() == H1 && minute() == M1) || (hour() == H2 && minute() == M2)  )
      {
        VALV1_ON();
        timer = true;
      }
    
    
    
    
      //✓ time to send temperature ? 
      float temperature = sensors.getTempCByIndex(0);
    
      unsigned long nowMillisA = millis();
      if (nowMillisA - startMillisA >= readtime)
      {
        //✓ read temperature  sensors 
        sensors.requestTemperatures();
        send(msg1.set(temperature, 1)); //send  temp to gw
        startMillisA =  nowMillisA ;  //reset time
      }
    }
    

    Todays Domoticz log from this sensors:

    0_1570911754580_26158c40-f747-4cb4-8a58-c89f2a97cd17-image.png


 

370
Online

8.9k
Users

9.6k
Topics

100.8k
Posts