3 Stage ATtiny85 Watchdog Timer

A while ago I started logging temperatures to Pachube via a Nanode.  For the most part this works fine, but sometimes something breaks and I might lose a few hours or days worth of data.  It might be the Nanode that’s gone down, or Pachube, or (most likely) my Internet connection.  So I decided to build a simple 3 stage external Watchdog Timer that would monitor the status of the feed and start taking steps to rectify it.

The principal works like this; every 16 seconds the Nanode tries to upload data to Pachube.  If it is successful, a 200OK message is returned.  The Nanode will bring pin 9 high for a moment.

The ATtiny is basically being used as a timer.  It starts counting from zero, and listens for an input from Nanodes pin 9.  If it gets an input (ie an upload was successful), it starts counting from zero again.  If it gets to 10 minutes with no input from the Nanode it grounds the reset pin on the Nanode for a moment (Nanode Reset – Stage 1).

If it still hears nothing it will continue to reset the Nanode every 10 minutes 4 more times.  If nothing is heard within 30 minutes after that, it triggers a relay that cuts the power to my internet router (Router Reset – Stage 2).

If there is still no life 35 minutes after that, then a small buzzer and flashing light is set off, and it will continue to buzz/flash until manually silenced or a connection is reestablished. (Call for human intervention – Stage 3)

There’s nothing too complicated about the circuit.  The ATtiny needs power and ground.  Pin 9 of the Nanode goes to Pin 3 of the ATtiny.  Pin 0, 1 & 2 are the stage 1, 2 & 3 outputs.  Because pin 0 is connected to reset, it must be kept high, and only go low when triggered.  The other 2 outputs are normally low, but go high when triggered. I have added an LED to each of these pins for debugging too, and a jumper to disable the Nanode reset if necessary.

One of the problems with the Nanode (most Arduino clones with an Ethernet jack actually) is that a normal shield won’t sit properly on the headers.  The Proto-X shield from Ciseco has an area at the top that I wouldn’t be using, so I trimmed it down with a PCB guillotine.  I think you’ll agree, it fits quite snugly now;

Initially I had it set with a 2 minute time on Stage 1 with 1 retry, and a 5 minute timer on Stage 2.  It appears, however, that a few minutes of inactivity uploading to Pachube is quite common, so the result was that my internet connection was continually bouncing, which played havoc with anything I wanted to do at the time!  The current settings may well be a bit on the cautious side, but it seems pretty stable.  In the last 5 weeks it has only reached State 2 once (about 4am), which in itself probably saved me from waking up and wondering why I couldn’t get on to Twitter!

Picture above: Mork & Mindy (Nanode! Nanode!) in the Arduino control room, with the Watchdog Timer on Mork.  The relay for the internet router is just out of shot on the left.

The code I used on the ATtiny;

int leda = 0;
int ledb = 1;
int ledc = 2;
int inpin = 3;
long lasttrig; //last time since input received
long thresha = 600000; //1st threshold in milliseconds 10 mins
long threshb = 1800000; //2nd threshold in milliseconds 30 mins
long threshc = 2100000; //3rd threshold in milliseconds 35 mins
int latcha = 0; //latches on when threshold A is reached
int latchb = 0; //latches on when threshold B is reached
long elapsed =0;
int counter = 0;
void setup(){
 pinMode (leda, OUTPUT);
 pinMode (ledb, OUTPUT);
 pinMode (ledc, OUTPUT);
 pinMode (inpin, INPUT);
digitalWrite (leda, HIGH);
 digitalWrite (ledb, LOW);
 digitalWrite (ledc, LOW);
 lasttrig = millis();
}
void loop(){
 elapsed = millis() - lasttrig;
 if (digitalRead(inpin) == HIGH){ // Checks if an input has been received
 lasttrig = millis(); // resets last triggered counter
 latcha = 0; // resets latches
 latchb = 0;
 elapsed = 0;
 }
 if (latcha == 0){
 if (elapsed >= thresha) {
 triga();
 }
 }
 if (latchb == 0) {
 if (elapsed >= threshb) {
 trigb();
 }
 }
 if (elapsed >= threshc) {
 trigc();
 }
}
void triga(){ // When threshold A is triggered
 digitalWrite (leda, LOW);
 delay(1000);
 digitalWrite (leda, HIGH);
 delay (2000);
 counter ++;
 if (counter == 5) {
 latcha = 1;
 }
 else {
 lasttrig = millis();
 }
}
void trigb(){ // When threshold B is triggered
 digitalWrite (ledb, HIGH);
 delay(2000);
 digitalWrite (ledb, LOW);
 latchb = 1;
}

void trigc(){ // When threshold C is triggered
 digitalWrite (ledc, HIGH);
 delay(2);
 digitalWrite (ledc, LOW);
}