// Датчик освещения на ATtiny45
// 16.09.2018
// Roman Kotelnirov

#include    // Библиотека работы с EEPROM-памятью
#include   // Библиотека защиты от дребезга

#define SWITCH0_PIN 0 //Кнопка выбора порога включения (при отключенном искуственном освещения) 
#define SWITCH1_PIN 1 //Кнопка выбора порога отключения (при включенном искуственном освещении))
#define LDR_PIN 3     //Фоторезистор
#define REL_PIN 4     //Реле

#define POROG0_EM 1    //Адрес памяти, где будет хранится младший байт порога 0, соответственно старший байт +1
#define POROG1_EM 3    //Адрес памяти, где будет хранится младший байт порога 1, соответственно старший байт +1

int porog0;           //Порог включения
int porog1;           //Порог отключения
int d=50;             // Защита от "дребезга"
bool threshold = false; // Флаг наличия темноты (если true, то темно и нужно включать свет)
int lightness;   

Bounce b0 = Bounce();   // Объекты работы с кнопкой (для процедуры защиты от дребезга)
Bounce b1 = Bounce();   // Объекты работы с кнопкой (для процедуры защиты от дребезга)

void setup() {
  // Определяем назначение выходов
  pinMode(SWITCH0_PIN, INPUT);
  pinMode(SWITCH1_PIN, INPUT);
  pinMode(LDR_PIN, INPUT);
  pinMode(REL_PIN, OUTPUT);
   
  b0.attach(SWITCH0_PIN);     // объект Bounce будет слушать кнопку на пине switchPin
  b0.interval(10);            // устанавливаем время задержки в [мс]
  b1.attach(SWITCH1_PIN);     // объект Bounce будет слушать кнопку на пине switchPin
  b1.interval(10);            // устанавливаем время задержки в [мс]
  porog0 = (EEPROM.read(POROG0_EM+1) << 8 | EEPROM.read(POROG0_EM));//Считываем значение порога отключения (два байта, старший и младший)
  porog1 = (EEPROM.read(POROG1_EM+1) << 8 | EEPROM.read(POROG1_EM));// Считываем значение порога включения (два байта, старший и младший)
  mignled (3); //Мигнуть для наглядности 3 раза
}

void loop() {
    if (b0.update() && b0.read() == 1) {                  // Если было нажатие кнопки 0 (порог включения)
      digitalWrite(REL_PIN,LOW);                          // Замер должен быть при отключенном свете (так как порог будет использоваться для включения)
      delay(1000);                                        // Подождем когда утихнут переходные процессы (для большинства систем не обязательно)
      porog0 = analogRead(LDR_PIN);      // Устанавливаем порог включения (при отключенном свете!)                                      
      EEPROM.write(POROG0_EM, lowByte(porog0));           //Записываем младший байт значения порога включеня
      EEPROM.write(POROG0_EM + 1, highByte(porog0));      //Записываем младший байт значения порога включени
                                                          // Проверяем, чтобы сразу не отключилось                                                            
      digitalWrite(REL_PIN,HIGH);                         // Замер должен быть при включенном свете
      delay(1000);
      lightness = analogRead(LDR_PIN);                    // Считываем значение освещенности.
      if (porog1 < lightness+d);   {                      // Проверяем, требуется ли корректировка верхнего порога
          porog1 = lightness+d;                           // Корректируем 
          if (porog1>1023) porog1=1023;                   // Защита от переполнения          
          EEPROM.write(POROG1_EM, lowByte(porog1));       //Записываем младший байт значение верхнего отключения
          EEPROM.write(POROG1_EM + 1, highByte(porog1));  //Записываем старший байт значение верхнего отключения
      }
      mignled (1);    
      threshold = true;
    }
    
    if (b1.update() && b1.read() == 1) {                    // Если было нажатие кнопки 1 (порог отключения)
      digitalWrite(REL_PIN,HIGH);                           // Замер должен быть при включенном свете (так как порог будет использоваться для отключения)
      delay(1000);
      porog1 = analogRead(LDR_PIN);                         // Считываем значение освещенности.
      EEPROM.write(POROG1_EM, lowByte(porog1));             //Записываем младший байт значение верхнего порога
      EEPROM.write(POROG1_EM + 1, highByte(porog1));        //Записываем старший байт значение верхнего порога
      digitalWrite(REL_PIN,LOW);                            // ну и отключаем свет
      lightness = analogRead(LDR_PIN);                      // Считываем значение освещенности 
      if (porog0 > lightness-d);   {                        // Проверяем, требуется ли корректировка нижнего порога
        porog0 = lightness-d;
        if (lightness<0) porog0=0;                          // Если да, то проверяем можно ли добавить запасс     
        EEPROM.write(POROG0_EM, lowByte(porog0));           //Записываем младший байт значения порога включеня
        EEPROM.write(POROG0_EM + 1, highByte(porog0));      //Записываем младший байт значения порога включени
      }
      mignled (3);
      threshold = false;
    }

lightness = analogRead(LDR_PIN);                  // Считываем значение освещенности  

 if (threshold) {                                       //Свет включен (режим "темно")
          if (lightness > porog1) {                     // Если текущий режим "темно", т.е. горит искуственное освещение и общая освещенность стала выше верхнего порога,
              threshold = false;                        // то отменяем режим "темно",
              digitalWrite(REL_PIN, LOW);               // и отключим свет
          }
      }
      else {                                        //Свет отключен режим "светло")
          if (lightness < porog0) {                 // Если текущий режим не "темно" (т.е. светло и искуственное освещение выключено) и общая освещенность стала ниже нижнего порога, 
            threshold = true;                       //считаем что стало "темно"
            digitalWrite(REL_PIN, HIGH);            // и включаем свет
       }
      }      
 }

void mignled (int n){ // Мигнуть светодиодом n раз
  for (int i = 1; i<=n;i++){
  digitalWrite(REL_PIN,LOW); 
  delay (1000);
  digitalWrite(REL_PIN,HIGH); 
  delay (1000);
  }
}