Newer
Older
chicken_door / chicken_door.ino
/*
 * Open and close the door on the chicken house depending on the
 * ambient light levels.
 * Copyright Alex Tucker 2013
 *
 */

#include <Narcoleptic.h>

#define NODEBUG

#ifdef DEBUG
#define DPRINTLN(str)    Serial.println(str)
#else
#define DPRINTLN(str)
#endif

#define PHOTOCELL_PIN      0
#define DOOR_CONTACT_2_PIN 2
#define FWREV_PIN          3
#define DOOR_CONTACT_1_PIN 4
#define ONOFF_PIN          5
#define TEMP_SUPPLY_PIN    6
#define AUX_BUTTON_PIN     7

#define INITIALIZE     0
#define WAIT_FOR_LIGHT 1
#define LOWER_DOOR     2
#define WAIT_FOR_DARK  3
#define RAISE_DOOR     4

#define BRIGHTNESS_SIZE  3
#define BRIGHT_THRESHOLD 600
#define OPEN_DELAY       6400
#define MAX_CLOSE_TIME   4000
#define MAX_OPEN_TIME    4000
#define HYSTERESIS       50

word brightness[BRIGHTNESS_SIZE];
int state = WAIT_FOR_LIGHT;
volatile int button_state = 0;

void setup() {
  pinMode(ONOFF_PIN, OUTPUT);
  pinMode(FWREV_PIN, OUTPUT);
  pinMode(DOOR_CONTACT_1_PIN, INPUT);
  digitalWrite(DOOR_CONTACT_1_PIN, LOW);
  pinMode(DOOR_CONTACT_2_PIN, INPUT);
  digitalWrite(DOOR_CONTACT_2_PIN, LOW);
  pinMode(AUX_BUTTON_PIN, INPUT);
  pinMode(TEMP_SUPPLY_PIN, OUTPUT);
  digitalWrite(TEMP_SUPPLY_PIN, HIGH); // for initial photocell reading
//  attachInterrupt(0, pressButton, LOW);
  digitalWrite(ONOFF_PIN, LOW);
  digitalWrite(FWREV_PIN, LOW);
  state = INITIALIZE;
  word currentBrightness = analogRead(PHOTOCELL_PIN);
  for (int i = 0; i < BRIGHTNESS_SIZE; i++) {
    brightness[i] = currentBrightness;
  }
  digitalWrite(TEMP_SUPPLY_PIN, LOW);
  Narcoleptic.disableTimer1();
  Narcoleptic.disableTimer2();
#ifdef DEBUG
  Serial.begin(9600);
#else
  Narcoleptic.disableSerial();
#endif
  Narcoleptic.disableWire();
  Narcoleptic.disableSPI();
  Narcoleptic.disableADC();
}

/* void pressButton() {
  button_state = 1;
} */

void raiseDoor() {
  long millisLeft = MAX_CLOSE_TIME;
  digitalWrite(TEMP_SUPPLY_PIN, HIGH);
  digitalWrite(FWREV_PIN, LOW);
  delay(100);
  millisLeft -= 100;
  digitalWrite(ONOFF_PIN, HIGH);
  while ((digitalRead(DOOR_CONTACT_2_PIN) == LOW) && (millisLeft > 0)) {
    delay(100);
    millisLeft -= 100;
  }
  delay(200);
  digitalWrite(ONOFF_PIN, LOW);
  delay(10);
  digitalWrite(TEMP_SUPPLY_PIN, LOW);
}

void lowerDoor() {
  long millisLeft = MAX_CLOSE_TIME;
  digitalWrite(TEMP_SUPPLY_PIN, HIGH);
  digitalWrite(FWREV_PIN, HIGH);
  delay(100);
  millisLeft -= 100;
  digitalWrite(ONOFF_PIN, HIGH);
  while ((digitalRead(DOOR_CONTACT_1_PIN) == LOW) && (millisLeft > 0)) {
    delay(100);
    millisLeft -= 100;
  }
  delay(200);
  digitalWrite(ONOFF_PIN, LOW);
  delay(10);
  digitalWrite(FWREV_PIN, LOW);
  digitalWrite(TEMP_SUPPLY_PIN, LOW);
}

word readBrightness() {
  Narcoleptic.enableADC();
  digitalWrite(TEMP_SUPPLY_PIN, HIGH);
  delay(500);
  word currentBrightness = analogRead(PHOTOCELL_PIN);
  DPRINTLN(currentBrightness);
  digitalWrite(TEMP_SUPPLY_PIN, LOW);
  Narcoleptic.disableADC();
  unsigned long total = brightness[0];
  for (int i = 0; i < BRIGHTNESS_SIZE; i++) {
    if (i == (BRIGHTNESS_SIZE - 1)) {
      brightness[i] = analogRead(PHOTOCELL_PIN);
    } else {
      brightness[i] = brightness[i+1];
    }
    total += brightness[i];
  }
  word avg = total / (BRIGHTNESS_SIZE + 1);
  return avg;
}

void loop() {
  switch (state) {
    case INITIALIZE:
      digitalWrite(TEMP_SUPPLY_PIN, HIGH);
      delay(500);
      if (digitalRead(DOOR_CONTACT_2_PIN) == LOW) {
        raiseDoor();
      }
      DPRINTLN("-> WAIT_FOR_LIGHT");
      state = WAIT_FOR_LIGHT;
      break;
    case WAIT_FOR_LIGHT:
      if ((readBrightness() > (BRIGHT_THRESHOLD + HYSTERESIS)) || (button_state == 1)) {
        button_state = 0;
        DPRINTLN("-> LOWER_DOOR");
        state = LOWER_DOOR;
      } else {
#ifdef DEBUG
        delay(10000);
#else
        Narcoleptic.delay(30000);
#endif
      }
      break;
    case LOWER_DOOR:
      lowerDoor();
      DPRINTLN("-> WAIT_FOR_DARK");
      state = WAIT_FOR_DARK;
      break;
    case WAIT_FOR_DARK:
      if ((readBrightness() < (BRIGHT_THRESHOLD - HYSTERESIS)) || (button_state == 1)) {
        button_state = 0;
        DPRINTLN("-> RAISE_DOOR");
        state = RAISE_DOOR;
      } else {
#ifdef DEBUG
        delay(10000);
#else
        Narcoleptic.delay(30000);
#endif
      }
      break;
    case RAISE_DOOR:
      raiseDoor();
      DPRINTLN("-> WAIT_FOR_LIGHT");
      state = WAIT_FOR_LIGHT;
      break;
  }
}