Умный санузел

Piglet
Piglet аватар
Offline
Зарегистрирован: 12.02.2017

Здравствуйте! Задался целью сделать автоматику против протечки в с/у и заодно прикрутить пару плюшек. Пока детали едут из Китая попробовал набросать скетч. Необходимо еще как то прикрутить обмен данными с NodeMCU по последовательному порту. С этим пока разбираюсь как вообще это происходит. Понимаю, что ужас полный, но это моя первая проба пера. Критика приветствуется.

#include <DHT.h>

volatile int waterAl_1 = 2;   // датчик протечки 1
volatile int waterAl_2 = 3;   // датчик протечки 2
int waterAl_3 = 4;   // датчик протечки 3
int light_WC = 5;     // датчик освещенности в туалете
int light_bath  = 6; //датчик освещенности в ванной
int higro = 7;             // датчик температуры и влажности
int relay_1 = 8;         // реле1 ХВС
int relay_2 = 9;         // реле2 ГВС
int relay_3 = 10;      // реле3 вентилятора в ванной
int relay_4 = 11;      // реле4 вентилятора в туалете
int ir_WC = 12;         // датчик движения  в туалете
int ir_bath = 13;      // датчик движения в ванной
int time_in = 14;      // получение времени (сигнал с1ч до4часов)
int alarm_in = 15;    // сигнал с дистанционки на выключение
int alarm_out = 16;// сигнал на NodeMcu об аварии
int gigro_out = 17; // данные температуры и влажности на NodeMcu
float temp = 0;       // переменная хранения теvпературы
float hum = 0;         // переменная хранения влажности
int al_out = 0;          // переменная значения протечки воды
boolean lightOn = false;                     // переменная счетчика цикла влажности в ванной
int hum_tmp = 50;  // переменная начального значения влажности
int hum_diff = 0;      // переменная разницы влажности за отрезок времени
boolean lightOnWC = false;          // переменная счетчика времени в туалете
boolean fanOnWC = false;           // переменная для включения вентилятора в ванной
unsigned long currentMillisLightBath = 0;     //Текущее значение счетчика времени включениясвета в ванной
unsigned long previousMillisLightBath = 0;     //Начальное значение счетчика времени включениясвета в ванной
unsigned long intervalLightBath = 180000;     //Интервал времени включенного света в ванной мсек.
unsigned long diffMillisWC = 60000;
unsigned long currentMillisWC = 0;
unsigned long previousMillisWC = 0;
unsigned long perWaterMillis = 4200000000;    // максимальное значение 4 294 967 295
unsigned long currentWaterMillis = 0;
int timeNight = 0;               // Надо как то получить с последовательного порта от NodeMcu
int alarm = 0;

DHT dht(higro, DHT22); // Создаем объект DHT

void setup() {
  pinMode(waterAl_1, INPUT);           // назначить выводу порт ввода датчика протечки 1
  digitalWrite(waterAl_1, LOW);       // включить подтягивающий резистор на землю

  pinMode(waterAl_2, INPUT);           // назначить выводу порт ввода датчика протечки2
  digitalWrite(waterAl_2, LOW);       // включить подтягивающий резистор на землю

  pinMode(waterAl_3, INPUT);           // назначить выводу порт ввода датчика протечки 3
  digitalWrite(waterAl_3, LOW);       // включить подтягивающий резистор на землю

  pinMode(light_WC, INPUT);           // назначить выводу порт ввода датчика освещения туалета
  digitalWrite(light_WC, LOW);      // включить подтягивающий резистор на землю

  pinMode(light_bath, INPUT);           // назначить выводу порт ввода датчика освещения ванны
  digitalWrite(light_bath, LOW);       // включить подтягивающий резистор на землю

  pinMode(higro, INPUT);           // назначить выводу порт ввода датчика температуры и влажности
  digitalWrite(higro, LOW);       // включить подтягивающий резистор на землю

  pinMode(ir_WC, INPUT);           // назначить выводу порт ввода датчика движения в туалете
  digitalWrite(ir_WC, LOW);       // включить подтягивающий резистор на землю

  pinMode(ir_bath, INPUT);           // назначить выводу порт ввода датчика движения в ванной
  digitalWrite(ir_bath, LOW);       // включить подтягивающий резистор на землю

  pinMode(relay_1, OUTPUT);          // назначить выводу порт вывода реле 1
  digitalWrite(relay_1, LOW);          // подаем изначально низкое напряжение

  pinMode(relay_2, OUTPUT);          // назначить выводу порт вывода реле 2
  digitalWrite(relay_2, LOW);          // подаем изначально низкое напряжение

  pinMode(relay_3, OUTPUT);          // назначить выводу порт вывода реле 3
  digitalWrite(relay_3, LOW);          // подаем изначально низкое напряжение

  pinMode(relay_4, OUTPUT);          // назначить выводу порт вывода реле 4
  digitalWrite(relay_4, LOW);          // подаем изначально низкое напряжение

  Serial.begin(9600);                          // Инициируем последовательный порт на скорости 9600 бит/с
  dht.begin();                                         // Вызов объекта dht

 attachInterrupt(2, waterAlarm, RISING);  // Прерывание при срабатывании датчика протечки 1
 attachInterrupt(3, waterAlarm, RISING);  // Прерывание при срабатывании датчика протечки 2

}

void loop() {
  waterAlarm();
  DHT_Function();
  fanBathHum();
  fanWC();
  Alarm();
}

// Функция считывания и присвоения данных температуры и влажности переменным
void DHT_Function() {                                       // Даем название функции
  float hum = dht.readHumidity();               // Считываем влажность
  float temp = dht.readTemperature();    // Считываем температуру
}

//Функция работы с датчиками протечки и приводами кранов
void waterAlarm() {                                                                            // Даем имя функции
  if (digitalRead(waterAl_1) == HIGH  || digitalRead(waterAl_2) == HIGH  || digitalRead(waterAl_3) == HIGH || digitalRead(alarm_in) == HIGH) {   // Если сработал какой то датчик протечки или сигнал на выключение, то
    digitalWrite(relay_1, LOW);                                                       // Выключаем реле крана ХВС
    digitalWrite(relay_2, LOW);                                                       // Выключаем реле крана ГВС
    digitalWrite(alarm_out, HIGH);                                                // Даем на пин 16 сигнал об аварии для NodeMcu
    al_out = 1;                                                                                        // Даем переменной аварии значение 1
  }
  else {                                                                                                   // Иначе
    digitalWrite(relay_1, HIGH);                                                      // Включаем реле крана ХВС
    digitalWrite(relay_2, HIGH);                                                      // Включаем реле крана ГВС
    digitalWrite(alarm_out, LOW);                                                // Даем на пин 16 сигнал об устранении аварии для NodeMcu
    al_out = 0;                                                                                       // Даем переменной аварии значение 0
  }
}

// Функция включения вентилятора в ванной по повышению влажности
void fanBathHum() {                                                                                 // Даем имя функции
  if (digitalRead(light_bath) == HIGH || lightOn == true) {                 // Если включен свет в ванной или принимали душ и вышли, то
        if (lightOn == false) {                                                                                            // Если счетчик цикла начальный, то 
          hum_tmp = hum;                                                                             // Записываем текущее значение влажности в буфер
          previousMillisLightBath = millis();                                           // Записываем текущее значение таймера работы программы
          }                                                                                                             // Конец условия счетчик цикла равен нулю
        currentMillisLightBath    = millis();                                                                        // Записываем текущее значение таймера работы программы
        if (currentMillisLightBath - previousMillisLightBath > intervalLightBath) {               // Проверяем не прошел ли нужный интервал, если прошел то
                      hum_diff = hum - hum_tmp;                                                                                            // Считаем изменение влажности за заданный интервал времени
                      lightOn = false;                                                                                         // Обнуляем счетчик цикла
         }                                                                                                             // Конец условия проверки заданного интервала
        else {lightOn = true;}                                                                                       // Меняем значение счетчика цикла на 1
  }                                                                                                                    // Конец условия включенного света в ванной 
  if (hum >= 80 || hum_diff >= 5) {                                                        // Если влажность более 80% или увеличение влажности более 5%, то
    digitalWrite(relay_3, HIGH);                                                           //  Включаем реле вентилятора в ванной
  }                                                                                                                 // Конец условия проверки влажности 80% или разницы в 5%
  else {                                                                                                       // Иначе, если влажность менее 80% или рост менее 5%
    if ( hum < 78 || hum_diff < -2){                                                       // Если влажность менее 78% или падение влажности более 2% то 
    digitalWrite(relay_3, LOW);                                                          // Вентилятор выключаем
    lightOn = false;
    }                                                                                                              // Конец условия проверки влажности 78% или падения на 2%
  }                                                                                                                // Конец условия  "Иначе, если влажность менее 80% или рост менее 5%"
}                                                                                                                  // Конец функции 

// Функция включения вентилятора в туалете по времени
void fanWC(){
   if (digitalRead(light_WC) == HIGH && digitalRead(ir_WC) == HIGH)  {
           if (lightOnWC == false) {                                                                                            // Если счетчик цикла начальный, то 
          previousMillisWC = millis();                                           // Записываем текущее значение таймера работы программы
          }                                                                                                             // Конец условия счетчик цикла равен нулю
          currentMillisWC    = millis();                                                                     // Записываем текущее значение таймера работы программы
         if (currentMillisWC - previousMillisWC > diffMillisWC) {               // Проверяем не прошел ли нужный интервал, если прошел то
                      lightOnWC = false;                                                                      // Обнуляем счетчик цикла
                      fanOnWC = true;
        }                                                                                                                       // Конец условия проверки заданного интервала
        else {lightOnWC = true;}                                                                        // Меняем значение счетчика цикла на 1
  }
    if (digitalRead(light_WC) == LOW && fanOnWC == true)  {
           if (lightOnWC == false) {                                                                                            // Если счетчик цикла начальный, то 
          previousMillisWC = millis();                                           // Записываем текущее значение таймера работы программы
          }                                                                                                             // Конец условия счетчик цикла равен нулю
          currentMillisWC    = millis();                                                                     // Записываем текущее значение таймера работы программы
         if (currentMillisWC - previousMillisWC > 180000) {               // Проверяем не прошли ли 3 минуты, если прошли, то
                      lightOnWC = false;                                                                      // Обнуляем счетчик цикла
                      fanOnWC =false;
        }                                                                                                                       // Конец условия проверки заданного интервала
        else {lightOnWC = true;}                                                                        // Меняем значение счетчика цикла на 1      
} 

if (fanOnWC == true) {
          digitalWrite(relay_4,HIGH);
}
else digitalWrite(relay_4,LOW);
}

// Функция сигнализации
void Alarm(){
 if (digitalRead(alarm_in) == HIGH && (digitalRead(light_WC) == HIGH || digitalRead(light_bath) == HIGH || digitalRead(ir_WC) == HIGH || digitalRead(ir_bath)) == HIGH) { alarm = 1;}
 else {alarm = 0;}
}
// Функция от закисания кранов.
void WaterRelayDelay(){
  currentWaterMillis = millis();
if (currentWaterMillis > perWaterMillis && timeNight == 1) {
    digitalWrite(relay_1, LOW);                                                       // Выключаем реле крана ХВС
    digitalWrite(relay_2, LOW);                                                       // Выключаем реле крана ГВС
    delay(60000);
    digitalWrite(relay_1, HIGH);                                                       // Включаем реле крана ХВС
    digitalWrite(relay_2, HIGH);                                                       // Включаем реле крана ГВС
}
}

 

arDubino
Offline
Зарегистрирован: 12.01.2017

ужас и есть.

делай 60000 говорит что в течение 60сек вернее минуты ваш счетч думает и в это время ничего не мониторить.

т.е. попадание потота в это момент его не остановит :)))

Piglet
Piglet аватар
Offline
Зарегистрирован: 12.02.2017

Это да, плохо. Но данная функция должна срабатывать раз в полтора месяца. А раз в полтора месяца остановка контроллера на минуту думаю не так уж и страшна. Тем более датчики протечки через прерывания должны сработать даже в этот момент.

А правда, что функция должна быть описана до ее вызова по листингу, или это как то несмертельно?

arDubino
Offline
Зарегистрирован: 12.01.2017

:)) не видел что она там у вас хз где вызвается. 

и вы уверены что даже если она и гдето вызвается то миллис может эти полтора месяца насчитать.

у меня просто сомнение что 16МГц хватит разрядности для счета не говоря о том что она там обнуляется по кругу. надо почитать мануалы какое ее значение макс дял вашей платы

valera678
Offline
Зарегистрирован: 04.11.2016

Piglet пишет:

А правда, что функция должна быть описана до ее вызова по листингу, или это как то несмертельно?

вообще не факт!  есть куча примеров когда описание функции позади вызова и все работает

Mr.Privet
Mr.Privet аватар
Offline
Зарегистрирован: 17.11.2015

valera678 пишет:

Piglet пишет:

А правда, что функция должна быть описана до ее вызова по листингу, или это как то несмертельно?

вообще не факт!  есть куча примеров когда описание функции позади вызова и все работает

говорили же 100 раз, по стандарту положено раньше, некоторые версии иде позволяют писать и ниже, но чтобв скетч компилировался в любой версии нужно писать выше

valera678
Offline
Зарегистрирован: 04.11.2016

пользуюсь 1.0.6 . в дальнейшем споре не вижу смысла