Управление светом и вентилятором в ванной, управление кранами.

Системы и компоненты "Умный дом"
Rex
Сообщения: 2
Зарегистрирован: 01 дек 2018, 16:15

Управление светом и вентилятором в ванной, управление кранами.

Сообщение Rex » 02 дек 2018, 19:29

Здравствуйте!
Хочу поделиться своими наработками. Я написал программу для управления освещением и вытяжкой в ванной, сделал сенсорное управление кранами на кухне и в ванной, а так же RGB светодиодной лентой для подсветки кухонного гарнитура.
Я только начинаю изучать Arduino и программирование так что не судите строго. Может кому то пригодится или знающие люди подскажут может можно как-то оптимизировать код программы.

Логика работы сенсоров кранов:
если поднести руки (или любой предмет) вода включится, после того как убрали руки вода выключится через 2 с. Если в зону действия сенсора на долго попал какой-то предмет, например поставили кастрюлю в раковину, вода выключится через 30 с. И включится только после того как предмет будет убран и сенсор будет активирован снова.

Логика управления освещением и вытяжкой:
при открытии двери свет включается и начинается выдержка 40 с до выключения света. Если фиксируется движение, начало выдержки обновляется. При закрытии двери начинается выдержка 5 с, при которой не фиксируется движение. Я добавил эту выдержку потому, что иногда при выходе из ванной и закрытии двери срабатывает датчик движения и включается свет, когда в ванной никого нет.
Когда защитная выдержка заканчивается, начинается фиксация движения. И если датчик движения сработал три раза в течении 40 с после первой сработки, свет останется включенным до открытия двери.
После закрытия двери, если нет движения, свет выключится через 15 с.

Управление RGB лентой и её блоком питания я сделал с помощью переменного резистора. Программный код, с некоторыми переделками, я взял с сайта http://alexgyver.ru/arduino-algorithms/

В своём проекте я использовал Arduino Nano.

Код: Выделить всё

#define SENSOR1_PIN 2            //вход управления 1м электроклапаном
#define SENSOR2_PIN 3            //вход управления 2м электроклапаном
#define FLAP1_PIN 4              //выход управления 1м электроклапаном
#define FLAP2_PIN 5              //выход управления 2м электроклапаном
#define GERKON_PIN 6             //вход геркон
#define SENSOR_PIN 7             //вход датчик движения
#define LAMP_PIN 8               //выход управления освещением
#define R_PIN 9                  //выход управления красным цветом
#define G_PIN 10                 //выход управления зеленым цветом
#define B_PIN 11                 //выход управления голубым цветом
#define RGB_POWER 12             //выход вкл/выкл БП для RGB
#define FAN_BUTTON_PIN 15        //вход управления вентилятором (кнопка)
#define FAN_PIN 16               //выход управления вентилятором
#define DEBOUNCE_DELAY 100       //время антидребезга кнопки вентилятора в мс
#define FAN_ON_TIME 10           //время работы вентилятора после выкл. света, мин
#define ON_FLAP1_ON 30           //время работы 1го клапана при активации сенсора, сек
#define ON_FLAP1_OFF 2           //время работы 1го клапана при деактивации сенсора, сек
#define ON_FLAP2_ON 30           //время работы 2го клапана при активации сенсора, сек
#define ON_FLAP2_OFF 2           //время работы 2го клапана при деактивации сенсора, сек
#define DEBOUNCE1_SENSOR 300     //задержка сработки для 1го электроклапана, мс
#define DEBOUNCE2_SENSOR 300     //задержка сработки для 2го электроклапана, мс
#define DELAY_LAMP_OFF_OPEN 40   //задержка выключения света после открытия двери, сек
#define DELAY_LAMP_OFF_CLOSE 15  //задержка выключения света после закрытия двери, сек
#define DELAY_DOOR_CLOSE 5       //задержка регистрации движения после закрытия двери, сек
#define DEBOUNCE_GERKON 80       //время антидребезга геркона в мс
#define INTERVAL 250             //интервал мигания светодиода индик. сработки датчика движения, мс

//переменные для управления кранами
unsigned long int timeSensor1On, timeSensor1Off, timeSensor2On, timeSensor2Off;
bool flap1On = false;      //переменная для хранения состояния 1го электроклапана
bool flap2On = false;      //переменная для хранения состояния 2го электроклапана
bool sensor1 = LOW;        //переменная для хранения состояния сенсора 1го электроклапана
bool sensor2 = LOW;        //переменная для хранения состояния сенсора 2го электроклапана
bool lastSensor1 = HIGH;   //переменная для хранения последнего состояния сенсора 1го электроклапана
bool lastSensor2 = HIGH;   //переменная для хранения последнего состояния сенсора 2го электроклапана
//////////////////////////////////////////////////////////////////////////////////

//переменные для управления освещением
bool lamp;           //переменная для хранения состояния освещения (вкл/выкл)
bool gerkon_flag;    //вспомогательная переменная для хранения состояния сработки геркона
bool sensor_flag;    //вспомогательная переменная для хранения состояния датчика движения
bool motionClose;    //переменная для индикации движения при закрытой двери
bool motionOpen;     //переменная для индикации движения при открытой двери
unsigned long doorClosedTime, doorOpenedTime, doorClosedDelay; //переменные для хранения времени момента закрытия и открытия двери
//переменные для функции светодиодной индикации сработки датчика движения
unsigned long int previousMillis = 0;
bool ledMotionState;
byte motionCount = 0;
////////////////////////////////////////////////////////////////////////////////////

//переменные для управления вентилятором
bool fanState;
bool fanButtonState;
bool lastFanButtonState;
unsigned long int lastDebounceTime = 0, fanButtonOffTime, workTime = (long)FAN_ON_TIME * 60 * 1000;
/////////////////////////////////////////////////////////////////////////////////////

//переменные для функции задержки (антидребезга) геркона
bool _bounse3S = 1;
bool _bounse3O = 1;
unsigned long _bounse3P = 0UL;
/////////////////////////////////////////////////////////////////////////////////////

//переменные для функций задержек (антидребезга) сенсоров электроклапанов
bool _bounse1S = 1;
bool _bounse1O = 1;
unsigned long _bounse1P = 0UL;
bool _bounse2S = 1;
bool _bounse2O = 1;
unsigned long _bounse2P = 0UL;
/////////////////////////////////////////////////////////////////////////////////////

//переменные для управления RGB
byte bright = 100; // яркость, от 0 до 100 (можно повесить на второй потенциометр при желании)
byte R, G, B;

void setup() {          //конфигурация портов (вход или выход)
  pinMode(SENSOR1_PIN, INPUT_PULLUP);   //подтягиваем вход к плюсу через внутренний резистор 20к
  pinMode(FLAP1_PIN, OUTPUT);
  pinMode(SENSOR2_PIN, INPUT_PULLUP);
  pinMode(FLAP2_PIN, OUTPUT);
  pinMode(GERKON_PIN, INPUT_PULLUP);
  pinMode(LAMP_PIN, OUTPUT);
  pinMode(SENSOR_PIN, INPUT);
  pinMode(FAN_BUTTON_PIN, INPUT_PULLUP);
  pinMode(FAN_PIN, OUTPUT);
  pinMode(R_PIN, OUTPUT);
  pinMode(G_PIN, OUTPUT);
  pinMode(B_PIN, OUTPUT);
  pinMode(RGB_POWER, OUTPUT);
  pinMode(13, OUTPUT);
}

//управление светодиодной лентой RGB (взято с сайта http://alexgyver.ru/arduino-algorithms/)
void rgbLed () {
  int colorPot = analogRead(0); // получаем значение с потенциометра (0 - 1023)
  // разбиваем диапазон 0 - 1023 на участки, и играемся с цветом согласно текущему значению
  if (colorPot >= 10) {  //если значение больше 10, вкл. БП, иначе выкл.
    digitalWrite(RGB_POWER, HIGH);
  } else {
    digitalWrite(RGB_POWER, LOW);
  }
  if (colorPot <= 10) {
    R = 0;
    G = 0;
    B = 0;
  } else if (colorPot > 10 && colorPot <= 20) {
    byte k = map(colorPot, 10, 20, 0, 255);
    R = 255;
    G = 255;
    B = 255;
  } else if (colorPot > 20 /*&& colorPot <= 145*/) {
    byte k = map(colorPot, /*10, 145*/20, 1023, 0, 255);
    R = 255 - k;
    G = 255 - k;
    B = 255 - k;
  } /*else if (colorPot > 145 && colorPot <= 290) {
    byte k = map(colorPot, 145, 290, 0, 255);
    R = 0;
    G = 0;
    B = k;
  } else if (colorPot > 290 && colorPot <= 435) {
    byte k = map(colorPot, 290, 435, 0, 255);
    R = 0;
    G = k;
    B = 255;
  } else if (colorPot > 435 && colorPot <= 580) {
    byte k = map(colorPot, 435, 580, 0, 255);
    R = k;
    G = 255;
    B = 255;
  } else if (colorPot > 581 && colorPot <= 725) {
    byte k = map(colorPot, 581, 725, 0, 255);
    R = 255 - k;
    G = k;
    B = 0;
  } else if (colorPot > 725 && colorPot <= 870) {
    byte k = map(colorPot, 725, 870, 0, 255);
    R = 0;
    G = 255 - k;
    B = k;
  } else if (colorPot > 870) {
    byte k = map(colorPot, 870, 1023, 0, 255);
    R = k;
    G = 0;
    B = 255 - k;
  }*/
  // подаём ШИМ на светодиод, учитывая яркость
  analogWrite(R_PIN, (bright * R / 100));
  analogWrite(G_PIN, (bright * G / 100));
  analogWrite(B_PIN, (bright * B / 100));
}

//функция вкл/выкл вентилятора
//вентилятор вкл/выкл кнопкой при включенном свете. После выключения света,
//если вентилятор был включен, он выключится через время FAN_ON_TIME
void fan(bool fanOff) {
  bool reading = !digitalRead(FAN_BUTTON_PIN);
  if (reading != lastFanButtonState) {
    lastDebounceTime = millis() + DEBOUNCE_DELAY;
  }
  if (lastDebounceTime <= millis()) {
    if (reading != fanButtonState) {
      fanButtonState = reading;
      if (!fanButtonState) {
        fanState = !fanState;
      }
    }
  }
  lastFanButtonState = reading;

  if (fanOff && fanState) {  //если свет выключился и вентилятор включен
    fanButtonOffTime = millis() + workTime;  //записываем время выключения света (с опережением millis())
  }
  if (fanButtonOffTime <= millis()) {  //если прошло время FAN_ON_TIME
    fanState = LOW;  //выключить вентилятор
  }
  digitalWrite(FAN_PIN, fanState);
}

//функция антидребезга для геркона
//сформирована в программе FLProg
bool bounseGerkon () {
  bool   _bounceTmpD1 =  digitalRead (GERKON_PIN);
  if (!_bounse3S)
  {
    if (millis() >= (_bounse3P + DEBOUNCE_GERKON))
    {
      _bounse3O =  _bounceTmpD1;
      _bounse3S = 1;
    }
  }
  else
  {
    if ( _bounceTmpD1 != _bounse3O )
    {
      _bounse3S = 0;
      _bounse3P = millis();
    }
  }
  return _bounse3O;
}

//------------------------функция управления освещением, начало---------------------------
/* Логики работы: открыли дверь - включился свет, начался отсчет выдержки. По окончании
  выдержки свет выключается, если при открытой двери есть движение, отсчет выдержки
  обновляется. Если закрыть дверь при включенном свете - начинается отсчет второй вы-
  держки, по истечении которой свет выключится. Если есть движение при закрытой двери
  и включенном свете и при сработке датчика движени три раза в течении DELAY_LAMP_OFF_OPEN, свет не выключится
  до следующего открывания двери не зависимо будет ещё срабатывать датчик движения или нет.
*/
void lite() {
  if (bounseGerkon () && !gerkon_flag) {   //если геркон разомкнулся (дверь открылась) и до этого был замкнут
    gerkon_flag = HIGH;  //изменение переменной (дверь была открыта)
    lamp = HIGH;  //включить свет
    motionClose = LOW;  //сброс индикатора движения
    doorOpenedTime = millis() + (long)DELAY_LAMP_OFF_OPEN * 1000;  //начало отсчета до выключения света при открытой двери
  }
  if (bounseGerkon () && gerkon_flag && digitalRead(SENSOR_PIN)) {  //если дверь открыта и есть движение
    lamp = HIGH;  //включить свет
    doorOpenedTime = millis() + (long)DELAY_LAMP_OFF_OPEN * 1000;  //обновление отсчета до выключения света при открытой двери
  }
  if (bounseGerkon () && gerkon_flag && doorOpenedTime <= millis()) {  //если дверь открыта и прошло время выдержки
    lamp = LOW;  //выключить свет
  }
  if (!bounseGerkon () && gerkon_flag) {  //если геркон замкнулся (дверь закрылась) и до этого он был разомкнут
    gerkon_flag = LOW;  //изменение переменной (дверь была закрыта)
    doorClosedTime = millis() + (long)DELAY_LAMP_OFF_CLOSE * 1000;  //начало отсчета до выключения света при закрытой двери
    doorClosedDelay = millis() + (long)DELAY_DOOR_CLOSE * 1000;  //начало задержки фиксации движения при закрытой двери
  }
  if (!bounseGerkon () && !gerkon_flag) {  //если дверь закрыта
    if (doorClosedDelay <= millis()) {  //и если прошло время задержки до выключения света
      if (digitalRead(SENSOR_PIN) && !sensor_flag) { //подсчет кол-ва сработок датчика движения при закрытой двери
        sensor_flag = HIGH;                          //для предотвращение ложного включения света до следующего
        motionCount ++;                              //открытия двери
        motionClose = HIGH;                          //
        if (!lamp) {  //если свет выключен
          lamp = HIGH;  //включить свет
          doorOpenedTime = millis() + (long)DELAY_LAMP_OFF_OPEN * 1000; //на время DELAY_LAMP_OFF_OPEN
        }
      }
      if (!digitalRead(SENSOR_PIN) && sensor_flag) {  //если датчик движения деактивировался
        sensor_flag = LOW;  //изменить переменную
      }
      if (motionCount >= 3) {
        motionCount = 3;  //ограничение кол-ва сработок датчика движения при закрытой двери до 3
      }
    }
  }
  //если дверь закрыта, прошло время до выключения света и счетчик сработок меньше трех
  if (!bounseGerkon () && !gerkon_flag && doorOpenedTime <= millis() && motionCount <= 2) {
    lamp = LOW;  //выключить свет
  }
  //если дверь закрыта и движения не было и прошло время до выключения света при закрытой двери
  if (!bounseGerkon () && !gerkon_flag && !motionClose && doorClosedTime <= millis()) {
    lamp = LOW;  //выключить свет
  }
  digitalWrite(LAMP_PIN, lamp);  //передать состояние переменной lamp на пин LAMP_PIN

  if (!lamp) {  //если свет выключен
    motionCount = 0;  //обнулить счетчик сработок датчика движения
  }

  //индикация сработки датчика движения
  //эту индикацию я сделал только для удобства мониторинга сработки датчика движения
  if (digitalRead(SENSOR_PIN)) {                //если сработал датчик движения
    digitalWrite(13, HIGH);    //включить светодиод
  } else {
    if (motionClose) {                               //мигание при сработке при закрытой двери
      if (millis() - previousMillis >= INTERVAL) {   //
        previousMillis = millis();                   //
        if (ledMotionState == LOW) {                 //
          ledMotionState = HIGH;                     //
        } else {                                     //
          ledMotionState = LOW;                      //
        }                                            //
        digitalWrite(13, ledMotionState);            //
      }                                              //
    } else {                 //при деактивации датчика движ., если не было сработки при закрытой двери,
      digitalWrite(13, LOW); //выключить светодиод
    }
  }
}
//------------------------функция управления освещением, конец---------------------------

//функция задержки сработки для 1го электроклапана
//сформирована в программе FLProg
bool bounse1flap () {
  bool   _bounceTmpD1 =  (digitalRead (SENSOR1_PIN));
  if (!_bounse1S)
  {
    if (millis() >= (_bounse1P + DEBOUNCE1_SENSOR))
    {
      _bounse1O =  _bounceTmpD1;
      _bounse1S = 1;
    }
  }
  else
  {
    if ( _bounceTmpD1 != _bounse1O )
    {
      _bounse1S = 0;
      _bounse1P = millis();
    }
  }
  return _bounse1O;
}

//функция задержки сработки для 2го электроклапана
//сформирована в программе FLProg
bool bounse2flap () {
  bool   _bounceTmpD1 =  (digitalRead (SENSOR2_PIN));
  if (!_bounse2S)
  {
    if (millis() >= (_bounse2P + DEBOUNCE2_SENSOR))
    {
      _bounse2O =  _bounceTmpD1;
      _bounse2S = 1;
    }
  }
  else
  {
    if ( _bounceTmpD1 != _bounse2O )
    {
      _bounse2S = 0;
      _bounse2P = millis();
    }
  }
  return _bounse2O;
}

//функция управления 1м краном
void flap1() {
  sensor1 = bounse1flap ();                      //считывание состояние сенсора 1 с задержкой
  if (sensor1 == LOW && lastSensor1 == HIGH) {   //если активен и последнее сост. - неактивен, то ...
    digitalWrite(FLAP1_PIN, HIGH);                //включаем 1й электроклапан
    lastSensor1 = LOW;                           //записываем последнее состояние сенсора 1
    timeSensor1On = millis() + (ON_FLAP1_ON * 1000);       //записываем время сработки сенсора 1 +
  }                                              //"опережаем время" на ON_FLAP1_ON для того,чтобы решить проблему
  //с переполнением millis() т.е. "опережение времени" на ON_FLAP1_ON и ON_FLAP1_OFF
  //(взято с сайта http://alexgyver.ru/arduino-algorithms/ от WakeUp4L1fe)

  if (sensor1 == HIGH && lastSensor1 == LOW) {   //если неактивен и последнее состояние сенсора 1 - активен
    timeSensor1Off = millis() + (ON_FLAP1_OFF * 1000);     //записываем время деактивации сенсора 1 +
    lastSensor1 = HIGH;                          //"опережаем время" на ON_FLAP1_OFF
  }
  if ((timeSensor1On <= millis() && sensor1 == LOW) ||   //если после активации сенсора 1 прошло время ON_FLAP1_ON
      (timeSensor1Off <= millis() && lastSensor1 == HIGH)) { //или если после деактивации сенсора 1 прошло время ON_FLAP1_OFF
    digitalWrite(FLAP1_PIN, LOW);   //то выключить кран
  }
}

//функция управления 2м краном
void flap2() {
  sensor2 = bounse2flap ();
  if (sensor2 == LOW && lastSensor2 == HIGH) {
    digitalWrite(FLAP2_PIN, HIGH);
    lastSensor2 = LOW;
    timeSensor2On = millis() + (ON_FLAP2_ON * 1000);
  }
  if (sensor2 == HIGH && lastSensor2 == LOW) {
    timeSensor2Off = millis() + (ON_FLAP2_OFF * 1000);
    lastSensor2 = HIGH;
  }
  if ((timeSensor2On <= millis() && sensor2 == LOW) ||
      (timeSensor2Off <= millis() && lastSensor2 == HIGH)) {
    digitalWrite(FLAP2_PIN, LOW);
  }
}

//основной цикл программы
void loop() {
  lite();
  fan(lamp);
  flap1();
  flap2();
  rgbLed ();
}


Вернуться в «Умный дом»

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 2 гостя