Chicken coop automatisation questions

We have a chicken coop with three chickens.

I want to modify three things of the status quo:

1.) Shutter door
The shutter is controlled with a timer clock.
I want to replace this timer clock in order to control it with home assistant (and link the open/close cycle relative to sunset/sundown). I want to reuse the existing hardware and electronics (despite the timer clock). The door is controlled by to pins which need to be connected (closed/closing) or separated (opening / open). There must not be any voltage , just connect for closing and disconnect for opening. How / with what hardware/components would I do this ideally? An ESPHome controlled relay?

2.) Nesting area
The chicken like the place where they are supposed to leg eggs so much, that they also sleep there if possible. This automatically leads to the fact that they also poop there, which is undesired and nasty (nasty chicken!). I want to build and add a horizontal motorized sliding door, which also can be controlled by home assistant. I would close it every day at noon and open it at midnight when the chicken are asleep. I thought of a piece of wood mounted to a linear rail, driven by a stepper motor / driver with end switches. What do you think? How would I initiate the opening and closing? ESPHome? MQTT? And how to register if the door is open or closed?

3.) Power supply
The only two things at the moment consuming power are the shutter and timer clock. They use regular AA-Batteries at the moment.
I would like to add a solar panel, charging controller and a motorcycle/car battery in order to autark this setup and the new components. I think I can use off-the-shelf components for this. Do you have any recommendations?

So in summery there are the following questions so far
-How to connect/disconnect the to pins for controlling the shutter?
-How would you build the sliding door for the nesting area?
-How initiate the closing or opening of the sliding door?
-How to determine whether the sliding door is open or closed?
-Can you recommend any components for the solar-power setup? I think it would be nice to also be able to check the batteries capacity.

Cheers

Pete

So I decided on a solar Panel, Charging Controller and Battery.

The front door I’ll control with ESPHome, WeMos D1 R2 and a relay.

I still have to build the mechanics for the nest area.

It used more time and money than I originally anticipated, but here is the current setup:

Hardware:

For opening the house main door I’ll use ESPhome with a Wemos D1 R2 and a 3.3V relay from Aliexpress.

For opening and closing the nesting area sliding door I use an Arduino Uno WiFi triggered by MQTT-messages from homeassistant. The sliding door is built with 3d-Printer hardware (V-Slot profile and a flat piece of wood as door with a matching gantry (1set 3D Drucker teile Openbuilds V gantry plat set spezielle rutsche platte pulley für 2020 /2040 V slot aluminium profile räder|3D Printer Parts & Accessories| - AliExpress)

Here is the Arduino sketch:

#include <Arduino.h>
#include <PubSubClient.h>
#include <WiFiNINA.h>

char *SSID = "IoT";
char *SSID_PW = "XXX";
const char *MQTT_SERVER = "homeassistant.local";
const char *clientId = "huehnerstall_legenest";
const char *USER_NAME = "mqtt_huehnerstall";
const char *PW = "XXX";
const char *SUBSCRIBTION_CHANNEL = "/huehnerhaus/legenest";

const int STATE_OPEN = 1;
const int STATE_CLOSED = 2;
const int STATE_MOVING = 3;

const int COMMAND_OPEN = 1;
const int COMMAND_CLOSE = 2;
const int COMMAND_STOP = 3;
const int COMMAND_MOVE = 4;
const int COMMAND_GET_STATE = 5;

const int PIN_DOOR_CLOSED_SWITCH = 8;
const int PIN_DOOR_OPEN_SWITCH = 7;
const int PIN_PULSE = 3;
const int PIN_DIRECTION = 4;
const int PIN_ENABLE = 5;

const long MAX_DURATION = 7 * 1000;
const int MOVE_DELAY = 700;

const int DIRECTION_CLOSING = HIGH;
const int DIRECTION_OPENING = LOW;

const int STEPS_PER_REVOLUTION = 200;

char cState[1];

WiFiClient arduinoClient;
PubSubClient client(arduinoClient);

void setup_wifi()
{
  delay(100);
  // We start by connecting to a WiFi network
  Serial.print("Connecting to ");
  Serial.println(SSID);

  WiFi.begin(SSID, SSID_PW);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  randomSeed(micros());
  Serial.println("");
  Serial.println("WiFi connected");
  //Serial.println("IP address: " + WiFi.localIP());
}

//Umgekehrte Logik, damit interne Pullup-Resistoren verwendet werden können
int get_state()
{
  if (digitalRead(PIN_DOOR_CLOSED_SWITCH) == LOW)
  {
    Serial.println("Door closed");
    return STATE_CLOSED;
  }
  else if (digitalRead(PIN_DOOR_OPEN_SWITCH) == LOW)
  {
    Serial.println("Door open");
    return STATE_OPEN;
  }
  else
  {
    Serial.println("Door moving...");
    return STATE_MOVING;
  }
}

void stop()
{
  // digitalWrite(PIN_PULSE, LOW);
  // digitalWrite(PIN_DIRECTION, LOW);
  // digitalWrite(PIN_ENABLE, LOW);
  digitalWrite(PIN_ENABLE, HIGH);
}

void start()
{
  digitalWrite(PIN_ENABLE, LOW);
}

void open_door()
{
  Serial.println("Opening reached...");

  stop();
  if (get_state() == STATE_OPEN)
  {
    return;
  }
  else
  {
    Serial.println("Opening door...");
    //Darf maximal 7 Sekunden dauern, ansonsten von selber stoppen
    long lStart = millis();
    start();
    digitalWrite(PIN_DIRECTION, DIRECTION_OPENING);
    while (get_state() != STATE_OPEN)
    // int x = 0;
    // while (x < 500)
    {
      //x++;
      digitalWrite(PIN_PULSE, HIGH);
      delayMicroseconds(MOVE_DELAY);
      digitalWrite(PIN_PULSE, LOW);
      delayMicroseconds(MOVE_DELAY);
      long lCurrent = millis();
      if (lCurrent - lStart >= MAX_DURATION)
      {
        Serial.println("Door opening takes too long => stop");
        return;
      }
    }
  }
}

void close_door()
{
  stop();
  if (get_state() == STATE_OPEN)
  {
    return;
  }
  else
  {
    long lStart = millis();
    start();
    digitalWrite(PIN_DIRECTION, DIRECTION_CLOSING);
    while (get_state() != STATE_CLOSED)
    {
      digitalWrite(PIN_PULSE, HIGH);
      delayMicroseconds(MOVE_DELAY);
      digitalWrite(PIN_PULSE, LOW);
      delayMicroseconds(MOVE_DELAY);
      long lCurrent = millis();
      if (lCurrent - lStart >= MAX_DURATION)
      {
        Serial.println("Door closing takes too long => stop");
        return;
      }
    }
  }
}

void move()
{
  start();

  if (get_state() == STATE_CLOSED)
  {
    digitalWrite(PIN_DIRECTION, DIRECTION_OPENING);
  }
  else if (get_state() == STATE_OPEN)
  {
    digitalWrite(PIN_DIRECTION, DIRECTION_CLOSING);
  }
  else
  {
    Serial.println("Invalid state for this operation. Door must be open or closed in order to test.");
    return;
  }
  for (int i = 0; i < 5 * STEPS_PER_REVOLUTION; i++)
  {
    digitalWrite(PIN_PULSE, HIGH);
    delayMicroseconds(MOVE_DELAY * 4);
    digitalWrite(PIN_PULSE, LOW);
    delayMicroseconds(MOVE_DELAY * 4);
  }

  digitalWrite(PIN_DIRECTION, !digitalRead(PIN_DIRECTION));
  for (int i = 0; i < 5 * STEPS_PER_REVOLUTION; i++)
  {
    digitalWrite(PIN_PULSE, HIGH);
    delayMicroseconds(MOVE_DELAY * 4);
    digitalWrite(PIN_PULSE, LOW);
    delayMicroseconds(MOVE_DELAY * 4);
  }
}

void callback(char *topic, byte *payload, unsigned int length)
{
  Serial.println(payload[0]);
  Serial.print("Command from MQTT broker is: [");
  Serial.print(topic);
  Serial.print(": ");
  int iPayload = (char)payload[0] - '0';
  Serial.println(iPayload);

  Serial.print("]");
  switch (iPayload)
  {
  case COMMAND_OPEN:
    open_door();
    break;
  case COMMAND_CLOSE:
    close_door();
    break;
  case COMMAND_MOVE:
    move();
    break;
  case COMMAND_STOP:
    stop();
    break;
  case COMMAND_GET_STATE:
    break;
  }
  int iState = get_state();
  Serial.println(iState);
  String sState = String(iState);
  sState.toCharArray(cState, sState.length() + 1);
  client.publish("/huehnerhaus/legenest/status", cState, true);
}

void reconnect()
{
  // Loop until we're reconnected
  while (!client.connected())
  {
    Serial.print("Attempting MQTT connection...");

    // Attempt to connect
    if (client.connect(clientId, USER_NAME, PW))
    {
      Serial.println("connected");
      //once connected to MQTT broker, subscribe command if any
      client.subscribe(SUBSCRIBTION_CHANNEL);
    }
    else
    {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 6 seconds before retrying
      delay(6000);
    }
  }
}

void setup()
{
  Serial.begin(9600);
  Serial.println("Starting up...");
  pinMode(PIN_DOOR_CLOSED_SWITCH, INPUT_PULLUP);
  pinMode(PIN_DOOR_OPEN_SWITCH, INPUT_PULLUP);
  pinMode(PIN_PULSE, OUTPUT);
  pinMode(PIN_DIRECTION, OUTPUT);
  pinMode(PIN_ENABLE, OUTPUT);
  //Serial.begin(9600); //115200
  setup_wifi();
  client.setServer(MQTT_SERVER, 1883);
  client.setCallback(callback);
}

void loop()
{
  if (!client.connected())
  {
    reconnect();
  }
  client.loop();
}

Currently I am waiting for the electrical installation material to arrive. I’ll post some pictures once I can start installing everything.

2 Likes

Work in progress

1 Like

Robot Chickens! You gotta love it :slight_smile:

Updated Code with Wifi reconnect after connection was lost

type or p#include <Arduino.h>
#include <PubSubClient.h>
//#include <WiFi.h>
#include <WiFiNINA.h>

char *SSID = "IoT";
char *SSID_PW = "";
const char *MQTT_SERVER = "192.168.1.239";//"homeassistant.local";//"192.168.1.239"; //"homeassistant.local";
const char *clientId = "huehnerstall_legenest";
const char *USER_NAME = "mqtt_huehnerstall";
const char *PW = "";
const char *SUBSCRIBTION_CHANNEL = "/huehnerhaus/legenest";

const int STATE_OPEN = 1;
const int STATE_CLOSED = 2;
const int STATE_MOVING = 3;

const int COMMAND_OPEN = 1;
const int COMMAND_CLOSE = 2;
const int COMMAND_STOP = 3;
const int COMMAND_MOVE = 4;
const int COMMAND_GET_STATE = 5;

const int PIN_DOOR_CLOSED_SWITCH = 8;
const int PIN_DOOR_OPEN_SWITCH = 7;
const int PIN_PULSE = 3;
const int PIN_DIRECTION = 4;
const int PIN_ENABLE = 5;

const long MAX_DURATION = 15 * 1000;
const int MOVE_DELAY = 700;

const int DIRECTION_CLOSING = HIGH;
const int DIRECTION_OPENING = LOW;

const int STEPS_PER_REVOLUTION = 200;

long lTime2 = 0;

char cState[1];

WiFiClient arduinoClient;
PubSubClient client(arduinoClient);

void setup_wifi()
{
  delay(100);
  // We start by connecting to a WiFi network
  Serial.print("Connecting to ");
  Serial.println(SSID);

  WiFi.begin(SSID, SSID_PW);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  randomSeed(micros());
  Serial.println("");
  Serial.println("WiFi connected");
  //Serial.println("IP address: " + WiFi.localIP());
}

//Umgekehrte Logik, damit interne Pullup-Resistoren verwendet werden können
int get_state()
{
  if (digitalRead(PIN_DOOR_CLOSED_SWITCH) == LOW)
  {
    Serial.println("Door closed");
    return STATE_CLOSED;
  }
  else if (digitalRead(PIN_DOOR_OPEN_SWITCH) == LOW)
  {
    Serial.println("Door open");
    return STATE_OPEN;
  }
  else
  {
    Serial.println("Door moving...");
    return STATE_MOVING;
  }
}

void stop()
{
  // digitalWrite(PIN_PULSE, LOW);
  // digitalWrite(PIN_DIRECTION, LOW);
  // digitalWrite(PIN_ENABLE, LOW);
  digitalWrite(PIN_ENABLE, HIGH);
}

void start()
{
  digitalWrite(PIN_ENABLE, LOW);
}

void open_door()
{
  Serial.println("Opening reached...");

  stop();
  if (get_state() == STATE_OPEN)
  {
    return;
  }
  else
  {
    Serial.println("Opening door...");
    //Darf maximal 7 Sekunden dauern, ansonsten von selber stoppen
    long lStart = millis();
    start();
    digitalWrite(PIN_DIRECTION, DIRECTION_OPENING);
    while (get_state() != STATE_OPEN)
    // int x = 0;
    // while (x < 500)
    {
      //x++;
      digitalWrite(PIN_PULSE, HIGH);
      delayMicroseconds(MOVE_DELAY);
      digitalWrite(PIN_PULSE, LOW);
      delayMicroseconds(MOVE_DELAY);
      long lCurrent = millis();
      if (lCurrent - lStart >= MAX_DURATION)
      {
        Serial.println("Door opening takes too long => stop");
        return;
      }
    }
  }
}

void close_door()
{
  stop();
  if (get_state() == STATE_CLOSED)
  {
    return;
  }
  else
  {
    long lStart = millis();
    start();
    digitalWrite(PIN_DIRECTION, DIRECTION_CLOSING);
    while (get_state() != STATE_CLOSED)
    {
      digitalWrite(PIN_PULSE, HIGH);
      delayMicroseconds(MOVE_DELAY);
      digitalWrite(PIN_PULSE, LOW);
      delayMicroseconds(MOVE_DELAY);
      long lCurrent = millis();
      if (lCurrent - lStart >= MAX_DURATION)
      {
        Serial.println("Door closing takes too long => stop");
        return;
      }
    }
  }
}

void move()
{
  start();

  if (get_state() == STATE_CLOSED)
  {
    digitalWrite(PIN_DIRECTION, DIRECTION_OPENING);
  }
  else if (get_state() == STATE_OPEN)
  {
    digitalWrite(PIN_DIRECTION, DIRECTION_CLOSING);
  }
  else
  {
    Serial.println("Invalid state for this operation. Door must be open or closed in order to test.");
    return;
  }
  for (int i = 0; i < 5 * STEPS_PER_REVOLUTION; i++)
  {
    digitalWrite(PIN_PULSE, HIGH);
    delayMicroseconds(MOVE_DELAY * 4);
    digitalWrite(PIN_PULSE, LOW);
    delayMicroseconds(MOVE_DELAY * 4);
  }

  digitalWrite(PIN_DIRECTION, !digitalRead(PIN_DIRECTION));
  for (int i = 0; i < 5 * STEPS_PER_REVOLUTION; i++)
  {
    digitalWrite(PIN_PULSE, HIGH);
    delayMicroseconds(MOVE_DELAY * 4);
    digitalWrite(PIN_PULSE, LOW);
    delayMicroseconds(MOVE_DELAY * 4);
  }
}

void callback(char *topic, byte *payload, unsigned int length)
{
  Serial.println(payload[0]);
  Serial.print("Command from MQTT broker is: [");
  Serial.print(topic);
  Serial.print(": ");
  int iPayload = (char)payload[0] - '0';
  Serial.println(iPayload);

  Serial.print("]");
  switch (iPayload)
  {
  case COMMAND_OPEN:
    open_door();
    break;
  case COMMAND_CLOSE:
    close_door();
    break;
  case COMMAND_MOVE:
    move();
    break;
  case COMMAND_STOP:
    stop();
    break;
  case COMMAND_GET_STATE:
    break;
  }
  int iState = get_state();
  Serial.println(iState);
  String sState = String(iState);
  sState.toCharArray(cState, sState.length() + 1);
  client.publish("/huehnerhaus/legenest/status", cState, true);
}

void reconnect()
{
  // Loop until we're reconnected
  while (!client.connected())
  {
    Serial.print("Attempting MQTT connection...");

    // Attempt to connect
    if (client.connect(clientId, USER_NAME, PW))
    {
      Serial.println("connected");
      //once connected to MQTT broker, subscribe command if any
      client.subscribe(SUBSCRIBTION_CHANNEL);
    }
    else
    {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 6 seconds before retrying
      delay(6000);
    }
  }
}

void setup()
{
  Serial.begin(9600);
  Serial.println("Starting up...");
  pinMode(PIN_DOOR_CLOSED_SWITCH, INPUT_PULLUP);
  pinMode(PIN_DOOR_OPEN_SWITCH, INPUT_PULLUP);
  pinMode(PIN_PULSE, OUTPUT);
  pinMode(PIN_DIRECTION, OUTPUT);
  pinMode(PIN_ENABLE, OUTPUT);
  //Serial.begin(9600); //115200
  setup_wifi();
  client.setServer(MQTT_SERVER, 1883);
  client.setCallback(callback);
}

void loop()
{
  //Reconnect if WiFi-Connection was lost
  //-------------------------------------
  long lTime1 = millis();
  if((lTime1-lTime2) > 3000) {
    if (WiFi.status() != WL_CONNECTED) {
      lTime2 = lTime1;
      setup_wifi();
    }
  }
  //-------------------------------------

  //Reconnect to MQTT-Server if connection was lost
    //-------------------------------------
  if (!client.connected())
  {
    reconnect();
  }
  //-------------------------------------

  client.loop();
}aste code here

Moving door…

3 Likes

Hi Pete,

I also have a shutter door based on a timer clock. Where you able to reuse the existing hardware and create a home assistant based controller on it ?

Kr,

Bart

Hi Bart

I integrated the door with mqtt to open and close it. In order not to burn out the motors, I disabled its power using a relay integrated with esphome…