Multiple Relay Irrigation Controller Arduino

thanks!

I added the pushbutton activator and a status LED. I have not tried to load onto a smaller Arduino yet, I tested on my UNO and it works. The code got flabby so I’ll have a run at that in V2.0 later on, after I get feedback and do more testing.

Let me know if you find any bugs.

I am aware that the status

gw.sendVariable( valveNumber, V_LIGHT, 0)

has a challenge getting to the VERA, but rest assured if they don’t indicate properly, it is functioning OK. I’ll look into getting that working really well, too. I have to check with the MySensors team on that.

added: You may need a capacitor and a resistor for the pushbutton. Should be a snap to get that wired in. diagram attached.

/*
Arduino Sprinkler Controller
 
 June 3, 2014
 
 Version 1.1    added F() macro to Serial.prints, storing text constants to flash memory
                     added pushbutton activation on interrupt 1 (pin 3) to cycle state 1
                     added LED status indicator
 Version 1.0     
 
 Arduino Multi-Zone Sprinkler Control
 
 Utilizing your Vera home automation controller and the MySensors.org gateway you can
 control up to an eight zone irrigation system with only three digital pins.  This sketch 
 will create n+1 devices on your Vera controller
 
 This sketch features the following:
 
 * Allows you to cycle through All zones or individual zone control.  
 * Use the (n+1)th controller to activate each zone in numeric sequence (zero to n) using 
   Variable1 as the "ON" time in minutes in each of the vera devices created.
 * Use the individual zone controller to activate a single zone.  This feature uses 
   Variable2 as the "ON" time for each individual device/zone.
 * Connect according to pinout below and uses an 74HC595 (or equiv) Shift Register as to 
   allow the MySensors standard radio configuration and still leave available digital pins
 * Compiles to ~12,000 Bytes, so will run on any Arduino
 * Turning on any zone will stop the current process and begin that particular process.
 * Turning off any zone will stop the current process and turn off all zones.
 * Sketch must collect your times so it takes several minutes to startup.
 * If you change your desired time intervals for your zones, simply restart your arduino 
   and it will self update
 * Pushbutton activation
 * LED status indicator
 
 by Jim (BulldogLowell@gmail.com) for free public use
 
 */
#include <Relay.h>
#include <SPI.h>
#include <EEPROM.h> 
#include <RF24.h>
//
#define NUMBER_OF_VALVES 8 // Change this to set you valve count.
#define RESET_TIME 5000    // Change this (in milliseconds) for the time you need your valves to change state
unsigned long valveTime [NUMBER_OF_VALVES + 1];
unsigned long valveSoloTime [NUMBER_OF_VALVES + 1];
byte valveByte [8] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 };  // Storing eight bytes
int valveNumber;
byte state = 0;
unsigned long startMillis;
const unsigned long ledInterval = 100;
const unsigned long slowLedInterval = 1250;
unsigned long ledTimer;
unsigned long slowLedTimer;
//
int latchPin = 8;
int clockPin = 4;
int dataPin  = 7;
int pin = 3;//interrupt 1
int ledPin = 5; // LED status blinks fast while changing a valve; steady during valve open or initialization; and slow blink when in stand-by
boolean buttonPushed = false;
// 
Sensor gw;
//
void setup() 
{ 
  Serial.begin(115200);
  gw.begin();
  //
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(pin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  attachInterrupt(1, PushButton, CHANGE);
  //
  digitalWrite (ledPin, HIGH);
  gw.sendSketchInfo("Sprinkler", "1.1");
  //
  for (int i=0; i<NUMBER_OF_VALVES + 1; i++) // Register all valves to gw (they will be created as child devices)
  {
    gw.sendSensorPresentation(i, S_LIGHT);
  }
  Serial.println(F("Sensor Presentation Complete"));
  //
  updateRelays(0x00);
  Serial.println(F("All Valves OFF"));
  //
  for (int i = 0; i < NUMBER_OF_VALVES + 1; i++)
  {
    gw.sendVariable( i, V_LIGHT, 0); //Display each Valve OFF
    valveTime [i] = atol(gw.getStatus( i, V_VAR1));// Get each Valve Cycle time
    valveSoloTime [i] = atol(gw.getStatus( i, V_VAR2));// Get each Valve Solo time
    Serial.print(F("Watering times collected from device: ")); 
    Serial.println(i);
  }
  for (int i = 0; i < NUMBER_OF_VALVES; i++)
  {
    Serial.print(F("Valve ")); 
    Serial.print(i); 
    Serial.print(F(" cycle time=")); 
    Serial.println(valveTime[i]);
    Serial.print(F("Valve ")); 
    Serial.print(i); 
    Serial.print(F(" solo  time=")); 
    Serial.println(valveSoloTime[i]);
  } 
  digitalWrite (ledPin, LOW);
  Serial.println(F("READY"));
}
//
void loop()
{
  if (gw.messageAvailable()) 
  {
    message_s message = gw.getMessage();
    setValveStatus(message);
  }
  if (buttonPushed)
  {
    state = 1;
    valveNumber = 0;
    gw.sendVariable( valveNumber, V_LIGHT, 1);
    gw.sendVariable( NUMBER_OF_VALVES, V_LIGHT,1);
    startMillis = millis();
    buttonPushed = false; 
    Serial.println(F("Cycling through ALL Valves"));
    Serial.print(F("state = ")); 
    Serial.println(state);     
  }

  if (state == 0) 
  {
    unsigned long nowMillis=millis();
    if ( (nowMillis - slowLedTimer) >= slowLedInterval)
    {
      slowToggleLED ();
    }
    updateRelays(0x00);
  }//End of state 0
  if (state == 1) //Cycle throug all Valves
  { 
    unsigned long nowMillis = millis();
    if (nowMillis - startMillis < RESET_TIME)
    {
      if ( (nowMillis - ledTimer) >= ledInterval)
      {
        toggleLED ();
      }
      updateRelays(0x00);
    }
    else if (nowMillis - startMillis < (valveTime[valveNumber] * 60000UL))
    {
      digitalWrite (ledPin, HIGH);
      updateRelays(valveByte [valveNumber]);
    }
    else if (nowMillis - startMillis > (valveTime [valveNumber]  * 60000UL))
    {
      updateRelays(0x00);
      startMillis = millis();
      gw.sendVariable( valveNumber, V_LIGHT, 0);
      valveNumber++;
      gw.sendVariable( valveNumber, V_LIGHT, 1);
      if (valveNumber > NUMBER_OF_VALVES) 
      {
        state = 0;
        digitalWrite (ledPin, LOW);
        Serial.print(F("State = ")); 
        Serial.println(state);
        gw.sendVariable( NUMBER_OF_VALVES + 1, V_LIGHT, 0);
      }
    }
  }//End of State 1
  //
  if (state == 2)// Run single valve
  {
    unsigned long nowMillis = millis();
    if (nowMillis - startMillis < RESET_TIME)
    {
      if ( (nowMillis - ledTimer) >= ledInterval)
      {
        toggleLED ();
      }
      updateRelays(0x00);
    }
    else if (nowMillis - startMillis < (valveSoloTime [valveNumber] * 60000UL))
    {
      digitalWrite (ledPin, HIGH);
      updateRelays(valveByte [valveNumber]);
    }
    else if (nowMillis - startMillis > (valveSoloTime [valveNumber] * 60000UL))
    {
      updateRelays(0x00);
      ;
      state = 0;
      digitalWrite (ledPin, LOW);
      Serial.print(F("State = ")); 
      Serial.println(state);
      gw.sendVariable( valveNumber, V_LIGHT, 0);
    }
  }//End of State 2
}//End of loop ()
//
void setValveStatus(message_s message) 
{
  if (message.header.messageType==M_SET_VARIABLE && message.header.type==V_LIGHT) 
  {
    valveNumber = message.header.childId;
    int incomingRelayStatus = atoi(message.data);
    if (incomingRelayStatus != 1)
    {
      state = 0;
      Serial.println(F("All Valves Off"));
      Serial.print(F("state = ")); 
      Serial.println(state);
    }
    else
    { 
      if (valveNumber < NUMBER_OF_VALVES)
      {
        state = 2;
        startMillis = millis();
        Serial.print(F("Cycling Valve #: ")); 
        Serial.println(valveNumber);
        Serial.print(F("state = ")); 
        Serial.println(state);
      }
      else 
      {
        state = 1;
        valveNumber = 0;
        gw.sendVariable( valveNumber, V_LIGHT, 1);
        startMillis = millis();
        Serial.println(F("Cycling through ALL Valves"));
        Serial.print(F("state = ")); 
        Serial.println(state);
      }
    }
  }
}
//
void updateRelays(byte value)
{
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, LSBFIRST, value); 
  digitalWrite(latchPin, HIGH);
}
//
void PushButton(){ //interrupt with debounce
  static unsigned long last_interrupt_time = 0;
  unsigned long interrupt_time = millis();
  if (interrupt_time - last_interrupt_time > 200)
  {
    Serial.println(F("interrupt"));
    buttonPushed = true;
  }
  last_interrupt_time = interrupt_time;
}
//
void toggleLED ()
{
  if (digitalRead (ledPin) == LOW)
    digitalWrite (ledPin, HIGH);
  else
    digitalWrite (ledPin, LOW);
  ledTimer = millis ();  
}
//
void slowToggleLED ()
{
  if (digitalRead (ledPin) == LOW)
    digitalWrite (ledPin, HIGH);
  else
    digitalWrite (ledPin, LOW);
  slowLedTimer = millis ();  
}

Thanks. I ordered the extra parts yesterday and should receive next week. I will update once I have it together.

So I received my parts and put everything together. I am not sure if it’s because I bought a different shift register but when I plug everything in all my relays turn on and won’t turn off. I used the sketch from mysensors that you provided as well. Changing the toggles in the Vera UI has no affect either. What things could I look at here to troubleshoot.

please double check the wiring for the Shift Register and post which one you used. I’ll take a look.

I can write a quick debug for the Shift Register for you if you tell me the three pins you are using and what they are assigned to. latch pin, data pin and clock pin

Sorry to see you are struggling here. it can be frustrating, I know.

EDIT: I forgot you told me already… apologies for that!

let me know for sure you wired it correctly. It is essentially the same register, different manufacturer.

Once you verified your wiring, try this sketch.

You should hear the relays click sequentially and quickly left to right, and right to left (knight rider example).

increase the delay if you need, or use 8 LEDs and be sure.

int latchPin = 8;
int clockPin = 4;
int dataPin  = 7;

const byte Leds [8] = { 0x01, 0x02, 0x04 , 0x08, 0x10, 0x20, 0x40, 0x80};

void setup()
{
  Serial.begin(115200);
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
}

void loop()
{
  for (int i=0; i<8; i++ )
  {
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, LSBFIRST, Leds[i]);   
    digitalWrite(latchPin, HIGH);
    delay(100);
  }
  for (int i=0; i<8; i++ )
  {
    digitalWrite(latchPin, LOW);
    shiftOut(dataPin, clockPin, LSBFIRST, Leds[ 7-i ]);   
    digitalWrite(latchPin, HIGH);
    delay(100);
  }
}

if this works, the sketch should work too.

if not, let me know…

So I have st_cp on pin 8, ds on pin 7 and sh_cp on pin 4. Trying your sketch now.

Just tried your sketch and it did exactly as you said it would (pretty cool looking after a couple drinks :)). So I am even more confused now as to why the other sketch isn’t working. I guess at least i know my wiring is working (and soldering as I had a surprise at the mail when I saw the shift register was not put together).

Can you run the serial monitor and let me know how the sketch reports as it progresses?

The new sketch you gave me doesn’t write anything for me on the serial monitor. The other sketch shows this:

Sensor Presentation Complete
All Valves OFF

But all the relays are on and don’t do anything when I toggle them in vera. But I do see in the serial monitor when I toggle that it does send a command:

Watering times collected from device: 0

Now one thing about your sketch where it goes back and forth, all the relays are on and it toggles them off, not sure if it should’ve been the other way around.

So when you turn on the vera ‘light’ button the serial monitor shows that vera sent the message to turn on the valves, right?

Sent from my iPhone using Tapatalk

Correct, but no change at all on the relays, they all just remain on.

Did you enter values in Variable1 and Variable2 on all devices? I don’t think they will come on at all if that value is zero. Update the values and restart Lua and refresh browser. Then, push reset on your arduino and turn on serial monitor. Verify that the values got into your arduino. It should report all your entries.

Sent from my iPhone using Tapatalk

Thought the same thing so I put 5 in each. No change.

Does the arduino report the values when you restart it with the serial monitor?

This is what I receive:

Sensor Presentation Complete
All Valves OFF
Watering times collected from device: 0
Watering times collected from device: 1
Watering times collected from device: 2
Watering times collected from device: 3
Watering times collected from device: 4
Watering times collected from device: 5

It should display both values you entered. This is telling me that it is not retrieving your values.

Jumping on a plane. Check for good radio, make sure you have saved values in the vera UI and restart your arduino with the serial monitor.

If still not working insert a delay of 2000 in the for loop where it gets the values. It may need a little time to grab those values.

Did you put a capacitor on the radio?

In setup like this:

Your values in vera need to be whole positive numbers.

for (int i = 0; i < NUMBER_OF_VALVES + 1; i++) { gw.sendVariable( i, V_LIGHT, 0); //Display each Valve OFF valveTime [i] = atol(gw.getStatus( i, V_VAR1));// Get each Valve Cycle time delay(2000); valveSoloTime [i] = atol(gw.getStatus( i, V_VAR2));// Get each Valve Solo time delay(2000); Serial.print(F("Watering times collected from device: ")); Serial.println(i);

Ok making progress, realized i needed to have some patience as I see there is a delay in changes and the startup. Here is the monitor from startup:

Sensor Presentation Complete
All Valves OFF
Watering times collected from device: 0
Watering times collected from device: 1
Watering times collected from device: 2
Watering times collected from device: 3
Watering times collected from device: 4
Watering times collected from device: 5
Watering times collected from device: 6
Watering times collected from device: 7
Watering times collected from device: 8
Valve 0 cycle time=5
Valve 0 solo time=10
Valve 1 cycle time=5
Valve 1 solo time=10
Valve 2 cycle time=5
Valve 2 solo time=10
Valve 3 cycle time=5
Valve 3 solo time=10
Valve 4 cycle time=5
Valve 4 solo time=10
Valve 5 cycle time=5
Valve 5 solo time=10
Valve 6 cycle time=5
Valve 6 solo time=10
Valve 7 cycle time=5
Valve 7 solo time=10
READY

So now the issue is this. When I first plug everything in, all relays turn on and stay on. When I go into the vera UI and turn something on, it actually turns that relay off. So it appears it is all backwards. I am still looking to see what could be causing this, but at least things appear to be progressing now.

Progress!

I can fix it programmatically, but do you have Normally Open and Normally closed selected properly on the relays?

Ok I was going off the led lights on the relay board. Testing before hooking it up. All LEDs turn on when plugged in. I just tested by connecting it to one of my sprinklers and can get it to work the way it should. I should be good now, but was wanted the all relays off. Thanks again for all your help on this.