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 ();
}