// --- Определение пинов Arduino ---
// Мотор драйвер (TA6586)
const int motorIn1Pin    = 12; // Пин для управления направлением 1 (например, открыть)
const int motorIn2Pin    = 11; // Пин для управления направлением 2 (например, закрыть)
//const int motorEnablePin = 4; // Пин для включения/выключения мотора (ENA/ENB на TA6586)
// Датчики Холла (концевики)
const int doorOpenSensorPin   = 3; // LOW, когда дверца полностью ОТКРЫТА
const int doorClosedSensorPin = 2; // LOW, когда дверца полностью ЗАКРЫТА
// Кнопки ручного управления
const int buttonOpenPin  = 7; // Кнопка "Открыть", LOW при нажатии (с INPUT_PULLUP)
const int buttonClosePin = 6; // Кнопка "Закрыть", LOW при нажатии (с INPUT_PULLUP)
// Фоторезистор (LDR)
const int ldrPin = A7; // Аналоговый пин для чтения освещенности
// LED для индикации (например, встроенный на D13)
const int statusLedPin = 13;
// --- Настройки и пороги ---
// Пороги освещенности (значения A0 от 0 до 1023)
// Эти значения нужно будет откалибровать на месте!
// Чем выше значение, тем светлее.
const int dawnThreshold = 700; // Порог для рассвета (дверь открывается)
const int duskThreshold = 300; // Порог для сумерек (дверь закрывается)
// Важно: dawnThreshold должен быть больше duskThreshold для гистерезиса,
// чтобы избежать быстрого открытия/закрытия при пограничной освещенности.
const long motorTimeoutMs = 30000; // Максимальное время работы мотора в одну сторону (30 секунд)
                                  // Если датчик не сработает за это время, мотор остановится.
const long debounceDelay = 50;    // Задержка для подавления дребезга кнопок (мс)
// --- Переменные состояния ---
// Состояния дверцы
enum DoorState {
  DOOR_OPEN,        // Дверца полностью открыта
  DOOR_CLOSED,      // Дверца полностью закрыта
  DOOR_OPENING,     // Дверца открывается
  DOOR_CLOSING,     // Дверца закрывается
  DOOR_STOPPED_MID  // Дверца остановлена в промежуточном положении (например, после ручного управления)
};
DoorState currentDoorState = DOOR_STOPPED_MID; // Начальное состояние неизвестно, будет откалибровано
// Режим управления
enum ControlMode {
  MODE_AUTOMATIC, // Автоматическое управление по освещенности
  MODE_MANUAL     // Ручное управление кнопками
};
ControlMode currentControlMode = MODE_AUTOMATIC; // Начинаем в автоматическом режиме
// Переменные для отслеживания времени (для таймаутов и дребезга)
unsigned long motorStartTime = 0;
unsigned long lastButtonOpenPressTime = 0;
unsigned long lastButtonClosePressTime = 0;
// --- Функции управления мотором ---
// Остановить мотор
void motorOff() {
  //digitalWrite(motorEnablePin, LOW); // Отключить EN пин драйвера
  digitalWrite(motorIn1Pin, LOW);    // Установить оба пина направления в LOW
  digitalWrite(motorIn2Pin, LOW);    // для предотвращения нежелательного движения
  Serial.println("Мотор остановлен.");
}
// Запустить мотор на открытие дверцы
void startOpeningDoor() {
  if (currentDoorState == DOOR_OPENING || digitalRead(doorOpenSensorPin) == LOW) {
    // Уже открывается или уже открыта
    return;
  }
  motorStartTime = millis(); // Записываем время начала движения для таймаута
  digitalWrite(motorIn1Pin, HIGH); // Установить направление 1 (проверьте, соответствует ли открытию)
  digitalWrite(motorIn2Pin, LOW);
  //digitalWrite(motorEnablePin, HIGH); // Включить EN пин драйвера
  currentDoorState = DOOR_OPENING;
  Serial.println("Дверца начинает ОТКРЫВАТЬСЯ...");
  digitalWrite(statusLedPin, HIGH); // Включить LED во время движения
}
// Запустить мотор на закрытие дверцы
void startClosingDoor() {
  if (currentDoorState == DOOR_CLOSING || digitalRead(doorClosedSensorPin) == LOW) {
    // Уже закрывается или уже закрыта
    return;
  }
  motorStartTime = millis(); // Записываем время начала движения для таймаута
  digitalWrite(motorIn1Pin, LOW);
  digitalWrite(motorIn2Pin, HIGH); // Установить направление 2 (проверьте, соответствует ли закрытию)
  //digitalWrite(motorEnablePin, HIGH); // Включить EN пин драйвера
  currentDoorState = DOOR_CLOSING;
  Serial.println("Дверца начинает ЗАКРЫВАТЬСЯ...");
  digitalWrite(statusLedPin, HIGH); // Включить LED во время движения
}
// --- Setup: Инициализация ---
void setup() {
  Serial.begin(9600); // Инициализация последовательного порта для отладки
  Serial.println("--- Контроллер дверцы курятника запущен ---");
  // Установка режимов работы пинов
  pinMode(motorIn1Pin, OUTPUT);
  pinMode(motorIn2Pin, OUTPUT);
  //pinMode(motorEnablePin, OUTPUT);
  pinMode(doorOpenSensorPin, INPUT_PULLUP);      // Датчики Холла (предполагаем активный HIGH)
  pinMode(doorClosedSensorPin, INPUT_PULLUP);    // Если нужны подтягивающие резисторы, используйте INPUT_PULLUP
  pinMode(buttonOpenPin, INPUT_PULLUP);   // Кнопки с внутренними подтягивающими резисторами
  pinMode(buttonClosePin, INPUT_PULLUP);  // (нажатие кнопки дает LOW)
  pinMode(statusLedPin, OUTPUT);
  // Изначально выключить мотор
  motorOff();
  // Калибровка при запуске: пытаемся закрыть дверцу, чтобы знать её начальное положение
  Serial.println("Выполнение начальной калибровки: попытка закрыть дверцу...");
  startClosingDoor();
  unsigned long calibrationStartTime = millis();
  while (digitalRead(doorClosedSensorPin) == HIGH && (millis() - calibrationStartTime < motorTimeoutMs)) {
    // Ждем, пока дверца закроется или истечет таймаут
    delay(50); // Небольшая задержка для предотвращения чрезмерного использования CPU
  }
  motorOff(); // Остановить мотор после калибровки
  if (digitalRead(doorClosedSensorPin) == LOW) {
    currentDoorState = DOOR_CLOSED;
    Serial.println("Калибровка завершена: Дверца ЗАКРЫТА.");
  } else {
    currentDoorState = DOOR_STOPPED_MID; // Не удалось закрыть до конца
    Serial.println("Калибровка НЕ завершена: Дверца не достигла ЗАКРЫТОГО состояния или таймаут.");
    Serial.println("Пожалуйста, проверьте механику или концевики.");
  }
  currentControlMode = MODE_AUTOMATIC; // После калибровки переходим в автоматический режим
}
// --- Loop: Основной цикл программы ---
void loop() {
  // --- Чтение текущих состояний датчиков ---
  int ldrValue = analogRead(ldrPin);
  bool isDoorOpenSensorActive = (digitalRead(doorOpenSensorPin) == LOW);
  bool isDoorClosedSensorActive = (digitalRead(doorClosedSensorPin) == LOW);
  // --- Обработка кнопок ручного управления (с подавлением дребезга) ---
  bool buttonOpenIsPressed = !digitalRead(buttonOpenPin); // LOW при нажатии
  bool buttonCloseIsPressed = !digitalRead(buttonClosePin); // LOW при нажатии
  if (buttonOpenIsPressed && (millis() - lastButtonOpenPressTime > debounceDelay)) {
    lastButtonOpenPressTime = millis();
    Serial.println("Нажата кнопка: ОТКРЫТЬ");
    currentControlMode = MODE_MANUAL; // Переходим в ручной режим
    if (currentDoorState != DOOR_OPENING && !isDoorOpenSensorActive) {
      startOpeningDoor();
    } else if (currentDoorState == DOOR_STOPPED_MID) { // Если остановили в середине, можно продолжить
      startOpeningDoor();
    }
  }
  if (buttonCloseIsPressed && (millis() - lastButtonClosePressTime > debounceDelay)) {
    lastButtonClosePressTime = millis();
    Serial.println("Нажата кнопка: ЗАКРЫТЬ");
    currentControlMode = MODE_MANUAL; // Переходим в ручной режим
    if (currentDoorState != DOOR_CLOSING && !isDoorClosedSensorActive) {
      startClosingDoor();
    } else if (currentDoorState == DOOR_STOPPED_MID) { // Если остановили в середине, можно продолжить
      startClosingDoor();
    }
  }
  // --- Логика работы дверцы в зависимости от состояния ---
  switch (currentDoorState) {
    case DOOR_OPENING:
      if (isDoorOpenSensorActive) {
        motorOff();
        currentDoorState = DOOR_OPEN;
        Serial.println("Дверца полностью ОТКРЫТА.");
        digitalWrite(statusLedPin, LOW); // Выключить LED
        currentControlMode = MODE_AUTOMATIC; // Возвращаемся в авторежим после достижения концевика
      } else if (millis() - motorStartTime > motorTimeoutMs) {
        motorOff();
        currentDoorState = DOOR_STOPPED_MID; // Ошибка или застряла
        Serial.println("ОШИБКА: Таймаут открытия дверцы!");
        digitalWrite(statusLedPin, LOW); // Выключить LED
      }
      break;
    case DOOR_CLOSING:
      if (isDoorClosedSensorActive) {
        motorOff();
        currentDoorState = DOOR_CLOSED;
        Serial.println("Дверца полностью ЗАКРЫТА.");
        digitalWrite(statusLedPin, LOW); // Выключить LED
        currentControlMode = MODE_AUTOMATIC; // Возвращаемся в авторежим после достижения концевика
      } else if (millis() - motorStartTime > motorTimeoutMs) {
        motorOff();
        currentDoorState = DOOR_STOPPED_MID; // Ошибка или застряла
        Serial.println("ОШИБКА: Таймаут закрытия дверцы!");
        digitalWrite(statusLedPin, LOW); // Выключить LED
      }
      break;
    case DOOR_OPEN:
      // Если дверца открыта, и мы в автоматическом режиме, проверяем сумерки
      if (currentControlMode == MODE_AUTOMATIC && ldrValue < duskThreshold) {
        Serial.print("Сумерки (LDR: "); Serial.print(ldrValue); Serial.println("). Инициирую закрытие.");
        startClosingDoor();
      }
      break;
    case DOOR_CLOSED:
      // Если дверца закрыта, и мы в автоматическом режиме, проверяем рассвет
      if (currentControlMode == MODE_AUTOMATIC && ldrValue > dawnThreshold) {
        Serial.print("Рассвет (LDR: "); Serial.print(ldrValue); Serial.println("). Инициирую открытие.");
        startOpeningDoor();
      }
      break;
    case DOOR_STOPPED_MID:
      // В этом состоянии дверца будет ждать ручного управления или условий авторежима,
      // если она была остановлена из-за таймаута или ручной остановки.
      // Если в автоматическом режиме, и условия изменились, может начать движение.
      // Если была ручная остановка, то currentControlMode будет MANUAL, и нужно ручное вмешательство.
      break;
  }
  // Вывод текущего значения LDR для отладки
  // Serial.print("LDR: "); Serial.print(ldrValue);
  // Serial.print(", State: ");
  // switch (currentDoorState) {
  //   case DOOR_OPEN: Serial.print("OPEN"); break;
  //   case DOOR_CLOSED: Serial.print("CLOSED"); break;
  //   case DOOR_OPENING: Serial.print("OPENING"); break;
  //   case DOOR_CLOSING: Serial.print("CLOSING"); break;
  //   case DOOR_STOPPED_MID: Serial.print("STOPPED_MID"); break;
  // }
  // Serial.print(", Mode: ");
  // Serial.println(currentControlMode == MODE_AUTOMATIC ? "AUTO" : "MANUAL");
  delay(100); // Небольшая задержка для стабильности и снижения нагрузки на CPU
}