Защита от протечек. Проба пера

MIIIIIA
Offline
Зарегистрирован: 09.03.2017
Здравствуйте,
Очень хочется овладеть навыками схемотехники и программирования для Arduino.
Хотел начать с несложной, но полезной защиты от протечек.
На форуме масса примеров, но все очень навороченные, с которыми мне сразу не разобраться.
Итак, с чего я начал:
1. Arduino Uno

2. Моторизированный шаровый кран, 5-и проводной https://ru.aliexpress.com/item/1-2-DC12V-brass-2-way-electric-motorized-valve-NPT-BSP-automatic-ball-valve-5-wires/2041306163.html

3. Реле
 
Вот мой самый первый скетч (после мигания встроенным светодиодом):
int probe = 2; //датчик
int button = 4; //кнопка открытия
int rel_1 = 7; //реле in1
int rel_2 = 8; //реле in2
void setup() {
  Serial.begin(9600); //будем писать отладочную инфу, можно удалить
  pinMode(rel_1, OUTPUT); 
  pinMode(rel_2, OUTPUT);
  pinMode(probe, INPUT); 
  pinMode(button, INPUT);
  digitalWrite(probe, HIGH);
  digitalWrite(button, HIGH);

  digitalWrite(rel_1, LOW); //начальное состояние, 0
  digitalWrite(rel_2, LOW);
}


void loop() {
  if (digitalRead(probe) == LOW) {
  Serial.println(" Close ");
  digitalWrite(rel_1, HIGH); //включаем оба реле
  digitalWrite(rel_2, HIGH);
  
 }
  
 if (digitalRead(button) == LOW) {
  Serial.println(" Open ");
  digitalWrite(rel_1, LOW); //выключаем оба реле
  digitalWrite(rel_2, LOW);
  
 } 

}

Для самого начала почти достаточно.

Хотелось бы услышать бэстпрактис, что у меня уже категорически неправильно сделано и решить 1-ю проблему: при перезагрузке Ардуины или пропадании питания кран то пытается открыться, то закрыться, в зависимости от положения. Хочется чтобы без явной команды краны не трогались. Я так думаю, нужно использовать сигнальные провода крана и считывать положение крана или есть способ лучше?
 
Кроме того, поднабравшись опыта, нужно будет реализовать:
1. Борьбу с "дребезгом". (прочитал про аппаратные и программные способы, пока не понял что правильно для датчиков протечки (обычные прободные))
2. Контроль обрыва датчика. 
3. Звонок на телефон (заказан GSM модуль https://ru.aliexpress.com/item/mini-A6-GPRS-GSM-Module-Kit-Wireless-Exte...)
4. Закрытие при пропадании питания (при разрядке ИБП)
5. Переодическое закрытие
6. Контроль работоспособности (Watchdog)
Если подскажите что нужно еще и примеры реализации, то буду безмерно благодарен.
Спасибо.
 
arDubino
Offline
Зарегистрирован: 12.01.2017

опять с самого начала методология неверная.

1) нужен датчик протечки

2) там же есть сигнали открыт закрыт.

3) соответственно при включение проверяем а) датчик протечки б) если протечки нет проверяем датчик открыт закрыт если закрыт - открываем если открыт не трогаем. если протечка все наоборот и все.

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

сигнал по смс посылать только если протечка и потом проверять если закрылось то посылать сигнал протека-кран закрыт. если не закрылось проверили еще раз через несколько секунд. там же ест ьвермя закрытия. и если опять не закрылось мега сигнал протечка-кран НЕ закрыт. после этого бежать домой.

MIIIIIA
Offline
Зарегистрирован: 09.03.2017

arDubino,

спасибо, но мне нужно как для самых маленьких( а то я не догоняю. Датчик протечки есть, но проводной датчик - это просто 2 контакта. "Там сигналы" - это где, на кране? У меня же задано положение начальное digitalWrite(rel_1, LOW); но при перезагрузке кран открывается на некоторое время.

ПС

GSM пока еще нету, даже не думал про логику пока

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

на твоем кране ж есть сигналы открыто закрыто. ты когда покупал то смотрел что берешь??

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

BL YW видимо блек и еллоу т.е. черный и желтый провод. первый заземляется видимо когда открыто желтый закрыто.

земля на белый идет.

MIIIIIA
Offline
Зарегистрирован: 09.03.2017

arDubino пишет:

на твоем кране ж есть сигналы открыто закрыто. ты когда покупал то смотрел что берешь??

Да, конечно, я же об этом в первом посту писал. Мне не столь важно положение крана (на данном этапе), там есть концевики и кран сам себя отключает в райних положениях. У меня-то больше вопрос был почему он открывается если у него начальное состояние закрыт? Ну т.е. мне бы хотелось чтобы Ардуина не трогала кран если нет явного указания на это. Перезагружается она или зависла, вода ли на нее льется) Но если кран закрыт, то он закрыт.

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

видимо потому что реле дает таки ток :))) а ток оно дает потому что выводы при перегрузке в состоянии видимо 1 или 0. читай даташиты и смотри в реле что включает

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

MIIIIIA начинайте плясать от этой схемы. RD(красный) BK BL YW(желтый) WТ(белый) . WT на вывод GND BL и YW на вход ардуины RD - на 1 канал реле  BK на 2 канал реле.

MIIIIIA
Offline
Зарегистрирован: 09.03.2017

qwone,

спасибо, плясать начал. Я понимаю, что нужно (можно) использовать состояние крана. Но никак не соображу как именно. C логикой беда( 

Я читаю положение крана, если открыт, то реле в положение открыть, если закрыт, то реле закрыть. А далее как и было - если протечка, то закрыть. Если нажато "открыть", то открыть. Масло маслянное.

Тем более мне кажется правильнее чтобы основную часть времени ничего не проиходило. Т.е. ловим только состояние кнопок и датчиков - сработал датчик, закрыли кран и опять только ловим состояние. А у меня получается что сработал датчик и я постоянно в цикле пытаюсь закрыть кран, до тех пор пока не сработает другой датчик (кнопка), нет состояния ничегонеделанья.

Имеет ли смысл добавлять delay(100); // задержка для устранения дребезга после нажатия кнопок?

Еще вопрос, как правильнее делать: чтобы при включенном реле кран был открыт или закрыт? Если при включенном открыт, то хорошо, если ардуина сломается, то кран закроется, но когда реле под напряжением оно слегка греется (а в этом положении оно почти все время) и я вычитал, что оно может "залипнуть" и в ответственный момент не сработать (но и даже если не залипнуть, то под напряжением по-умолчанию это плохо)

Пробую осознать скетч от avton http://arduino.ru/forum/proekty/sistema-zashchity-ot-protechki-vody

 

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

MIIIIIA пишет:

Я читаю положение крана, если открыт, то реле в положение открыть, если закрыт, то реле закрыть. А далее как и было - если протечка, то закрыть. Если нажато "открыть", то открыть. Масло маслянное.

Ну во первых у крана не 2 состояния как у реле (открыто , закрыто), есть еще промежуточное . или промежуточные.  Опять же лучше рассматривать кран как объект у которого есть методы Открыть и Закрыть. То есть по команде Открыто  на движок подается положительное напряжение до тех пор пока не сработает концевик  Открыто. И это произойдет через 10 секунд, что для процессора вечность.  Метод Закрыто идет аналогично. На мотор подается Отрицательное напряжение до тех пор пока не сработает концевик Закрыто.  Вот для того что бы управлять мотором надо 2 пина управления 00 стоит движок 01 мотор работает в + 10 мотор в 2-"

Замечательно было бы если Концевики были на размыкание в крайних положениях .  Тогда просто собрали последовательну цепочку из мотора  2 выпрямительных диодов и концевиков.  Один концевик отрубает ток в + в конечном положении, а другой в -. Так что подать нужное направление напряжения и подождать секунд 10 к кран будет закрыт или открыт.   А так придется делать это программно. 

ПС: Хотя кран не ворота . Но алгоритм похож http://arduino.ru/forum/proekty/avtomaticheskie-vorota-garazha#comment-266538

MIIIIIA
Offline
Зарегистрирован: 09.03.2017

qwone пишет:

Замечательно было бы если Концевики были на размыкание в крайних положениях .  

На самом деле так и есть, мотором можно управлять 2-я проводами, в крайних положениях по 2 концевика: 1 размыкает цепь, 2-й сигнальный. У меня в 1-м посте как раз сигнальные концевики не задействованы. Я не имел в виду что мотор постоянно под напряжением.

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016
             +-- /  ---!>!--+
+/-  ----(M)-!              !------   -/+
             +-- /  ---!<!--+

                                                    ^  половинка диодного моста

Logik
Offline
Зарегистрирован: 05.08.2014

))) Эта наскальная живопись называется паралельное встречное включение диодов.

MIIIIIA
Offline
Зарегистрирован: 09.03.2017

Logik пишет:

))) Эта наскальная живопись называется паралельное встречное включение диодов.

ага, я понял. Я выше писал что так и реализовано.

MIIIIIA
Offline
Зарегистрирован: 09.03.2017

хм, месяц прошел, а я все еще не определился как же управлять реле. Посмотрел пример qwone но там все-таки немного не про то. Меня интересует именно реле. С мотором у меня все хорошо.

Еще раз повторюсь, что именно мне не нравится, может кто-то предложит свежее решение:

1. способ подключения вижу только один - 2 реле которые перекидывают контакты от мотора на +или-. Рассматривал еще вариант с 4 реле, где каждый модуль на 1 провод, но там вообще все чревато КЗ.

2. Если использовать реле в положении "выключено - кран закрыт", то почти все время обмотку реле необходимо держать под напряжением, что вроде как не очень хорошо.

3. Если использовать реле в положении "включено - кран закрыт", то есть риск, что при выходе из строя управляющего устройства, кран просто не закроется в ответственный момент.

Dejmos
Offline
Зарегистрирован: 19.02.2016

примерно с такой же системой вожусь, но у меня краны трехпроводные. Я использую транзисторные ключи.

Реле вполне можно использовать, и даже держать катушку под напряжением. Такие же реле в люстрах с дистанционным управлением и в других устройствах целыми днями работают. Можно конечно через минуту после подачи команды реле обесточивать. Ведь если мотор за это время не закрылся/открылся, то ему уже ничего не поможет.

 

У Ардуино есть энергонезависимая память EEPROM, в которую я записываю состояние мотора (открыт/закрыт), чтобы после внезапного отключения электричества знать, в каком состоянии я кран оставлял. Кроме того, электричество может пропасть в момент закрывания / открывания. Имеет смысл после включения электроэнергии закрыть кран, чтобы потом точно знать его состояние. И потом решить, надо его открыть или нет. Посмотрите алгоритмы работы фирменных систем

По последнему пункту: это может произойти и с фирменной системой. Выбирайте компоненты надежных фирм. Либо делать аналог Гидролок Виннер, который без внешнего контроллера обходится

 

afen
Offline
Зарегистрирован: 24.04.2017

Я для управления кранами использовал L298N   https://ru.aliexpress.com/item/L298N-Module-Dual-H-Bridge-Stepper-Motor-...

Вот мой скетч но тут много чего лишнего емкостной датчик под крышкой унитаза, ультразвуковой дальномер, MQ-7 как датчик дыма для обнаружения курильщиков и включения вентилятора esp8266 для передачи по WIFI для расширения входов исползуется 74HC165

есть в протеусе только не знаю как его сюда залить

//**************************************************************
//**************************************************************
//при открытых кранах пищит 1 раз в сек типа чтоб не забыли
//**************************************************************
#include "SoftwareSerial.h"
#include "CapacitiveSensor.h"
#include <SPI.h>
#include "Ultrasonic.h"
#include <EEPROM.h>
#include <avr/wdt.h>

//определим пины
#define pinWaterLeak  A0 
#define pinBuzzer A1   
#define pinHCSR04Trig A2
#define pinHCSR04Echo A3
#define pinLedOpen A4
#define pinLedClose A5
#define pinSmokeSensor A6
#define pinNC7 A7

#define pinLight 2     //свет
#define pinCooler 3    //вентилятор
#define pinCapSend 4          //емкостной датчик
#define pinCapReceive 5       //емкостной датчик
#define pinSoftRX 6       //софтовые пины для esp8266
#define pinSoftTX 7       //
#define pinMotorIN1 8
#define pinMotorIN2 9
#define pinSS 10     //использется для SPI 
#define pinMOSI 11   //использется для SPI
#define pinMISO 12   //использется для SPI
#define pinCLK 13    //использется для SPI

CapacitiveSensor   capToiletBowlSensor = CapacitiveSensor(pinCapSend,pinCapReceive);        // 10M resistor between pins 4 & 5, pin 5 is sensor pin, add a wire and or foil

#define ver "1.2.0.0"         //версия программы

long capSensor;
#define _maxCapSensor 100
boolean enableCapSensor = true;
boolean assSitToiletBowl = false;    //сидит ли жопа на унитазе ??

boolean enableSmokeSensor = true;   //разрешаем использование датчика для включения вентилятора
int smokeSensor = 0;   //показания датчика 
#define _maxSmokeSensor 100  //максимальные показания для срабаьывания вентилтилятора

#define _auto 1
#define _manual 0
byte verbose = 1;   //0-не пишем в serial ничего 1-пишем сообщения 2-пишем дистанцию непрерывно 3-
byte Mode = _auto;  //1 - автоматическое управление светом 0 - только с выключателя или с serial

//управление моторами
#define _valveStop 0    
#define _valveRun  1
#define _valveErr  2
byte ValveState = _valveStop;    //состояние моторов крутяться, стоят, не дошли до концевых за отведенное время
#define freqBuzzer 1000   //пикаем на частоте гц
//управление светом и вентилятором
#define _distanceLightOn  60  //дистанция для включения света 
#define _distanceCoolerOn  5  //дистанция для включения вентилятора
#define _countLight 3
#define _countCooler 3
short cntLightOn = _countLight;      //если три раза расстояние меньше заданого то включаем свет
short cntLightOff = _countLight;     //если три раза расстояние больше заданого то выключаем свет
short cntCoolerOn = _countCooler;    //если три раза расстояние меньше заданого то включаем вентилятор
#define _maxDistanceErr 100    //от некоторых поверхностей считает не правильно >100 см хотя до стенки 80 см если больше 100 см то присвоим среднее 
#define _distanceErr 20        //среднее значение 20 см
#define _coolerDelayOn  1  //задержка перед включением вентилятора, в 0,1 сек интервалах //была 10
#define _coolerDelayOff  600 //после выключения света вентилятор еще работает coolerDelayOff времени, в 0,1 сек интервалах
#define _lightHandDelayOff  150   //после включения c выключателя задержка перед выключеним если не никто не зашел в туалет в 0,1 сек интервалах
#define _lightDelayOff  130  //задежка выключения света, в 0,1 сек интервалах  

int cntLightDelayOff = 0;    //счетчик кол-ва прошедших 0,1 сек интервалов при влючении света cntLightDelayOff = _lightDelayOff и декремент до нуля потом отключаем свет 
int cntCoolerDelayOn = 0;    //счетчик кол-ва прошедших 0,1 сек интервалов здесь наоборот инкремент
int cntCoolerDelayOff = 0;   //счетчик кол-ва прошедших 0,1 сек интервалов здесь наоборот инкремент
int distance = 0;          //измеренное расстояние   было float
int distanceRaw = 0;       //"чистые" показания датчика

int sensorWaterLeak = 0;
#define _WaterLeakMax 500    //показания при которых срабатывает утечка =
int cntSensorWaterLeak = 0;   //число срабатывания от дребезка 
#define _maxCntSensorWaterLeak 200
boolean WaterLeakOn=false;    //признак того что утечка была
boolean BuzzerOn=false;      //для пиканья
boolean mutebeep=false;          //запретим пищать чтоб не надоедало 
long timeRunValve = 4000;   //время за которое должны закрыться краны
long timeReadSens = 100;       //100 миллисекунд
long timeErrBeep = 4000;       //200 миллисекунд
long time1sec = 1000;       //1 секунда

String serialCommand = "";

unsigned long TimerRunValveMillis = 0;
unsigned long TimerReadSensMillis = 0;
unsigned long Timer1SecMillis = 0;
unsigned long TimerErrBeepMillis = 0;
unsigned long TimerCurrentMillis;
static uint8_t last_input_states = 0;  //читаем сдвиговый регистр
 
  byte btnCloseWater=0;       //нажата закрыть
  byte btnOpenWater=0;        //нажата открыть
  byte EndSwHotCloseWater=0;  //концевой закрыто гор воды 
  byte EndSwHotOpenWater=0;   //концевой открыто гор воды
  byte EndSwColdCloseWater=0; //концевой закрыто хол воды 
  byte EndSwColdOpenWater=0;  //концевой открыто хол воды

Ultrasonic ultrasonic(pinHCSR04Trig, pinHCSR04Echo);  //инитим HCSR04
SoftwareSerial esp8266(pinSoftRX, pinSoftTX); // RX, TX

//*************************************************************
// Переменные, создаваемые процессом сборки,
// когда компилируется скетч
extern int __bss_end;
extern void *__brkval;
 
// Функция, возвращающая количество свободного ОЗУ (RAM)
int memoryFree()
{
   int freeValue;
   if((int)__brkval == 0)
      freeValue = ((int)&freeValue) - ((int)&__bss_end);
   else
      freeValue = ((int)&freeValue) - ((int)__brkval);
   return freeValue;
}
//*************************************************************
void setup() {   
  verbose = EEPROM.read(0);
  Mode = EEPROM.read(1);
  enableSmokeSensor = EEPROM.read(2);
  enableCapSensor = EEPROM.read(3);
  Serial.begin(9600);
  esp8266.begin(1200);
//*****************************************    
  SPI.begin();
  pinMode(pinSS, OUTPUT);/* Включаем защёлку */
  digitalWrite(pinSS, HIGH);
//*****************************************  
  StopValve();
//*****************************************  
  pinMode(pinWaterLeak, INPUT);    // initialize the digital pin as an output.   
  pinMode(pinSmokeSensor,INPUT);
  pinMode(pinHCSR04Echo, INPUT);     
  pinMode(pinHCSR04Trig, OUTPUT);     
  pinMode(pinMotorIN1, OUTPUT);     
  pinMode(pinMotorIN2, OUTPUT);     
  pinMode(pinLight, OUTPUT);     
  pinMode(pinCooler, OUTPUT);     
  pinMode(pinLedOpen, OUTPUT);     
  pinMode(pinLedClose, OUTPUT);     
  pinMode(pinBuzzer, OUTPUT);     
 // Serial.println("Wait 8 sec..");
 // delay(8000); // Задержка, чтобы было время перепрошить устройство в случае bootloop
  wdt_enable (WDTO_8S); // Для тестов не рекомендуется устанавливать значение менее 8 сек.
  Serial.println("Watchdog enabled.");
  Serial.println(memoryFree());
}
//**************************************************************************************
//закроем краны
void CloseValve()
{
  if (!(EndSwHotCloseWater&&EndSwColdCloseWater)) {
  EndSwHotOpenWater=0; EndSwColdOpenWater=0;
//  if (verbose > 0) {Serial.println(F("#WC:CloseValve"));}
  digitalWrite(pinMotorIN1, HIGH); 
  digitalWrite(pinMotorIN2, LOW);   
  ValveState = _valveRun;
  TimerRunValveMillis = TimerCurrentMillis; 
  mutebeep=false;
  delay(150);  //задержка чтоб сойти с концевых                                                                               
  }
}
//**************************************************************************************
//откроем краны
void OpenValve()
{ 
  if (!(EndSwHotOpenWater&&EndSwColdOpenWater)) {
  EndSwHotCloseWater=0;EndSwColdCloseWater=0;  
//  if (verbose > 0) {Serial.println(F("#WC:OpenValve"));}
  digitalWrite(pinMotorIN1, LOW); 
  digitalWrite(pinMotorIN2, HIGH);   
  ValveState = _valveRun;
  TimerRunValveMillis = TimerCurrentMillis; 
  mutebeep=false;
  delay(150);  //задержка чтоб сойти с концевых
  }
}
//**************************************************************************************
void StopValve()
{
//  if (verbose > 0) Serial.println(F("#WC:StopValve"));
  digitalWrite(pinMotorIN1, LOW);   //остановим моторы 
  digitalWrite(pinMotorIN2, LOW);
  ValveState = _valveStop;
}
//**************************************************************************************
void mute(){noTone(pinBuzzer);WaterLeakOn=false; ValveState = _valveStop; mutebeep=true; /*if (verbose > 0) Serial.println(F("#WC:Mute ON"));*/}
//**************************************************************************************
void parseSerialCommand() {
//   Serial.println(serialCommand);
   if (serialCommand.indexOf("WCvO=1")!=-1) {
    OpenValve();
    Serial.println("Open Valve");
   }
   if (serialCommand.indexOf("WCvC=1")!=-1) {
    CloseValve();
    Serial.println("Close Valve");
   }
   if (serialCommand.indexOf("WCsL=")!=-1) {
    byte light=serialCommand.substring(serialCommand.indexOf("=")+1,serialCommand.indexOf(";")-1).toInt();
    digitalWrite(pinLight,light);
    Serial.print("Light=");Serial.println(light);
   }
   if (serialCommand.indexOf("WCsF=")!=-1) {
    byte cooler=serialCommand.substring(serialCommand.indexOf("=")+1,serialCommand.indexOf(";")-1).toInt();
    digitalWrite(pinCooler,cooler);
    Serial.print("Cooler=");Serial.println(cooler);
   }
   if (serialCommand.indexOf("WCsM=")!=-1) {
    Mode=serialCommand.substring(serialCommand.indexOf("=")+1,serialCommand.indexOf(";")-1).toInt();
    Serial.print("Mode=");Serial.println(Mode);
   }
   serialCommand="";
   writeToEsp8266();   //пишем состояние системы
}
//**************************************************************************************
void serialEvent() {
  if(Serial.available()) // check if the esp is sending a message 
  {
    while(Serial.available())
    {
      char c = Serial.read(); // read the next character.
      serialCommand += c;
      Serial.write(c);
      if (c=='#') {parseSerialCommand();}
    }
  }  
}
//**************************************************************************************
void esp8266Event() {
  if(esp8266.available()) // check if the esp is sending a message 
  {
    while(esp8266.available())
    {
      char c = esp8266.read(); // read the next character.
      serialCommand += c;
      Serial.write(c);
      if (c=='#') {parseSerialCommand();}
    }
  }
}    
//**************************************************************************************
void writeToEsp8266(){
   char mess[50];  //1-coolerState;2-lightState;3-sensorWaterLeak;4-WaterLeakOn;5-EndSwHotCloseWater;6-EndSwHotOpenWater;7-EndSwColdCloseWater;8-EndSwColdOpenWater;9-distance;10-Mode;#  
   sprintf(mess,"WC%1d;%1d;%1d;%1d;%1d;%1d;%1d;%1d;%1d;%1d;#",digitalRead(pinCooler),digitalRead(pinLight),sensorWaterLeak,WaterLeakOn,EndSwHotCloseWater,EndSwHotOpenWater,EndSwColdCloseWater,EndSwColdOpenWater,distanceRaw,Mode);
   //Serial.println(mess);
   esp8266.print(mess);
}  
//**************************************************************************************


void loop() {
//*****************************
   wdt_reset();//сброс watchdog 
//   Serial.println(memoryFree());
//*****************************
//*****************************  читаем сдвиговый регистр
  digitalWrite(pinSS, LOW);       // Читаем запомненные состояния входов. Ноль шлём просто потому,
  digitalWrite(pinSS, HIGH);      // что transfer() одновременно и шлёт, и принимает. 
  uint8_t states = SPI.transfer(0);
    if (states != last_input_states)
  {                                                                 //если свет выключен то включаем и наоборот 
    if (states & B00000001) {digitalWrite(pinLight,HIGH);cntLightDelayOff=_lightHandDelayOff; /*if (verbose > 0) Serial.println(F("#WC:Switch Light ON"));*/}
        else { if (Mode==_manual) {digitalWrite(pinLight,LOW); cntLightDelayOff=0; /*Serial.println(F("#WC:Switch Light OFF"));*/}}           //выключатель света
    if (states & B00000010) {mute();}//mute sound
    if (states & B00000100) btnCloseWater = 1; else btnCloseWater=0;
    if (states & B00001000) btnOpenWater = 1; else btnOpenWater=0;
    if (states & B00010000) EndSwColdCloseWater = 1; else EndSwColdCloseWater=0;
    if (states & B00100000) EndSwColdOpenWater = 1; else EndSwColdOpenWater=0;
    if (states & B01000000) EndSwHotCloseWater = 1; else EndSwHotCloseWater=0;
    if (states & B10000000) EndSwHotOpenWater = 1; else EndSwHotOpenWater=0;
    last_input_states = states;
    //------------------------
  }
//**********************************  
  if ((btnCloseWater==1)&&(btnOpenWater==0)) {CloseValve(); }  //нажата закрыть и не нажата открыть
  if ((btnCloseWater==0)&&(btnOpenWater==1)) {OpenValve(); }  //нажата открыть и не нажата закрыть
//**********************************  7
  if ((EndSwHotCloseWater==1)&&(EndSwColdCloseWater==1)&&(ValveState == _valveRun)) {StopValve(); /*if (verbose > 0) Serial.println(F("#WC:stop on endsw "));*/}; 
  if ((EndSwHotOpenWater==1)&&(EndSwColdOpenWater==1)&&(ValveState == _valveRun)) {StopValve(); /*if (verbose > 0) Serial.println(F("#WC:stop on endsw ")); */}; 
//**********************************  
  if ((EndSwHotCloseWater==1)&&(EndSwColdCloseWater==1)&&(ValveState != _valveErr)) {digitalWrite(pinLedClose,HIGH);} else {if (ValveState!=_valveErr) digitalWrite(pinLedClose,LOW);};
  if ((EndSwHotOpenWater==1)&&(EndSwColdOpenWater==1)&&(ValveState != _valveErr)) {digitalWrite(pinLedOpen,HIGH);} else {if (ValveState!=_valveErr) digitalWrite(pinLedOpen,LOW);};
//**********************************  
//**********************************  
  sensorWaterLeak = analogRead(pinWaterLeak);
  if (sensorWaterLeak < _WaterLeakMax) cntSensorWaterLeak++; else cntSensorWaterLeak=0;
  if (cntSensorWaterLeak > _maxCntSensorWaterLeak){WaterLeakOn=true; tone(pinBuzzer,freqBuzzer); BuzzerOn=true; CloseValve(); /*if (verbose > 0) {Serial.println(F("#WC:Achtung Water Leak !!! Close valve !!!"));}*/}
//**********************************  
//организуем некое подобие таймера
  TimerCurrentMillis = millis();
  if((TimerCurrentMillis - TimerRunValveMillis > timeRunValve)&(ValveState == _valveRun) ) 
  {
   StopValve(); ValveState = _valveErr; // if (verbose > 0) {Serial.println(F("#WC:Time valve error"));} //если дошли до сюда то краны не закрылись за отведенное время останавливаем моторы моргаем диодами и пищим динамиком (в StopValve() ValveState = _valveStop но потом один хер ставим ошибку) 
  }
  if (millis() - Timer1SecMillis > time1sec)   //1 секунда
  {
   writeToEsp8266();   //пишем состояние системы
   if (WaterLeakOn) {if (BuzzerOn) {noTone(pinBuzzer); BuzzerOn=false;} else {tone(pinBuzzer,freqBuzzer); BuzzerOn=true;} } 
   if (ValveState == _valveErr ) {digitalWrite(pinLedClose,!digitalRead(pinLedClose)); digitalWrite(pinLedOpen,!digitalRead(pinLedOpen)); }  //моргаем светодиодами
    Timer1SecMillis = millis();
  }
    if (millis() - TimerErrBeepMillis > timeErrBeep)   // миллисекунд  часто пищим при ошибках и зарытых кранах
  {
    if ((ValveState == _valveErr)||(EndSwHotCloseWater==1)||(EndSwColdCloseWater==1)&&(!WaterLeakOn)&&(!mutebeep)) {if (BuzzerOn) {noTone(pinBuzzer); BuzzerOn=false;} else {tone(pinBuzzer,freqBuzzer); BuzzerOn=true;} } 
    TimerErrBeepMillis = millis();
  }

  if (millis() - TimerReadSensMillis > timeReadSens)    //100 миллисекунд
  {
    distanceRaw = ultrasonic.Ranging(CM);
    distance = distanceRaw;
   // if (verbose > 1) { Serial.print(F("#WC:"));Serial.print(millis()); Serial.print(F(" ms Distance-"));Serial.println(distance); }
    if (distance > _maxDistanceErr) {distance=_distanceErr;};    //от ложных срабатываний волосатых поверхностей (показывет больше 100 см)
    
   // if (enableSmokeSensor) smokeSensor=analogRead(pinSmokeSensor); //if (verbose>1) {Serial.print(("WC:"));Serial.print(millis()); Serial.print(F(" ms Smoke sensor-"));Serial.println(smokeSensor); }
   // if ((enableSmokeSensor)&(smokeSensor > _maxSmokeSensor)) {/* some code */} 
    
   // if (enableCapSensor) { 
   //   capSensor = capToiletBowlSensor.capacitiveSensor(30);  //если жопа сидит на унитазе то не даем сбрасывать счетчик на выключение света
   //   if (verbose > 1) {Serial.print(F("WC:"));Serial.print(millis()); Serial.print(F(" ms Capactor-"));Serial.println(capSensor); };
   //   if ((capSensor > _maxCapSensor)/*&(Mode==_auto)*/) {assSitToiletBowl = true; /*cntLightDelayOff=_lightDelayOff; */} else {assSitToiletBowl = false;}
   //                      };
    if (Mode==_auto) {
      if (distance < _distanceLightOn) cntLightOn--; else cntLightOn = _countLight;
      if (distance > _distanceLightOn) cntLightOff--; else cntLightOff = _countLight;
      if (cntLightOn < 0) {digitalWrite(pinLight,HIGH); cntLightDelayOff=_lightDelayOff; };
      if (cntLightOff < 0) {cntLightDelayOff--;}
      if (distance < _distanceCoolerOn) cntCoolerOn--; else cntCoolerOn = _countCooler;
      if (cntCoolerOn < 0) {cntCoolerDelayOn++;} else {cntCoolerDelayOn = 0;}
      if ((digitalRead(pinLight)==0)&(digitalRead(pinCooler)==1)) {cntCoolerDelayOff++;} else {cntCoolerDelayOff = 0;}
                      }
    TimerReadSensMillis = millis();
  }
//**********************************
   if (Mode==_auto) {  
   if (cntLightDelayOff < 0) {digitalWrite(pinLight,LOW); }
   if (cntCoolerDelayOn > _coolerDelayOn)   { digitalWrite(pinCooler,HIGH);}
   if (cntCoolerDelayOff > _coolerDelayOff) { digitalWrite(pinCooler,LOW); }
                     }
//**********************************
//**********************************
//**********************************  
 
//**********************************
 serialEvent();
 esp8266Event();
//**********************************  
//**********************************
//**********************************  
//**********************************
//**********************************  
//**********************************
  
}

 

afen
Offline
Зарегистрирован: 24.04.2017

только почему кран Dy15 ??  у меня труба пластик 20 мм

alexval2007
Offline
Зарегистрирован: 10.11.2012

afen потому что у этой трубы условный проход 15 внутри