Project in progress

Chicken Coop Automation © GPL3+

Automating a chicken coop with sensors and actors, using an Arduino MKR1000 and the Blynk internet dashboard.

  • 5,728 views
  • 9 comments
  • 16 respects

Components and supplies

Abx00004 iso both
Arduino MKR1000 & Genuino MKR1000
×1
CHIHAI DC Motor - 12V 200rpm Encoder with Mounting Bracket
×1
Geekcreit L298N Dual H Bridge Stepper Motor Driver Board For Arduino
×1
Adafruit industries ada161 image 75px
Photo resistor
×1
10167 01
DHT22 Temperature Sensor
×1

Apps and online services

About this project

Introduction

To protect our new chickens from the different predators, an automatic door is needed. We had a look on the available solutions on the market, but none could meet our requirements:

  • Remote monitoring and control by using an app
  • Possibility to add additional sensors and actors to measure temperature or buzzer alert
  • Not too expensive

It would be way more fun to build it myself, so this is the start of my first microcontroller project.

Concept

A simple aluminium plate with guide rails will serve as the door. It is attached to a DC motor by using nylon wire. The DC motor includes a gearbox, resulting in 200 rpm on 12V DC. The used motor has a hall sensor encoder built in. To keep the door in the "up" position, it is not needed to engage the motor. Resulting power consumption will therefore be very low.

The control module I used is the Arduino MKR1000. It has WiFi built in and plenty of I/O. I have installed a WiFi Access Point in my garden shed, so WiFi reception is perfect within my chicken coop.

After booting or restarting the Arduino, the first step will be to "calibrate" the encoder values for its up and down positions. The app will ask to give the Up command or to confirm the door is already in the Up position. Once done, the encoder value is set to zero.

For the next step, the app will ask to give the Close command and Close confirmation. The encoder value at that moment will be stored in a variable. From now on, we can control the door between a zero encoder value and closed encoder value.

To control the door automatically, I've used a cheap photoresistor. Threshold value for daylight and sunset are preset within the Blynk dashboard as well as the operating mode: manual or automatic.

The DHT22 temperature & humidity sensor is only used to monitor both values.

Issues

1. The solution is not working very reliably. After some days, the door movement or sensor reading stops working. Browsing on the internet showed more people are having the same problem with the MKR1000 in combination with a web service - it is to be analysed if this can be solved.

Future improvements

1. Install magnetic reed switches to serve as a reliable positioning measurement and to generate position alarms in case the door will not reach the requested position in time.

2. IR camera to be able to monitor if all chicken have entered in the coop before the door closes. Maybe also to keep an eye on the egg nest or to monitor the outside at night.

3. Motion sensor including buzzer or strobo light to scare away predators who are too close to the chicken coop.

Code

Chicken Coop CodeArduino
/* Code developed by BMic on 19 March 2018
 * Used to connect with Blynk IOT service and to control a chicken coop: 
 * - Door control based on encoder value
 * - Environmental monitoring: Temperature, Humidity and light
*/

#include "DHT.h"
#include <SPI.h>
#include <WiFi101.h>
#include <BlynkSimpleMKR1000.h>


//========================================================== //
//============== IO & Variables definition ================= //
//========================================================== //

#define encoderPinA 0
#define encoderPinB 1
#define O_MotorDriverOut1 7
#define O_MotorDriverOut2 8

#define I_LightSensor A0

#define DHTPIN 9
#define DHTTYPE DHT22
DHT dht(DHTPIN, DHTTYPE);

float hum;  //Stores humidity value
float temp; //Stores temperature value

int LightValue = 0;
int deltaLight = 0;
int deltaDark = 0;

volatile int encoderPos = 0;
int encoderClosePos = 0;

//--- Used for sequential programming steps during initialize procedure ---
int step = 0;

//--- The different states of the system ---
enum states {INITIALIZE, DOOR_ERROR, DOOR_IS_OPEN, CLOSING_DOOR, DOOR_IS_CLOSED, OPENING_DOOR};
String OldState;

states state;

//========================================================== //
//=========== Blynk connection with Read/Write ============== //
//========================================================== //
// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "xxxxxxxxxxxxxxxxx";

// Your WiFi credentials.
// Set password to "" for open networks.
char ssid[] = "WiFi-SSID";
char pass[] = "password";

//========================================================== //
//============== Initial setup at Startup ================= //
//========================================================== //

BlynkTimer timer;

void setup() 
{
  
//--- initialize digital pin LED_BUILTIN as an output ---
  pinMode(O_MotorDriverOut1, OUTPUT);
  pinMode(O_MotorDriverOut2, OUTPUT);
  pinMode(encoderPinA, INPUT_PULLUP);
  pinMode(encoderPinB, INPUT_PULLUP);
  
 state = INITIALIZE;

  attachInterrupt(0, doEncoder, CHANGE);

  dht.begin();
  timer.setInterval(5000L, dhtTimerEvent);

  Blynk.begin(auth, ssid, pass);
  timer.setInterval(1000L, BlynkTimerEvent);
}

int ThresHoldGettingDark = 25;
  BLYNK_WRITE(V21)
{
  ThresHoldGettingDark = param.asInt();
}

int ThresHoldGettingLight = 650;
  BLYNK_WRITE(V22)
{
  ThresHoldGettingLight = param.asInt();
}

void BlynkTimerEvent()
{
  Blynk.virtualWrite(V2, encoderPos);
}

void dhtTimerEvent()
{
  hum = dht.readHumidity();
  temp= dht.readTemperature();
  Blynk.virtualWrite(V3, temp); 
  Blynk.virtualWrite(V4, hum);

  LightValue = analogRead(I_LightSensor);
  deltaLight = ThresHoldGettingLight - LightValue;
  deltaDark = ThresHoldGettingDark - LightValue;
  Blynk.virtualWrite(V1, LightValue);
  Blynk.virtualWrite(V11, deltaLight);
  Blynk.virtualWrite(V12, deltaDark);
}

int buttonOpenValue;
  BLYNK_WRITE(V7)
{
  buttonOpenValue = param.asInt();
}

int buttonCloseValue;
  BLYNK_WRITE(V8)
{
  buttonCloseValue = param.asInt();
}

int switchOpenValue;
  BLYNK_WRITE(V9)
{
  switchOpenValue = param.asInt();
}

int switchCloseValue;
  BLYNK_WRITE(V10)
{
  switchCloseValue = param.asInt();
}

int operatingModeValue = 0;
  BLYNK_WRITE(V20)
{
  operatingModeValue = param.asInt();
}

//========================================================== //
//============== Finite State Machine Loop ================= //
//========================================================== //
void loop() 
{ 

  Blynk.run(); 
  timer.run(); 
 
  switch (state)
  {
    case INITIALIZE:
      Initializing();
      break;

    case DOOR_IS_OPEN: 
      StopDoorMotor();
      CheckDownButton(); 
      CheckGettingDark();
      ChangeState("Door is OPEN");
    break;

    case CLOSING_DOOR:
      ClosingDoor(); 
      CheckCloseSwitch();
      CheckEncoderCloseValue();
      ChangeState("Closing door");
    break;   

    case DOOR_IS_CLOSED:
      StopDoorMotor();
      CheckUpButton(); 
      CheckGettingLight();
      ChangeState("Door is CLOSED");
    break; 

    case OPENING_DOOR:
      OpeningDoor();
      CheckOpenSwitch();
      CheckEncoderOpenValue();
      ChangeState("Opening door");
    break; 

    case DOOR_ERROR:
      ChangeState("Door Error");
    break;
  }


}

//========================================================== //
//============== Finite State - Functions ================= //
//========================================================== //

// --------------- Initializing Function ---------------
void Initializing() //Calibrate Encoder values for Open & Closed position

{
  switch(step)
  {   
    case 0:
      Blynk.virtualWrite(V6, "Give Open Command");
      if(buttonOpenValue == HIGH)
      {
        OpeningDoor();
        step = 1;
      }
      else if(switchOpenValue == HIGH)
      {
        StopDoorMotor();
        encoderPos = 0;
        step = 2;  
      }
      break;

    case 1:
      Blynk.virtualWrite(V6, "Opening - Stop when Open");
      if(switchOpenValue == HIGH)
      {
        StopDoorMotor();
        encoderPos = 0;
        step = 2;         
      }
      break;

    case 2:
      Blynk.virtualWrite(V6, "Give Close Command");
      if(buttonCloseValue == HIGH)
      {
        ClosingDoor();
        step = 3;
      }
      break;

    case 3:
      Blynk.virtualWrite(V6, "Closing - Stop when Closed");
      if(switchCloseValue == HIGH)
        {
          StopDoorMotor();
          encoderClosePos = encoderPos;
          state = DOOR_IS_CLOSED;         
        }
        break;
    }
    
}

// --------------- MOTOR Functions ---------------
void StopDoorMotor()
{
  digitalWrite(O_MotorDriverOut1, LOW);
  digitalWrite(O_MotorDriverOut2, LOW);
}

void ClosingDoor()
{
 digitalWrite(O_MotorDriverOut1, HIGH);
 digitalWrite(O_MotorDriverOut2, LOW);
}

void OpeningDoor()
{
 digitalWrite(O_MotorDriverOut1, LOW);
 digitalWrite(O_MotorDriverOut2, HIGH);
}

// --------------- Input Buttons ---------------
void CheckDownButton()
{
  if(buttonCloseValue == HIGH) // Virtual value from Blynk
  {
    state = CLOSING_DOOR;
  }  
}

void CheckUpButton()
{
  if(buttonOpenValue == HIGH) // Virtual value from Blynk
  {
    state = OPENING_DOOR;
  }
}

// --------------- Input Switches ---------------
void CheckCloseSwitch()
{
  if(switchCloseValue == HIGH) // Virtual value from Blynk
    {
      state = DOOR_IS_CLOSED;
    }
}

void CheckOpenSwitch()
{
  if(switchOpenValue == HIGH) // Virtual value from Blynk
  {
    state = DOOR_IS_OPEN;
  }
}

void CheckEncoderCloseValue()
{
  if(encoderPos >= encoderClosePos)
  {
    StopDoorMotor();
    state = DOOR_IS_CLOSED;    
  }
}

void CheckEncoderOpenValue()
{
  if(encoderPos <= 0)
  {
    StopDoorMotor();
    state = DOOR_IS_OPEN;    
  }
}

// --------------- Light Sensor ---------------
void CheckGettingDark()
{
  if(operatingModeValue && LightValue < ThresHoldGettingDark)
  {
    state = CLOSING_DOOR;
  }
}

void CheckGettingLight()
{
  if(operatingModeValue && LightValue > ThresHoldGettingLight)
  {
    state = OPENING_DOOR;
  }
}

// --------------- Status String ---------------
void ChangeState(String Status)
{
  if(OldState != Status)
  {
    Blynk.virtualWrite(V6, Status);
    OldState = Status;
  }
}

//========================================================== //
//=========== Interrupts - Detect fast changes ============== //
//========================================================== //
void doEncoder()
{
  if(digitalRead(encoderPinA) == digitalRead(encoderPinB))
  {
    encoderPos++;
  }
  else 
  {
    encoderPos--;
  }
}

Schematics

kippendeur_Ndx0y55bgl.fzz
kippendeur_Ndx0y55bgl.fzz
2018-04-29_14_40_35-kippendeur_OpOH7Fj2Gg.png
2018 04 29 14 40 35 kippendeur opoh7fj2gg

Comments

Similar projects you might like

Night Light Assistant

Project tutorial by Gabriele Fugazzi

  • 767 views
  • 4 comments
  • 7 respects

Smart Energy Saver for Your Home

Project tutorial by Dhairya Parikh

  • 3,402 views
  • 8 comments
  • 12 respects

A Geiger Counter Simulator

Project tutorial by organtin

  • 1,088 views
  • 1 comment
  • 4 respects

Twilight Switch With Levels

Project in progress by Rafa Salvador

  • 969 views
  • 1 comment
  • 4 respects

Arduino MKR DIN Rail Mount

Project showcase by hwhardsoft

  • 1,020 views
  • 0 comments
  • 4 respects

Simple Water Quality Analysis

Project showcase by Wen-Liang Lin

  • 7,243 views
  • 5 comments
  • 10 respects
Add projectSign up / Login