Driving 20km every day just to turn the generator and water pump on was becoming a drag, so I built an arduino solution with a GPRS shield, relay board, current sensor and real time clock to be able to turn them on remotely and monitor error conditions.
During testing I must have put too much current through one of the Phidgets sensors caused it stopped working properly, would only close, but not open – so switched it out for a 10A solid state version. Have been using the SMS command system for a week now without a hitch, basically I can start the generator, stop it, query it’s status and turn the timer on or off. If the unit detects any error condition, it will immediately shut the generator off and send an SMS alert.
The unit also has a built in warm up and cool down time for the generator and uses the current sensor to detect if the well is dry, i.e. if well is dry, pump stops, so current sensors can detect this and the arduino will shut down the generator. The current sensor will also detect if the generator didn’t come on or if the pump failed to turn on – or if the generator stopped when it should be running. All result in an error SMS being sent.
Had to mount the Arduino on the ceiling as the antenna cable wasn’t long enough

Relay box as close to the thick cabling as possible

Complete source code below, if anyone needs to rip bits out of it. Note that you’ll need to change the phone number, and the password “1234″, this password has nothing to do with the sim card, it’s just a number I’ve picked so that only people who know it can send messages to the generator.
#include "Wire.h"
#include
#define DS1307_I2C_ADDRESS 0x68
#define maxLength 200
#define PHONE 11111111111
String inString = String(maxLength);
int HOUR = 21;
int MINUTE_START = 01;
int MINUTE_STOP = 55;
boolean DEBUG = false;
unsigned long starttime = 0;
const unsigned long OVERRUN_TIME = 2UL*60UL*60UL*1000UL;
const int GEN_START_PIN = 10;
const int LOAD_PIN = 11;
const int LED = 13;
int GEN_START_DELAY = 20000;
int GEN_STOP_DELAY = 20000;
const int RETRY_LIMIT = 3;
const int CURRENT_SENSOR_PIN = 2;
const double MINIMUM_LOAD = 0.2;
long WARMUP_DELAY = 60000;
long LOAD_DELAY = 10000;
const int GPRSonModulePin = 2;
const double PUMP_LOAD = 4.0;
double load = 0.0;
boolean errorSent = false;
boolean stoppedInWindow = false;
boolean timerOn = true;
int genState = 0; //0 = off, 1=running
int pumpCommandState = 0;
int genCommandState = 0; //0 = stop, 1 = start
int error = 0;
char* errorMsg[] = {"No error","Pump failed to start","Generator failed to start","Generator failed to stop","Generator overrun","Generator still running after stop signal"};
char* msg = "";
void getSerialChars() {
while (Serial.available() > 0) {
char inChar = Serial.read();
if (inString.length() < maxLength) {
inString.append(inChar);
}
}
}
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
return ( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
return ( (val/16*10) + (val%16) );
}
void setDateDs1307(byte second, // 0-59
byte minute, // 0-59
byte hour, // 1-23
byte dayOfWeek, // 1-7
byte dayOfMonth, // 1-28/29/30/31
byte month, // 1-12
byte year) // 0-99
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.send(0);
Wire.send(decToBcd(second)); // 0 to bit 7 starts the clock
Wire.send(decToBcd(minute));
Wire.send(decToBcd(hour)); // If you want 12 hour am/pm you need to set
// bit 6 (also need to change readDateDs1307)
Wire.send(decToBcd(dayOfWeek));
Wire.send(decToBcd(dayOfMonth));
Wire.send(decToBcd(month));
Wire.send(decToBcd(year));
Wire.endTransmission();
}
// Gets the date and time from the ds1307
void getDateDs1307(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
// Reset the register pointer
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.send(0);
Wire.endTransmission();
Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
// A few of these need masks because certain bits are control bits
*second = bcdToDec(Wire.receive() & 0x7f);
*minute = bcdToDec(Wire.receive());
*hour = bcdToDec(Wire.receive() & 0x3f); // Need to change this if 12 hour am/pm
*dayOfWeek = bcdToDec(Wire.receive());
*dayOfMonth = bcdToDec(Wire.receive());
*month = bcdToDec(Wire.receive());
*year = bcdToDec(Wire.receive());
}
void switchModule(){
digitalWrite(GPRSonModulePin,HIGH);
delay(2500);
digitalWrite(GPRSonModulePin,LOW);
delay(25000);
if (DEBUG) {
Serial.println("GPRS module turned on");
}
}
boolean genInTimerWindow() {
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
if (DEBUG) {
Serial.print("Time: ");
Serial.print(hour,DEC);
Serial.print(":");
Serial.println(minute,DEC);
}
if (hour != HOUR) {
stoppedInWindow = false;
}
if ((hour == HOUR) && (minute >= MINUTE_START) && (minute <= MINUTE_STOP)) {
return true;
} else {
return false;
}
}
void startGen() {
if (DEBUG) {
Serial.println("Starting gen");
}
digitalWrite(GEN_START_PIN, HIGH);
genState = 1;
}
void stopGen() {
if (DEBUG) {
Serial.println("Stopping gen");
}
digitalWrite(GEN_START_PIN, LOW);
genState = 0;
}
void connectLoad() {
if (DEBUG) {
Serial.println("Connecting load");
}
digitalWrite(LOAD_PIN, HIGH);
}
void disconnectLoad() {
digitalWrite(LOAD_PIN, LOW);
if (DEBUG) {
Serial.println("Disconnecting load");
}
}
double readLoad() {
int load = analogRead(CURRENT_SENSOR_PIN);
return (((double)load)*25.0/1023.0);
}
void deleteAllMsgs() {
delay(1500);
Serial.println("AT+CMGD=0,4");
delay(4000);
}
int smsCommand() {
int retval=0;
delay(1500);
Serial.print("AT+CMGL=");
Serial.print(34,BYTE);
Serial.print("REC UNREAD");
Serial.println(34,BYTE);
delay(3000);
if (Serial.available() > 0) {
inString = "";
delay(500);
getSerialChars();
if (inString.contains("1234#")) {
String command = String(20);
command = inString.substring(inString.indexOf('#')+1,inString.length());
if (command.contains("start")) retval = 1;
if (command.contains("stop")) retval = 2;
if (command.contains("clear")) retval = 3;
if (command.contains("status")) retval = 4;
if (command.contains("timer on")) retval = 5;
if (command.contains("timer off")) retval = 6;
if (retval != 0) deleteAllMsgs();
}
}
return retval;
}
void sendSMSpreamble() {
delay(1500);
Serial.print("AT+CMGS=");
Serial.print(34,BYTE);
Serial.print(PHONE);
Serial.println(34,BYTE);
delay(1500);
}
void sendSMSappend() {
delay(500);
Serial.print(0x1A,BYTE); // end of message command 1A (hex)
delay(5000);
}
void sendErrorSMS() {
sendSMSpreamble();
Serial.print("Error: ");
Serial.print(errorMsg[error]);
writeStatus();
sendSMSappend();
}
void sendStopSMS() {
sendSMSpreamble();
writeStatus();
sendSMSappend();
}
void writeStatus() {
load = readLoad();
Serial.println(msg);
Serial.print("L: ");
Serial.println(load);
Serial.print("Gen: ");
Serial.println(genState);
Serial.print("Runtime: ");
Serial.print((millis()-starttime)/60000UL);
Serial.println(" min");
Serial.print("Timer: ");
if (timerOn) {
Serial.print(HOUR);
Serial.print(":");
Serial.print(MINUTE_START);
Serial.print(" - ");
Serial.println(MINUTE_STOP);
} else {
Serial.println("Off");
}
}
void sendStatusSMS() {
sendSMSpreamble();
writeStatus();
sendSMSappend();
}
void raiseError() {
stopGen();
sendErrorSMS();
}
void genStartSequence() {
if (DEBUG) {
Serial.println("Gen start sequence");
}
disconnectLoad();
startGen();
delay(GEN_START_DELAY);
load = readLoad();
if (DEBUG) {
Serial.println(load);
}
if (load >= MINIMUM_LOAD) {
starttime = millis();
delay(WARMUP_DELAY);
connectLoad();
delay(LOAD_DELAY);
load = readLoad();
if (load > PUMP_LOAD) {
if (DEBUG) {
Serial.print("Pump came on");
}
} else {
error = 1;
if (DEBUG) {
Serial.print(load);
Serial.println(" was less than the pump load.");
}
}
} else {
error = 2;
if (DEBUG) {
Serial.print(load);
Serial.println(" was less than the minimum load.");
}
}
}
void genStopSequence() {
if (DEBUG) {
Serial.println("Gen stop sequence");
}
disconnectLoad();
delay(WARMUP_DELAY);
stopGen();
delay(GEN_STOP_DELAY);
load = readLoad();
if (load >= MINIMUM_LOAD) {
error = 3;
} else {
sendStopSMS();
}
}
void blinkLED() {
digitalWrite(LED,HIGH);
delay(1000);
digitalWrite(LED,LOW);
}
void setup() {
Serial.begin(19200);
pinMode(LED, OUTPUT);
digitalWrite(LED, HIGH);
pinMode(GEN_START_PIN, OUTPUT);
digitalWrite(GEN_START_PIN, LOW);
pinMode(LOAD_PIN, OUTPUT);
digitalWrite(LOAD_PIN, LOW);
Wire.begin();
delay(5000);
starttime = 0UL;
switchModule(); // swith the module ON
Serial.println("AT+CMGF=1");
if (DEBUG) {
//byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
//getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
//HOUR = hour;
//MINUTE_START = minute;
//MINUTE_STOP = MINUTE_START+1;
WARMUP_DELAY=1000;
LOAD_DELAY = 1000;
GEN_START_DELAY = 2000;
GEN_STOP_DELAY = 2000;
}
msg = "Module turned on.";
//sendStatusSMS();
msg = "";
digitalWrite(LED, LOW);
}
void loop() {
switch (smsCommand()) {
case 1:
genCommandState = 1;
error = 0;
timerOn = false;
break;
case 2:
genCommandState = 0;
stoppedInWindow = true;
msg = "Stop signal from SMS";
break;
case 3:
error = 0;
break;
case 4:
msg = "";
sendStatusSMS();
break;
case 5:
timerOn = true;
sendStatusSMS();
break;
case 6:
timerOn = false;
sendStatusSMS();
break;
}
if (error == 0) {
errorSent = false;
if (genState == 0) {
starttime = 0UL;
if ((timerOn) && (genInTimerWindow()) && (!stoppedInWindow)) {
if (DEBUG) {
Serial.println("In time window");
}
genCommandState = 1;
}
if (genCommandState == 1) {
genStartSequence();
}
} else {
if ((timerOn) && !genInTimerWindow()) {
genCommandState = 0;
msg = "Stopped by timer";
}
if (readLoad() < PUMP_LOAD) {
msg = "Stop signal from pump";
if (DEBUG) {
Serial.println(msg);
}
genCommandState = 0;
stoppedInWindow = true;
}
unsigned long time = millis();
if ((time - starttime) > OVERRUN_TIME) {
error = 4;
}
if (genCommandState == 0) {
genStopSequence();
}
}
} else {
if (!errorSent) {
raiseError();
errorSent = true;
}
}
delay(2000);
blinkLED();
if (DEBUG) {
Serial.print("gen state=");
Serial.print(genState);
Serial.print(" Load=");
Serial.println(readLoad());
}
}