Система "Умный дом" для загородного дома на Arduino Mega2560, HC-05, SIM900,DHT11,3-х DS18B20,RTC-DS1302

naz
Offline
Зарегистрирован: 15.11.2016

Питание моего SIM900 - внешнее 5В 2А, скорость установил 9600, использую на Меге Serial1 - пины 18 и 19. Никаких библиотек не подключаю. Порт живой, т.к. после выключения - включения питания работает нормально. Подозреваю, что он в какой-то режим переходит непонятный после посылки смс. Об ограничении по TX и RX не слышал для SIM900, как его сделать?

Макет

stambylov
stambylov аватар
Offline
Зарегистрирован: 10.05.2012

naz пишет:

Питание моего SIM900 - внешнее 5В 2А, скорость установил 9600, использую на Меге Serial1 - пины 18 и 19. Никаких библиотек не подключаю. Порт живой, т.к. после выключения - включения питания работает нормально. Подозреваю, что он в какой-то режим переходит непонятный после посылки смс. Об ограничении по TX и RX не слышал для SIM900, как его сделать?

Макет

 

Рабочий код для получения баланса

// Дата написания: 04.06.2016
// Создатель: Стамбулов Дмитрий
// E-mail: stambylov@ya.ru

#include <SoftwareSerial.h>
SoftwareSerial gsm(2, 3); // 2-txd, 3-rxo , Arduino mini или Arduino nano

void setup()
{
gsm.begin(9600);
// Запускаем GSM
gsm.write("AT+CMGF=1\r"); // устанавливает текстовый режим смс-сообщения
    delay(300);
gsm.write("AT+IFC=1, 1\r"); //устанавливает программный контроль потоком передачи данных
    delay(300);
gsm.write("AT+CPBS=\"SM\"\r");//открывает доступ к данным телефонной книги SIM-карты
    delay(300);
gsm.write("AT+CNMI=1,2,2,1,0\r");// включает оповещение о новых сообщениях, новые сообщения 
    delay(500);
gsm.write("AT+GSMBUSY=1\r\n"); // запрет всех входящих звонков.
    delay(300);
gsm.write("AT+CMGDA=DEL ALL\r\n"); // команда удалит все сообщения
    delay(500);
gsm.println("AT+CSQ");// Проверяем уровень сигнала
    delay(800);
}

void loop()
{

//*******************************************************************
  if (gsm.available()) {          //есть данные от GSM модуля
    String currStr = "";                      //выждем, чтобы строка успела попасть в порт целиком раньше чем будет считана
    String currStrN = "";
    String dataBalanceTemp = "";
    String dataBalance = "";
    String dataSms = "";
    String val = "";
    int flag1 = 0;
    int flag2 = 0;
    while (gsm.available()) {      //сохраняем входную строку в переменную val
      c:
      int ch = gsm.read();  //int
      val += char(ch);      // String
      char data = ch;      // char = int
      if ('\r' == data) {
        currStr = "";
      } else if ('\n' != data) {
          currStr += String(data);
          dataSms = currStr;
        }

// Начинаем разбор полученного смс, Работает 100% с оператором МТС
//Полученный текст: +CUSD: 0, "Balance:117,27r ", 15
      if (data == 'U' && flag1 == 2){flag2 = 3;}
      if (data == 'S' && flag2 == 3){flag2 = 4;}
      if (data == 'D' && flag2 == 4){flag2 = 5;}
      if (data == ':' && flag2 == 5){flag2 = 6;}
      if (data == '"' && flag2 == 6){dataBalanceTemp = ""; flag2 = 7; goto c;}
      if (data != '"' && flag2 == 7){dataBalanceTemp += String(data); dataBalance = dataBalanceTemp;}
      if (data == '"' && flag2 == 7){flag2 = 8;}
  }

// Смотрим данные полученные от модуля, Получили смс с балансом, теперь отсылаем 
    if (val.indexOf("+CUSD:") > -1) { 
      // +CUSD: 0, "Balance:117,27r ", 15
      if (dataBalance != "") {
        smsSendAlarm("Hi, " + dataBalance);
        dataBalance = "";
      }
    }
    
// Читаем смс полученные с мобильного
if (val.indexOf("+CMT") > -1) {
 if (dataSms.indexOf("Balans") > -1) {    // Запрос баланса
          GoBalans();
        }
}
  }
}

//процедура отправки СМС
void smsSendAlarm(String text) {
    String NBoss = "79115557744";
    gsm.println("AT+CMGS=\"" + NBoss + "\"");  //Отправляем на GSM комманду отправка смс-номер
    NBoss = "";                                //Очищаем перемунную
    delay(300);                                //Делаем задержку на передачу комманды
    gsm.print(text);                           //Отправляем на GSM комманду отправка смс-текст
    text = "";                                 //Очищаем перемунную
    delay(500);                                //Делаем задержку на передачу комманды
    gsm.print((char)26);                       //Отправляем на GSM комманду отправка смс!
    delay(5000);                               //Делаем задержку отправку смс
    
}

//Отправка смс о балансе
void GoBalans(){
  gsm.print("AT+CUSD=1,");
  gsm.print('"');
  gsm.print("#100#");
  gsm.println('"');
}

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

naz пишет:

Здравствуйте, форумчане.

Тоже занимаюсь темой умного дома, правда не столь продвинут. Автору спасибо за труд, и что поделился. Делаю на Меге 2560.

Вопрос у меня касается SIM900 (подключен на Serial1): после посылки смс шилд встаёт в ступор и перестаёт реагировать на АТ команды. В мониторе появляются ">". Привести шилд в чувство можно, передёрнув питание: выключить и включить (программно, конечно) после каждой посланной смс. Предполагаю, что есть более красивое решение, кто имел такую же проблему?

и все таки попробуйте софт сериал. Тоже сначала не работал сим900 на харде. Потом на софтсериале попробовал - заработало как надо. Правда сейчас и на харде работает, хз почему раньше глючило. 

naz
Offline
Зарегистрирован: 15.11.2016
Всё получилось после установки задержек:
    Serial1.print("AT+CNMI?\r"); delay(300); 
    // Устанавливаем адресата: телефонный номер в международном формате
    Serial1.println("AT + CMGS = \"+79227100381\""); 
    delay(300);
    Serial1.println((char)26); 
    delay(5000); 

Шилд стал адекватен, спасибо ответившим.

 

      

 

 

naz
Offline
Зарегистрирован: 15.11.2016

 

      

 

 

Serg1
Offline
Зарегистрирован: 04.12.2015

MaksVV,

я вставил ваш код #371 для работы с датчиками DS18 по таймеру в программу умного дома. Разложил фрагменты по соответствующим местам программы.

Остался последний рубеж- убрать ошибку:

"In file included from C:\Users\Сергей\Desktop\arduino-1.6.5-r5\hardware\arduino\avr\cores\arduino/Arduino.h:30:0,

from C:\Users\Сергей\Desktop\arduino-1.6.5-r5\скетч\libraries\OneWire/OneWire.h:7, from DS181.ino:2:

DS181.ino: In function 'void izmereniya()':
DS181:343: error: expected unqualified-id before string constant
DS181:343: error: a function-definition is not allowed here before '{' token
bluetooth:204: error: expected '}' at end of input
bluetooth:204: error: expected '}' at end of input
expected unqualified-id before string constant"
Если закоментировать строчку"ISR (WDT_vect)  {"  тот ошибок нет.
Подозреваю что где то не так с кавычками. Или не туда вставил фрагмент.
Подскажите, если не сложно ,где напортачил?
Serg1
Offline
Зарегистрирован: 04.12.2015
void izmereniya()   //  Замер температур с датчиков DS18B20 и влажности с датчика DHT11 

{  // http://arduino.ru/tutorials/BlinkWithoutDelay на основе
   unsigned long currentMillis = millis();
   if(currentMillis - previousMillis > interval) { // Замеры в интервале 
     dht.read(DHT11PIN);                  // Замеры температур с DHT11
     delay(100);                          // Необязательная задержка
     vlaga = dht.humidity;                // Уровень влажности % с DHT11
     TempPodpol = dht.temperature;        // Температура в подполе  с DHT11
     if (TempPodpol < 3 || TempPodpol > 35){ // Перезапрос. Борьба с помехами.
       dhtschet++;                           // +1 к счетчику ошибок DHT11
       delay(300);                           // Необязательная задержка
       dht.read(DHT11PIN);                   // Замеры температур с DHT11
       vlaga = dht.humidity;                 // Уровень влажности % с DHT11
       TempPodpol = dht.temperature;         // Температура в подполе  с DHT11
     if (TempPodpol < 3 || TempPodpol > 35){ // Перезапрос. Борьба с помехами.
       dht2schet++;                          // +1 к счетчику повторных ошибок DHT11
     
       }
     }



  ISR (WDT_vect)  {
static boolean n=0; // флаг работы: запрос температуры или её чтение
n=!n;

if (n) {ds.reset();  // сброс шины
        ds.write(0xCC);//обращение ко всем датчикам
        ds.write(0x44);// начать преобразование (без паразитного питания) 
       }
else   {ds.reset();
        ds.select(KuhnyaC);   
        ds.write(0xBE); // Read Scratchpad (чтение регистров) 
        TempKuhnyaC =  ds.read() | (ds.read()<<8); //прочитаны 2 байта      
        TempKuhnyaC = TempKuhnyaC / 16;
        // получение с 2-го датчика
        ds.reset();
        ds.select(ZalC);   
        ds.write(0xBE); // Read Scratchpad (чтение регистров) 
        TempZalC =  ds.read() | (ds.read()<<8); //прочитаны 2 байта 
        TempZalC = TempZalC/16;
        ds.reset();
        ds.select(UlicaC);   
        ds.write(0xBE); // Read Scratchpad (чтение регистров) 
        TempUlicaC =  ds.read() | (ds.read()<<8); //прочитаны 2 байта      
        TempUlicaC = TempUlicaC / 16;
        // получение с 3-го датчика
        ds.reset();
       ds.select(FreezeC);   
        ds.write(0xBE); // Read Scratchpad (чтение регистров) 
        TempFreezeC =  ds.read() | (ds.read()<<8); //прочитаны 2 байта 
        TempFreezeC = TempFreezeC/16 ;
}

//  } тут была

    { 
     UlicaS = analogRead(A15)/10;           // Считываем освещенность на улице
     voltmetr();                            // Считываем напряжения на выходе ИБП (норма 13,5в)
     previousMillis = currentMillis;}       // Сброс таймера
}
}// перенес

 

Serg1
Offline
Зарегистрирован: 04.12.2015

Подскажите, если не сложно, где напортачил?

Serg1
Offline
Зарегистрирован: 04.12.2015

MaksVV, 

могли бы вы поделиться вашим вариантом программы?

Не получается у меня внедрить опрос датчиков DS18 по сторожевому таймеру.(Ваш пост #371).

 

naz
Offline
Зарегистрирован: 15.11.2016

Коллеги, кто что думает/ имел опыт по монтажу ардуино + Sim900 с источниками питания в один корпус? У меня корпус небольших размеров, в нём монтирую ардуино, Sim900, твёрдотельное реле и вытащенные из корпусов блоки питания на 9В и 5В. Так вот, в этих БП используются малогабаритные импульсные трансформаторы - они могут наводить помехи на антенну Sim900?

 

naz
Offline
Зарегистрирован: 15.11.2016

Serg1 пишет:

MaksVV, 

могли бы вы поделиться вашим вариантом программы?

Не получается у меня внедрить опрос датчиков DS18 по сторожевому таймеру.(Ваш пост #371).

 

Я использовал пример для DS18 из библиотеки OnWire- заработал сразу, прочитал адрес и выдал температуру.

Serg1
Offline
Зарегистрирован: 04.12.2015

NAZ,

 в этом примере ( от OnWire) тоже идет задержка 750 мс.  Далласовскую библиотеку по этому поводу и гнобили. Поэтому я и пытался код от Димакса прикрутить-не получилось. Потом разглядел, что в авторской программе  опрос датчиков происходит раз в 2 минуты и успокоился.

Продолжаю править программу под свои нужды:

У меня  в нежилом доме котел электрический 3-х ступенчатый. 3-6-9 КВт., и счетчик 2х тарифный. Соответственно задумка по максимуму греть теплоноситель ночью, а днем только по необходимости ( чтоб температура была положительная). При этом хочу задействовать ступенчатый нагрев (3-6-9 КВт) в зависимости от (чего??)-  темп. за бортом\темп. в доме\ дельта  температур дом-улица...

Есть ли у кого идеи по такому алгоритму?

MaksVV
Offline
Зарегистрирован: 06.08.2015

Serg1 пишет:

Подскажите, если не сложно, где напортачил?

нужно убрать цикл void izmerenia ()  . вы измеряете температуры здесь ISR (WDT_vect)

Просто пользуетесь переменными температур, они сами обновляются сторожевой собакой. 

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

..

Serg1
Offline
Зарегистрирован: 04.12.2015

Так я его и убирал, за исключением цикла измерения с датчиков DHT11.

Заменил датчики DHT11 на DHT22. Поставил 2 шт. На улицу и в доме. Все температуры( с DHT и с  DS18) выводятся целочисленные.

Хотя указано разрешение 10 бит для Далласа. Не совсем понятно, где происходит округление? INT ?

osele
osele аватар
Offline
Зарегистрирован: 12.11.2016

Мужики вот здесь http://remotexy.com/ru/registration/complate/

Если кому интересно.

duplex
Offline
Зарегистрирован: 06.12.2016

Дорогие форумчане, подскажите по  опторазвязкам и модулю времени.

Нашел на ali вот такие PC817, можно ли использовать их в качестве аналога?

Заметил, что модули времени многие начали использовать другие, я нашел DS1302. Все таки есть смысл использовать именно его?

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

Serg1 пишет:

Так я его и убирал, за исключением цикла измерения с датчиков DHT11.

Заменил датчики DHT11 на DHT22. Поставил 2 шт. На улицу и в доме. Все температуры( с DHT и с  DS18) выводятся целочисленные.

Хотя указано разрешение 10 бит для Далласа. Не совсем понятно, где происходит округление? INT ?

дак у вас всё же заработали dallasы через прерывание? Не понятно зачем такая точность, но вроде чтобы десятые градуса показывало, нужно там где делится на 16, вместо /16 поставить /16,0

MaksVV
Offline
Зарегистрирован: 06.08.2015

duplex пишет:

Дорогие форумчане, подскажите по  опторазвязкам и модулю времени.

Нашел на ali вот такие PC817, можно ли использовать их в качестве аналога?

Заметил, что модули времени многие начали использовать другие, я нашел DS1302. Все таки есть смысл использовать именно его?

 

заказывал 100 штук pc817 с али - работают хорошо. Чето в 100 рубей вышло, дешево однако. часы лушче 1307, они по шине i2c подключаются, и вроде как не спешат. 1302 за полгода на полчаса убегают, если не раньше.  

spa-sam
Offline
Зарегистрирован: 14.12.2012

Часы лучше ds3231, идут очень точно, кварц вствроен в микросхему, есть температурная компенсация и т.д.

MaksVV
Offline
Зарегистрирован: 06.08.2015

Может кому будет интересно. Тестировал тут gsm модуль SIM800L, т.к. он совсем дешевый стал - около 250 руб. Но с ним возникли проблемы. Обязательно нужно хорошее питание через DC-DC преобразователь, 4,0В. Я подключал всё на бредборде естественно китайскими проводочками пин-пин. Так вот модуль по сериал соединению на АТ команды отвечал хорошо, но не находил сеть. Что я только не пробовал, кучу времени убил. Не верил в то, что многие говорили - типа припаяй провода и всё заработает (типа подключение через бредборд не вариант, плохой контакт и т.д.) Каково же было моё удивление, когда действительно модуль стал находить сеть (после надёжного соединения пайкой). Ещё нужно делать согласование уровней Rx и Tx чтобы от ардуино к GSM приходило по 2,7В на этих сигнальных проводах. (делается при помощи резистивных делителей напряжения). Ну и в конце ещё меня ожидали косяки в скетче. Скетч автора темы, который работает на Sim900, не работает на sim800L. В частности вот ошибки. 


void startMaxSMS() //__________________Цикл подготовки модуля к отправке СМС-сообщений по первому номеру
{
      mySerial.print("AT+CMGF=1\r");
      delay(100);
      mySerial.println("AT + CMGS = \"+79000000000\""); // (+79000000000 сдесь должен быть ваш номер №1)
      delay(100);
}

Здесь косяк кроется в пробелах в команде АТ+CMGS  - пробелов быть не должно, иначе команда не выполняется и смс не отправляется, хотя SIM900 на это не обращает внимания

MaksVV
Offline
Зарегистрирован: 06.08.2015

И ещё косяки в скетче автора, которые и для SIM900 нужно тоже исправить 

void NastroykaGSM () {
      mySerial.print("AT+CMGF=1\r");         //устанавливает текстовый режим смс-сообщения
    delay(100);
  mySerial.print("AT+IFC=1, 1\r");       //устанавливает программный контроль потоком передачи данных
    delay(100);
  mySerial.print("AT+CPBS=\"SM\"\r");    //открывает доступ к данным телефонной книги SIM-карты
    delay(100);
  mySerial.print("AT+GSMBUSY=1, 1\r");   //запрет всех входящих звонков
    delay(100);
  mySerial.print("AT+CNMI=1,2,2,1,0\r"); //включает оповещение о новых сообщениях
    delay(300);
  mySerial.print("AT+CMGDA=«DEL ALL»\r"); // удаляем все смс, ки
   delay(2000);  }

 

Команда AT+GSMBUSY=1, 1\r непонятно зачем ещё единица после запятной (команда не выполняется, проверял), нужная команда выглядит так AT+GSMBUSY=1\r

Команда AT+CMGDA=«DEL ALL»\r не выполняется, т.к. нужно вот так AT+CMGDA=\"DEL ALL\"\r 

Итоговый вариант 

void NastroykaGSM () {
      mySerial.print("AT+CMGF=1\r");         //устанавливает текстовый режим смс-сообщения
    delay(200);
  mySerial.print("AT+IFC=1, 1\r");       //устанавливает программный контроль потоком передачи данных
    delay(200);
  mySerial.print("AT+CPBS=\"SM\"\r");    //открывает доступ к данным телефонной книги SIM-карты
    delay(200);
  mySerial.print("AT+GSMBUSY=1\r");   //запрет всех входящих звонков
    delay(300);
  mySerial.print("AT+CNMI=1,2,2,1,0\r"); //включает оповещение о новых сообщениях
    delay(300);
  mySerial.print("AT+CMGDA=\"DEL ALL\"\r"); // удаляем все смс, ки
   delay(2000);
}

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

spa-sam пишет:

Часы лучше ds3231, идут очень точно, кварц вствроен в микросхему, есть температурная компенсация и т.д.

точно, лучше такие заказывать. (я перепутал их с 1307)

Serg1
Offline
Зарегистрирован: 04.12.2015

MaksVV,  нет датчики не заработали.

Оставил как есть.

У меня очередной косяк обнаружился- датчики DHT22.  Один на 6 пине, второй на 3 пине(пока не подключен). Данные дублируются.

Serg1
Offline
Зарегистрирован: 04.12.2015
  #include <stDHT.h>
DHT sens(DHT22);

////
vlaga = sens.readHumidity(6); // чтение датчика на пине 6 //dht.humidity; // Уровень влажности % с DHT11
Tempout = sens.readTemperature(6); // чтение датчика на пине 6 //dht22.temperature; // Температура в подполе с DHT11
delay(1500);
//vlaga2 = sens.readHumidity(3); // чтение датчика на пине 3 //dht.humidity; // Уровень влажности % с DHT11
// Tempin = sens.readTemperature(3); // чтение датчика на пине 3 //dht22.temperature;

TEMPin = sens.readTemperature(3); // чтение датчика на пине 3
HUMin = sens.readHumidity(3); // чтение датчика на пине 3

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

Serg1 пишет:

MaksVV,  нет датчики не заработали.

покажи весь скетч, посмотрим что у тебя не так

Serg1
Offline
Зарегистрирован: 04.12.2015

#include <SPI.h>
#include <SD.h>
//cs -> 53
//mosi -> 51
//sck -> 52
//miso -> 50
//50---39 было- гараж
//51---48 было- дренаж насос
//52--41 было-баня
//
const int chipSelect = 53;

#include <OneWire.h> // библиотека для DS18B20
#include <DallasTemperature.h> // библиотека для DS18B20

#define ONE_WIRE_BUS 7  // датчики DS18B20 на 7 пин
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature ds(&oneWire);  // Везде где встречается ds - это работа с датчиками Dallas DS18B20
DeviceAddress BoilerC = { 0x28, 0xA3, 0xA4, 0x03, 0x00, 0x00, 0x80, 0x33 }; // Сетевой адрес датчика DS18B20 --в доме ГВС закрашена верхушка
DeviceAddress SlivC =   { 0x28, 0xBB, 0x8A, 0x03, 0x00, 0x00, 0x80, 0x93 }; // Сетевой адрес датчика DS18B20 на улице-- В канализации без меток
DeviceAddress OtoplenieC = { 0x28, 0xBB, 0x73, 0x03, 0x00, 0x00, 0x80, 0xC6 }; // Сетевой адрес датчика DS18-- в СО  одна точка
int tempC; // для работы с DS18B20

int  TempBoilerC   = 60;  // Переменная. Измеренная температура в зале  -ГВС  (По умолчанию 20гр.*С)
int  TempSlivC     = 10;  // Переменная. Измеренная температура в сливе  (По умолчанию 20гр.*С)
int  TempOtoplenieC = 30;  // Переменная. Измеренная температура на батарее  (По умолчанию 20гр.*С)

int  UlicaS        = 15;  // Переменная. Измеренная освещенность на улице (По умолчанию 15%)

int  TEMPMINB = 40;  // Переменная. Уставка сигнализации минимальной температуры в зале  --  ГВС
int  TEMPMINS = -2; // Переменная. Уставка сигнализации минимальной температуры на улице -- (Слив)
int  TEMPMINO = 30;  // Переменная. Уставка сигнализации минимальной температуры ----в радиаторе  
int  TEMPMINP = 1;   // Переменная. Уставка сигнализации минимальной температуры на улице (По умолчанию 1гр.*С)

int  TEMPMAXB = 70;  // Переменная. Уставка сигнализации максимальной температуры в зале --ГВС   
int  TEMPMAXS = 50;  // Переменная. Уставка сигнализации максимальной температуры на улице   (Слив) 
int  TEMPMAXO = 70;  // Переменная. Уставка сигнализации максимальной температуры ---в радиаторе   
int  TEMPMAXP = 25;  // Переменная. Уставка сигнализации максимальной температуры в подполе (По умолчанию 25гр.*С)

//_______Все для циклов SavePar(),PrintPar(),ReadPar()____________________________________________________
#include <EEPROM.h>  // библиотека для записи в память микроконтроллера
int Epause_K; // Переменная печати времени выдержки спец из памяти
int Epause_V; // Переменная печати времени выдержки спец из памяти
int Epause_Z; // Переменная печати времени выдержки спец из памяти
int Epause_S; // Переменная печати времени выдержки спец из памяти

//_______Все для цикла void irremote()____________________________________________________________________

#include <IRremote.h>// удалил 2 фаила из библиотеки ремоте туул
//как исправить косяк с конфликтом таймеров при работе библиотеки IRremote и функции Tone
// <a data-cke-saved-href="http://www.arduino.ru/forum/programmirovanie/motor-shield-v3-podklyuchenie-tsop#comment-22223" href="http://www.arduino.ru/forum/programmirovanie/motor-shield-v3-podklyuchenie-tsop#comment-22223" rel="nofollow">http://www.arduino.ru/forum/programmirovanie/motor-shield-v3-podklyuchenie-tsop#comment-22223</a> 

IRrecv irrecv(8);

decode_results results;

//_______Все для цикла void otoplenie()____________________________________________________________________

int tempDust = 22;     // Уставка желаемой температуры в доме (По умолчанию 22гр.С)
int tempDECOust = 05;  // Уставка температуры в доме в режиме "Экономия"(По умолчанию 15гр.С)
// <a data-cke-saved-href="http://blockduino.blogspot.ca/2013/08/Password-Keypad-w-Sound.html" href="http://blockduino.blogspot.ca/2013/08/Password-Keypad-w-Sound.html" rel="nofollow">http://blockduino.blogspot.ca/2013/08/Password-Keypad-w-Sound.html</a> кодовый замок

#include <stDHT.h>
DHT sens(DHT22);

#include <DS1307.h> //Подключение модуля DS1307
DS1307 rtc(20,21);//(sda 20,scl 21)
Time t;

int RTCSekunda;              // Переменная "секунда" для суточного таймера цикл RTCtimer()
int RTCChas;                 // Переменная "час" для суточного таймера цикл RTCtimer()
int RTCMinuta;               // Переменная "минута" для суточного таймера

boolean statusKur=false;     // Флаг "работа курантов" 

boolean statusDay=false;     // Флаг "Режим работы true - дневной, false - ночной"

boolean SMSDvigenieK=false;  // Флаг "Отправлена СМС о движении на кухне" --оставляем
boolean SMSDvigenieV=false;  // Флаг "Отправлена СМС о движении в ванной"--будет лестница
boolean SMSDvigenieZ=false;  // Флаг "Отправлена СМС о движении в зале"-- будет веранда
boolean SMSDvigenieS=false;  // Флаг "Отправлена СМС о входе"           -- будет  в сенях
boolean SMSopenKal=false;    // Флаг "Отправлена СМС открыта калитка"
boolean SMSopenBan=false;    // Флаг "Отправлена СМС открыта баня"-    ----ворота

boolean SMSVoltOFF=false;    // Флаг "Отправлена СМС об отключении питания 220в"
boolean SMSVoltON=false;     // Флаг "Отправлена СМС о восстановлении питания 220в"

boolean SMSPodpol=false;     // Флаг "Отправлена СМС об затоплении подпола"
boolean SMSFireSensor=false; // Флаг "Отправлена СМС о сработке дымового датчика"
boolean SMSFireAlarm=false;  // Флаг "Отправлена СМС о сработке пожарной сигнализации"
boolean SMSDelete=false;     // Флаг "Удалены все СМС на SIM900"
boolean TimeSMSzapros=false; // Флаг "Отправлена СМС о состоянии дома по таймеру"
boolean SMSAlarmTemp=false;  // Флаг "Отправлена СМС о критической температуре"
boolean SMSVoltIBP=false;    // Флаг "Отправлена СМС о низком заряде аккумулятора"
//boolean EcoTempDust=false;   // Флаг "Экономия отопления"
int SMSschet=0;        // Подсчет кол-ва отправленных смс
int Fireschet=0;       // Подсчет кол-ва срабатываний пож.шлейфа
int dsshet=0;          // Подсчет кол-ва ошибок DS18B20

int Dayschet=0;        // Подсчет кол-ва дней бесперебойной работы после последней прошивки

int HUMin;   // влажность в доме DTH22
int TEMPin;  // температура в  доме DTH22
int vlaga;         // Значение влажности в цикле ventilyaciya()--На улице DTH22  
int Tempout;   // Переменная. Измеренная температура на улице ДТН22 
int pambilang;         // переменная для цикла sirena()

//_______Все для цикла void voltmetr()
float vout = 0.0;      // Напряжение на входе аналового входа
float Vpit = 0.0;      // Измеряемое напряжение на выходе ИБП
  int volt = 0;        // Напряжение на входе АЦП

int statushome=0;      // переменная статуса включения умного дома 1 - включен, 0 -выключен
int statusotp=0;       // статус отопления дома                0 - откл , 1- вкл , 2- экономия
//int statusrzd=0;       // статус питания розеток дома          0 - откл , 1- вкл
//int statusgaraj=0;     // статус питания гаража                0 - откл , 1- вкл
//int statusbania=0;     // статус питания бани                  0 - откл , 1- вкл
int statusPump=0;      // статус питания станции водоснабжения 0 - откл , 1- вкл
int perimetr=0;        // статус включения охраны периметра    0 - откл , 1- вкл
int statusperimetr=0;  // статус периметра        1 - все двери закрыты , 0 - дверь не закрыта
int statuspoliv=0;     // статус полива                        0 - откл , 1- вкл , 2- Таймер
int statusAlarm=0;     // Переменная "Наличие тревоги"
int AlarmTemp=0;       // Переменная "Наличие тревоги по критической температуре"
int statusFireAlarm=1; // Переменная "Режим работы пож.сигнализации" - 0 - откл , 1- вкл , 2- проверка, 3-в тревоге
int signaliz=0;        // Переменная "Режим работы охр.сигнализации" - 0 - откл , 1- вкл , 2- постановка на охрану, 3-в тревоге
int statusPIK=0;       // статус работы тональной пищалки            - 0 - откл , 1- вкл
int ULsvet=2;          // Режим работы уличного освещения            - 0 - откл , 1- вкл , 2- АВТОРЕЖИМ

boolean statusBlock=false;  // статус блокировки освещения зала пользователем

int intervalPIK = 1000;//  интервал для цикла Pik()
int TonPIK = 2500;     //  частота тона пищалки

//_________ Уставки для работы по расписанию________________________
int TimeOFFpump = 0;     // Время выключения насосной станции  (По умолчанию 0:00)
int TimeONperimetr = 23; // Время включения охраны периметра   (По умолчанию 23:00)
int TimeOFFperimetr = 6; // Время выключения охраны периметра   (По умолчанию 6:00)
int TimeONdren = 20;     // Время включения дренажного насоса  (По умолчанию 20:00)
int TimeOFFdren = 21;    // Время выключения дренажного насоса (По умолчанию 21:00)
int TimeONnagr  = 4;     // Время включения нагревателя воды   (По умолчанию 06:00)
int TimeOFFnagr = 22;    // Время выключения нагревателя воды  (По умолчанию 22:00)

//_________ флаги для таймеров______________________________________
boolean Timer1On = false;  //Флаг таймера РЕЗЕРВ
boolean Timer2On = false;  //Флаг таймера постановки на охрану

//_________ переменные времени для таймеров_________________________
unsigned long EndPikMillis = 0; // храним время последнего тона для цикла Pik()
unsigned long NowTime1 = 0;         // переменная хранения времени таймера №1 
unsigned long StartTime1 = 0;       // переменная хранения времени запуска таймера №1 
unsigned long NowTime2 = 0;         // переменная хранения времени таймера №2 
unsigned long StartTime2 = 0;       // переменная хранения времени запуска таймера №2 


//_________ флаги для цикла Kvitirovanie()(сброс звука сирены)______________________________________
boolean KvitDI30 = false;     //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход 30
boolean KvitDI29 = false;     //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход 29
boolean KvitDI31 = false;     //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход 31
boolean KvitBoilerC = false;     //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура зал-- Бойлер
boolean KvitSlivC = false;   //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура улицы -- СЛИВ
boolean KvitOtoplenieC = false;  //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура кухни-СО
boolean KvitPodpolC=false;    //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура на улице

//boolean KvitAI14 = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход A14

long previousMillis = 0;    // храним время последнего замера влажности для цикла izmereniya()
long interval = 120000;     // интервал между замерами параметров для цикла  izmereniya() 2 минуты 

//______ Переменные для цикла avtosvet() взято с <a data-cke-saved-href="http://zelectro.com.ua/PIR_sensor" href="http://zelectro.com.ua/PIR_sensor" rel="nofollow">http://zelectro.com.ua/PIR_sensor</a> ___________________________
long unsigned int lowIn_K;  // Время, в которое был принят сигнал отсутствия движения на кухне(LOW)
long unsigned int lowIn_V;  // Время, в которое был принят сигнал отсутствия движения в ванной(LOW)-Лестница
long unsigned int lowIn_Z;  // Время, в которое был принят сигнал отсутствия движения в зале(LOW) --веранда
long unsigned int lowIn_S;  // Время, в которое был принят сигнал отсутствия движения в сенях(LOW)
int pause_K = 1; //Пауза, после которой движение считается оконченным (1 мин)
int pause_V = 1; //Пауза, после которой движение считается оконченным (1 мин)
int pause_Z = 2; //Пауза, после которой движение считается оконченным (2 мин)
int pause_S = 1; //Пауза, после которой движение считается оконченным (1 мин)
boolean lockLow_K = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean lockLow_V = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean lockLow_Z = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean lockLow_S = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean takeLowTime_K; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
boolean takeLowTime_V; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
boolean takeLowTime_Z; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
boolean takeLowTime_S; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
int pirPin_K = 26;    //вывод подключения PIR датчика Кухни--
int pirPin_V = 24;    //вывод подключения PIR датчика Ванной  --лестница
int pirPin_Z = 22;    //вывод подключения PIR датчика Зал  ---веранда
int pirPin_S = 28;    //вывод подключения PIR датчика Сени--

//_______Для работы терминала по  bluetooth___________________________
int inSize=0;  // Переменная которая будет содержать размер буфера терминала bluetooth
char str[128]; // Так как типа string тут нет, будем использовать массив символов

//_______Для работы терминала по  Sim900______________________________

String currStr = "";
boolean isStringMessage = false;  // Переменная принимает значение True, если текущая строка является сообщением

//___________________ Стартовый цикл _________________________________

void setup()

{
  ds.begin();
  ds.setResolution(BoilerC, 10);   
  ds.setResolution(SlivC, 10); 
  ds.setResolution(OtoplenieC, 10); 
  
  pinMode(22, INPUT); digitalWrite(22,HIGH);    // вход датчик движения зал--веранда
  pinMode(24, INPUT); digitalWrite(24,HIGH);    // вход датчик движения--лестница
  pinMode(26, INPUT); digitalWrite(26,HIGH);    // вход датчик движения кухня
  pinMode(28, INPUT); digitalWrite(28,HIGH);    // вход датчик движения сени
  pinMode(30, INPUT); digitalWrite(30,HIGH);    // вход сигнализатор "Вода протечка"
  pinMode(32, INPUT); digitalWrite(32,HIGH);    // Резерв
  pinMode(34, INPUT); digitalWrite(34,HIGH);    // Резерв
  pinMode(36, INPUT); digitalWrite(36,HIGH);    // Кнопка звонка домофона
  
  pinMode(23, INPUT); digitalWrite(23,HIGH);    // вход концевики ворот
  pinMode(25, INPUT); digitalWrite(25,HIGH);    // вход концевик входной двери(веранда)
  pinMode(27, INPUT); digitalWrite(27,HIGH);    // вход концевик калитка
  pinMode(29, INPUT); digitalWrite(29,HIGH);    // вход термостат "Баня готова"
  //pinMode(31, INPUT); digitalWrite(31,HIGH);    // вход термостат "Очень высока температура в бане"
  pinMode(33, INPUT); digitalWrite(33,HIGH);    // Дымовой шлейф №1
  pinMode(35, INPUT); digitalWrite(35,HIGH);    // Дымовой шлейф №2
  pinMode(37, INPUT); digitalWrite(37,HIGH);    // Нет напряжения после УЗО
    
  pinMode( 5, OUTPUT);     // Пьезо динамик
  pinMode(13, OUTPUT);     // Лампа УД включен
  
  pinMode(38, OUTPUT);     // Свет в Кухня
  pinMode(40, OUTPUT);     // Свет -лестница
  pinMode(42, OUTPUT);     // Свет в Зал-- веранда
  pinMode(44, OUTPUT);     // Свет в Сени
  pinMode(46, OUTPUT);     // Питание насосной станции...
  pinMode(48, OUTPUT);     // Питание дренажного насоса.......... ТЕПЕРЬ ОТОПЛЕНИЕЁ!!!
  //pinMode(50, OUTPUT);     // Питание водонагревателя  ТЕПЕРЬ MISO
 // pinMode(52, OUTPUT);     // Освещение двора  ТЕПЕРЬ  SCK
  
  digitalWrite(38,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  digitalWrite(40,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  digitalWrite(42,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  digitalWrite(44,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  digitalWrite(46,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  digitalWrite(48,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
 // digitalWrite(50,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  //digitalWrite(52,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  
  //pinMode(50, OUTPUT);     // Питание гаража 39
  pinMode(41, OUTPUT);     // Питание бани 41  Теперь осв двора
  pinMode(43, OUTPUT);     // Питание розеток дома 
  pinMode(45, OUTPUT);     // Питание нагревателя слива............................
  
  pinMode(47, OUTPUT);     // Клапан полива
  pinMode(49, OUTPUT);     // Сирена громкая
  //pinMode(51, OUTPUT);     //  MOSI               было Управление отоплением!!!!!!!!!!!!!!!!!!!!!!!!!!!
  pinMode(53, OUTPUT);     // SD card
  pinMode(31, OUTPUT);  // индикация записи на карту SD
  pinMode(6, INPUT);  //DHT22  
  digitalWrite(6, HIGH); 
  pinMode(3, INPUT);   // DHT22
  digitalWrite(3, HIGH);

  
  Serial.begin(9600);      // Связь по терминалу
Serial.print("Initializing SD card...");

  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    // don't do anything more:
    //return;
  }
  Serial.println("card initialized.");


  
  Serial1.begin(9600);     // HC-05 Bluetooth <a data-cke-saved-href="http://robocraft.ru/blog/electronics/587.html#comment4652" href="http://robocraft.ru/blog/electronics/587.html#comment4652" rel="nofollow">http://robocraft.ru/blog/electronics/587.html#comment4652</a>
  Serial2.begin(19200);     // GSM SMS-передача 
  //Serial3.begin(9600);    // Плата голосового оповещения на attiny2313 и SD-карте
  if(EEPROM.read(0)==10){ReadPar();} // Чтение настроек из памяти, если они туда были сохранены ранее
  delay(2000);
  SMSVoltON=true;
  NastroykaGSM();           // Настройка работы с SIM900
  irrecv.enableIRIn();      // Запуск ИК-приемника
  tone(5, 2000, 200);       // Звук, когда все готово!  выключил
  delay(4000);
  t = rtc.getTime();

  RTCSekunda = t.sec; // t.sec  - запрос секунд
  RTCChas = t.hour;   // t.hour - запрос часов
  RTCMinuta = t.min;  // t.min  - запрос минут
  
  SMSschet = EEPROM.read(51); // чтение  кол-ва ранее отправленных СМС
 // startOneSMS();
//  Serial2.print("SmartHome vkluchen - "); vremya2();  EndSMS();// время включения
}

void loop()
{
   RTCtimer();
   izmereniya();
   alarms();
   irremote();
   bluetooth();
   sms_read();
   osvechenie(); // Управление освещением во дворе
    Slivnagrev(); // управление подогревом сливной канализации



 // make a string for assembling the data to log:
  String dataString = "";

  // read three sensors and append to the string:
  ///for (int analogPin = 0; analogPin < 3; analogPin++) {
   // int sensor = analogRead(analogPin);
    dataString += (t.date, DEC);
     dataString += ",";
dataString += String(rtc.getDOWStr());
 dataString += ",";
dataString += String(HUMin);
 dataString += "% in";
dataString += String(TEMPin);
 dataString += ",Cin";
dataString += String(vlaga);
 dataString += "% out";
dataString += String(Tempout);
 dataString += ",Cout";
dataString += String(UlicaS);
dataString += "lux";

 //   }
 // }/////////////////////////////////////////////////////////////////////////////

  
 if(RTCSekunda==0){              // если секунды равны 00
        if(RTCMinuta%2==0){//запись каждые   --2 мин
  // open the file. 
  File dataFile = SD.open("datalog.txt", FILE_WRITE);

  // if the file is available, write to it:
  if (dataFile) {
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    Serial.println(dataString);
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");
  }
}/////////////////////////////////////////////////////////////////////////////////////
}
    
   if (!statusFireAlarm==0){FireAlarm();}                                     // Работа пожарной сигнализации
   if (statushome==1) {avtosvet();}                                           // Автоматическое управление освещением в доме меньше 11%
   if (statushome==1){digitalWrite(13,HIGH);}   else {digitalWrite(13, LOW);} // Лампа "Умный дом включен"
   //if (statushome==1){ventilyaciya();}                                      // Управление вентиляцией в подполе по датчику влажности DHT11 
   if (statusotp==1) {otoplenie();} else {digitalWrite(48, LOW);}             // Управление работой газового котла 1 - вкл., 0 - откл.53-51
   if (!signaliz==0){signalizSMS();}                                          // Работа сигнализации сигнализации при режимах 1,2,3
   if (statusPIK==1){Pik();}                                                  // Работа тональной пищалки
   if (perimetr==1){Operimetr();}                                             // Охрана периметра участка
   if ((statusPump==1) && (digitalRead(30)==LOW)) {digitalWrite(46,LOW);} else {digitalWrite(46, HIGH);} // Питание станции водоснабжения (Сигнал инвертированный)
  // if (statusrzd==1){digitalWrite(43,HIGH);}    else {digitalWrite(43, LOW);} // Питание розеток дома 
  // if (statusgaraj==1){digitalWrite(39,HIGH);}  else {digitalWrite(39, LOW);} // Питание гаража
  // if (statusbania==1){digitalWrite(41,HIGH);}  else {digitalWrite(41, LOW);} // Питание бани
   if (statuspoliv==0) {digitalWrite(47, LOW);}                               // Выключение клапана полива
   if (statuspoliv==1) {digitalWrite(47, HIGH);}                              // Включение клапана полива на постоянку
   if (statuspoliv==2) {digitalWrite(47, HIGH); timerPoliv();}                // Клапан полива включен по таймеру
   if ((perimetr==1 && statusperimetr==0) || statusAlarm==1) { sirena();}     // Работа малой сирены
   
   //if (analogRead(14)>100)    {KvitAI14=false;}                       // Сброс квитирования при возвращении параметра в норму
   if (digitalRead(29)==LOW)  {KvitDI29=false;}                         // Сброс квитирования при возвращении параметра в норму
   if (digitalRead(30)==LOW)  {KvitDI30=false;}                         // Сброс квитирования при возвращении параметра в норму
   if (digitalRead(31)==LOW)  {KvitDI31=false;}                         // Сброс квитирования при возвращении параметра в норму

}

void izmereniya()   //  Замер температур с датчиков DS18B20 и влажности с датчика DHT11 
{  // <a data-cke-saved-href="http://arduino.ru/tutorials/BlinkWithoutDelay" href="http://arduino.ru/tutorials/BlinkWithoutDelay" rel="nofollow">http://arduino.ru/tutorials/BlinkWithoutDelay</a> на основе
   unsigned long currentMillis = millis();
   if(currentMillis - previousMillis > interval) { // Замеры в интервале 

    
     vlaga = sens.readHumidity(6);    // чтение датчика на пине 6         //dht.humidity;                // Уровень влажности % с DHT11
     Tempout = sens.readTemperature(6); // чтение датчика на пине 6     //dht22.temperature;        // Температура в подполе  с DHT11
delay(2000);
  
    HUMin = sens.readHumidity(3);    // чтение датчика на пине 3
    TEMPin = sens.readTemperature(3); // чтение датчика на пине 3
   
     ds.requestTemperatures();            // Замеры температур с DS18B20
     delay(350);                          // Необязательная задержка
     TempBoilerC    = ds.getTempC(BoilerC);     // Считываем температуру в зале---ГВС
     delay(100);
     TempSlivC  = ds.getTempC(SlivC);   // Считываем температуру на улице--  Слив
     delay(100);
     TempOtoplenieC = ds.getTempC(OtoplenieC);  // Считываем температуру в кухне--- СО
     delay(100);
     if(TempBoilerC== -127 || TempSlivC== -127 || TempOtoplenieC== -127) // Перезапрос при ошибке датчика
     {
       ds.requestTemperatures(); delay(750); dsshet++ ; // +1 к счетчику ошибок DS18B20
       TempBoilerC    = ds.getTempC(BoilerC);     // Считываем температуру в зале--ГВС
       delay(100);
       TempSlivC  = ds.getTempC(SlivC);   // Считываем температуру на улице---Слив
       delay(100);
       TempOtoplenieC = ds.getTempC(OtoplenieC);  // Считываем температуру в кухне-- СО
       delay(100);
      }
     UlicaS = analogRead(A15)/10;           // Считываем освещенность на улице
     voltmetr();                            // Считываем напряжения на выходе ИБП (норма 13,5в)
     previousMillis = currentMillis;}       // Сброс таймера
}

void voltmetr()  //____________Цикл "Вольтметр"__измерение напряжения на выходе ИБП
// Взято с <a data-cke-saved-href="http://digitrode.ru/computing-devices/mcu_cpu/87-voltmetr-na-arduino.html" href="http://digitrode.ru/computing-devices/mcu_cpu/87-voltmetr-na-arduino.html" rel="nofollow">http://digitrode.ru/computing-devices/mcu_cpu/87-voltmetr-na-arduino.html</a>
{
   volt = analogRead(A0);                       // А0 аналоговый вход вольтметра
   vout = (volt * 5.0) / 1024.0;             
   Vpit = vout / (10000.0/(100000.0+10000.0));  // По формуле Vpit = vout / (R2/(R1+R2)) 
   if (Vpit<0.09) { Vpit=0.0;}                  // Округление до нуля 
}

void osvechenie() // Работа уличного освещения двора
{
 if ( ULsvet==2 )   // Если режим работы автоматический
 {
  if (UlicaS > 8){digitalWrite(41,HIGH);}  // Освещение двора выключить при освещении больше 8%  (сигнал инвертированный)52--41
  if (UlicaS < 4) {digitalWrite(41,LOW);}  // Освещение двора включить при освещении меньше 4% (сигнал инвертированный)  52--41
 }
}
  
void avtosvet()   //______Цикл управления автоматическим освещением____________________________________
{

  //______Ниже для зала______________________________________
  if(digitalRead(pirPin_Z) == HIGH && statusBlock==false && UlicaS < 30) //Если обнаружено движение, нет блокировки, и освещенность улицы меньше 20%
  {    
    if(lockLow_Z) //Если до этого момента еще не включили реле
    { lockLow_Z = false; digitalWrite(42, LOW); delay(50);}     //Включаем свет.     
    takeLowTime_Z = true;
  }  
  if(digitalRead(pirPin_Z) == LOW) //Ели движения нет
  { //Если время окончания движения еще не записано     
    if(takeLowTime_Z){lowIn_Z = millis();takeLowTime_Z = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
    if(!lockLow_Z && millis() - lowIn_Z > (pause_Z * 60000))               //Если время без движение превышает паузу => движение окончено
    { lockLow_Z = true; digitalWrite(42, HIGH); delay(50);}      //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения                
  } 
  if (statushome==1 && UlicaS > 35) {digitalWrite(42,HIGH);}     // Отключение реле управления освещением больше 35%

  //______Ниже для кухни______________________________________
  if(digitalRead(pirPin_K) == HIGH && statusDay==false && UlicaS < 30) //Если обнаружено движение с 23 до 8 включаем подсветку
  {    
    if(lockLow_K) //Если до этого момента еще не включили реле
    { lockLow_K = false; digitalWrite(38, LOW); delay(50);}   //Включаем свет.     
    takeLowTime_K = true;}  
  if(digitalRead(pirPin_K) == LOW) //Ели движения нет
  { //Если время окончания движения еще не записано     
    if(takeLowTime_K){lowIn_K = millis();takeLowTime_K = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
    if(!lockLow_K && millis() - lowIn_K > (pause_K * 60000))     //Если время без движение превышает паузу => движение окончено
    { lockLow_K = true; digitalWrite(38, HIGH); delay(50);}      //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения                
  }
  if (statushome==1 && UlicaS > 35) {digitalWrite(38,HIGH);}     // Отключение реле управления освещением больше 20%

  //______Ниже для ванной комнаты------лестницы___
  if(digitalRead(pirPin_V) == HIGH && UlicaS < 30) //Если обнаружено движение
  {    
    if(lockLow_V) //Если до этого момента еще не включили реле
    { lockLow_V = false; digitalWrite(40, LOW); delay(50);}     //Включаем свет.     
    takeLowTime_V = true;}  
  if(digitalRead(pirPin_V) == LOW) //Ели движения нет
  { //Если время окончания движения еще не записано     
    if(takeLowTime_V){lowIn_V = millis();takeLowTime_V = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
    if(!lockLow_V && millis() - lowIn_V > (pause_V * 60000))     //Если время без движение превышает паузу => движение окончено
    { lockLow_V = true; digitalWrite(40, HIGH); delay(50);}      //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения                
  }
  if (statushome==1 && UlicaS > 35) {digitalWrite(40,HIGH);}     // Отключение реле управления освещением больше 35%

  //______Ниже для сеней______________________________________
  if(digitalRead(pirPin_S) == HIGH && UlicaS < 16) //Если обнаружено движение
  {    
    if(lockLow_S) //Если до этого момента еще не включили реле
    { lockLow_S = false; digitalWrite(44, LOW); delay(50);}     //Включаем свет.     
    takeLowTime_S = true;}  
  if(digitalRead(pirPin_S) == LOW) //Ели движения нет
  { //Если время окончания движения еще не записано     
    if(takeLowTime_S){lowIn_S = millis();takeLowTime_S = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
    if(!lockLow_S && millis() - lowIn_S > (pause_S * 60000))               //Если время без движение превышает паузу => движение окончено
    { lockLow_S = true; digitalWrite(44, HIGH); delay(50);}      //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения                
  }
  if (statushome==1 && UlicaS > 20) {digitalWrite(44,HIGH);}     // Отключение реле управления освещением больше 20%
}

   void Slivnagrev()
     {
   if (TempSlivC > 5) {digitalWrite(45,LOW );} //  Выключение нагревателя при темп более 5 град.
   if (TempSlivC < 0) {digitalWrite(45, HIGH);}  // Включение нагревателя при темп менее 0
    }

void homeON() //____________Цикл включения умного дома____________________________________________________
{
  statushome=1;      // статус умного дома                   0 - откл , 1- вкл
 statusotp=1;       // статус отопления дома                0 - откл , 1- вкл
 // statusrzd=1;       // статус питания розеток дома          0 - откл , 1- вкл
//  statusgaraj=1;     // статус питания гаража                0 - откл , 1- вкл
//  statusbania=1;     // статус питания бани                  0 - откл , 1- вкл    
}

void homeOFF() //____________Цикл выключения умного дома________________________
{
  statushome=0;      // статус питания дома                  0 - откл , 1- вкл
 //statusrzd=0;       // статус питания розеток дома          0 - откл , 1- вкл
 // statusgaraj=0;     // статус питания гаража                0 - откл , 1- вкл
 // statusbania=0;     // статус питания бани                  0 - откл , 1- вкл
  statusPump=0;      // статус питания станции водоснабжения 0 - откл , 1- вкл
  digitalWrite(38,HIGH); // выключение реле (сигнал инвертированный)
  digitalWrite(40,HIGH); // выключение реле (сигнал инвертированный)
  digitalWrite(42,HIGH); // выключение реле (сигнал инвертированный)
  digitalWrite(44,HIGH); // выключение реле (сигнал инвертированный)  
  digitalWrite(46,HIGH); // выключение реле (сигнал инвертированный)
  digitalWrite(48,HIGH); // выключение реле (сигнал инвертированный)  
  digitalWrite(39,HIGH); // выключение реле (сигнал инвертированный)  50--39   
  SMSAlarmTemp=false;   // сброс флага отправки СМС о критической темпертуры
 // SMSBanyaTemp=false;   // сброс флага отправки СМС о критической темпертуры в бане
  SMSPodpol=false;      // сброс флага отправки СМС о воде в подполе
}

void otoplenie() // Цикл управления газовым котлом (Сигнал инвертированный!
{
  if ( statusotp==0) // Отключено
     {  digitalWrite(48,HIGH);} // Отключить отопление  51--48
  
  if ( statusotp==1) // Климат-контроль
     {  if ( TempOtoplenieC > (tempDust+1)){digitalWrite(48,HIGH);} // Отключить отопление если температура больше желаемой на 1грС  51--48
        if ( !TempOtoplenieC== -127 && (TempOtoplenieC < tempDust) )   {digitalWrite(48,LOW);}  // Включить отопление если температура меньше желаемой 51--48
     }
  if ( statusotp==2) // Экономия
     {  if ( TempOtoplenieC > (tempDECOust+1)){digitalWrite(48,HIGH);} // Отключить отопление если температура больше желаемой на 1грС 51--48
        if ( !TempOtoplenieC== -127 && (TempOtoplenieC < tempDECOust) )   {digitalWrite(48,LOW);}  // Включить отопление если температура меньше желаемой 51--48
     }
}  

void timerPoliv()    // Таймер клапана полива огорода 0 - откл , 1- вкл , 2- Таймер
{

  NowTime1 = millis();
  if(Timer1On == true) { StartTime1 = NowTime1 ; Timer1On = false; statuspoliv=2;}
  if( statuspoliv==2 && NowTime1 - StartTime1 > 900000) // выдержка 15 минут
    { statuspoliv=0; } // Сброс таймера
}


 

Serg1
Offline
Зарегистрирован: 04.12.2015

MaksVV, выкладываю основной код.

В воскресенье перезалил этот код- стал нормально отображать показания с DTH22. Странно, по ним ничего не менял!

Я добавил код записи данных с датчиков температур на SD карту. Пока нет карты закомментировал пару строк кода, чтоб работала остальная программа.

Запись параметров на карту должна происходить каждые 2 мин, когда секунды равны 0.

Обнаружилась особенность- программа в сериал выдает 3-4 раза сообщение об ошибки открытия файла(по идее д.б. один раз в 2 мин.00 секунд) Я так понимаю, что в течении этой нулевой секунды программа успевает 3 раза пытаться открыть файл?

Вывод по блютуф- то параметры выводятся построчно, что есть правильно, но периодически перенос некоторых строк отсутствует. Происходит это случайным образом.  Вкладку работы с блютуф кардинально не менял. Только прописал в кавычки параметры по русски.

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

MaksVV
Offline
Зарегистрирован: 06.08.2015

MaksVV пишет:

Serg1 пишет:

MaksVV,  нет датчики не заработали.

покажи весь скетч, посмотрим что у тебя не так

Я имел ввиду посмотрим только почему не работают датчики даллас по прерыванию. А в предоставленном коде вообще по обычной библе они работают. 

Serg1
Offline
Зарегистрирован: 04.12.2015
#include <OneWire.h> // библиотека для DS18B20

OneWire ds(7);   // датчики DS18B20 на 7 пин

byte KuhnyaC[8] ={0x28, 0xFF, 0xB1, 0x43, 0x52, 0x15, 0x01, 0xDB};//Сетевой адрес датчика DS18B20 в доме

byte ZalC[8] ={0x28, 0xFF, 0xBA, 0x6C, 0x52, 0x15, 0x01, 0x41};

byte UlicaC[8] ={0x28, 0xFF, 0xE8, 0x3C, 0x03, 0x15, 0x03, 0xE3};

byte FreezeC[8] ={0x28, 0x9D, 0xE5, 0x70, 0x01, 0x00, 0x00, 0xEE};// Сетевой адрес датчика DS18 на батарее

volatile int  TempKuhnyaC = 20;

volatile int  TempZalC = 20;

volatile int  TempFreezeC = 20;

volatile int  TempUlicaC = 20;

//bool SMSAlarmTemp = false;

//bool AlarmTemp = false;




//int tempC; // для работы с DS18B20&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&

//int  TempZalC    = 20;  // Переменная. Измеренная температура в зале    (По умолчанию 20гр.*С)
//int  TempUlicaC  = 20;  // Переменная. Измеренная температура на улице  (По умолчанию 20гр.*С)
//int  TempKuhnyaC = 20;  // Переменная. Измеренная температура на батарее  (По умолчанию 20гр.*С)
int  TempPodpol  = 7;   // Переменная. Измеренная температура в подполе (По умолчанию 7гр.*С)
int  UlicaS      = 15;  // Переменная. Измеренная освещенность на улице (По умолчанию 15%)

int  TEMPMINZ = 15;  // Переменная. Уставка сигнализации минимальной температуры в зале    (По умолчанию 15гр.*С)
int  TEMPMINU = -25; // Переменная. Уставка сигнализации минимальной температуры на улице  (По умолчанию -25гр.*С)
int  TEMPMINK = 10;  // Переменная. Уставка сигнализации минимальной температуры в радиаторе   (По умолчанию 10гр.*С)
int  TEMPMINP = 1;   // Переменная. Уставка сигнализации минимальной температуры в подполе (По умолчанию 1гр.*С)

int  TEMPMAXZ = 31;  // Переменная. Уставка сигнализации максимальной температуры в зале    (По умолчанию 31гр.*С)
int  TEMPMAXU = 40;  // Переменная. Уставка сигнализации максимальной температуры на улице  (По умолчанию 40гр.*С)
int  TEMPMAXK = 77;  // Переменная. Уставка сигнализации максимальной температуры в радиаторе   (По умолчанию 77гр.*С)
int  TEMPMAXP = 25;  // Переменная. Уставка сигнализации максимальной температуры в подполе (По умолчанию 25гр.*С)

//_______Все для циклов SavePar(),PrintPar(),ReadPar()____________________________________________________
#include <EEPROM.h>  // библиотека для записи в память микроконтроллера
int Epause_K; // Переменная печати времени выдержки спец из памяти
int Epause_V; // Переменная печати времени выдержки спец из памяти
int Epause_Z; // Переменная печати времени выдержки спец из памяти
int Epause_S; // Переменная печати времени выдержки спец из памяти

//_______Все для цикла void irremote()____________________________________________________________________

#include <IRremote.h>// удалил 2 фаила из библиотеки ремоте туул
//как исправить косяк с конфликтом таймеров при работе библиотеки IRremote и функции Tone
// http://www.arduino.ru/forum/programmirovanie/motor-shield-v3-podklyuchen... 

IRrecv irrecv(8);

decode_results results;

//_______Все для цикла void otoplenie()____________________________________________________________________

int tempDust = 22;     // Уставка желаемой температуры в доме (По умолчанию 22гр.С)
int tempDECOust = 15;  // Уставка температуры в доме в режиме "Экономия"(По умолчанию 15гр.С)
// http://blockduino.blogspot.ca/2013/08/Password-Keypad-w-Sound.html кодовый замок

#include <stDHT.h>     //библиотека датчика DTH11
//#define DHT22PIN 6     //Датчик DTH11 на pin6
DHT sens(DHT22);


#include <DS1307.h> //Подключение модуля DS1307
DS1307 rtc(20,21);//(sda 20,scl 21)
Time t;

int RTCSekunda;              // Переменная "секунда" для суточного таймера цикл RTCtimer()
int RTCChas;                 // Переменная "час" для суточного таймера цикл RTCtimer()
int RTCMinuta;               // Переменная "минута" для суточного таймера

boolean statusKur=false;     // Флаг "работа курантов" 

boolean statusDay=false;     // Флаг "Режим работы true - дневной, false - ночной"

boolean SMSDvigenieK=false;  // Флаг "Отправлена СМС о движении на кухне"
boolean SMSDvigenieV=false;  // Флаг "Отправлена СМС о движении в ванной"
boolean SMSDvigenieZ=false;  // Флаг "Отправлена СМС о движении в зале"
boolean SMSDvigenieS=false;  // Флаг "Отправлена СМС о входе"
boolean SMSopenKal=false;    // Флаг "Отправлена СМС открыта калитка"
boolean SMSopenBan=false;    // Флаг "Отправлена СМС открыта баня"
boolean SMSdomofon=false;    // Флаг "Отправлена СМС Кто там? Кто там?"
boolean SMSVoltOFF=false;    // Флаг "Отправлена СМС об отключении питания 220в"
boolean SMSVoltON=false;     // Флаг "Отправлена СМС о восстановлении питания 220в"
boolean SMSBanyaTemp=false;  // Флаг "Отправлена СМС о предельной температуре в бане"
boolean SMSPodpol=false;     // Флаг "Отправлена СМС об затоплении подпола"
boolean SMSFireSensor=false; // Флаг "Отправлена СМС о сработке дымового датчика"
boolean SMSFireAlarm=false;  // Флаг "Отправлена СМС о сработке пожарной сигнализации"
boolean SMSDelete=false;     // Флаг "Удалены все СМС на SIM900"
boolean TimeSMSzapros=false; // Флаг "Отправлена СМС о состоянии дома по таймеру"
boolean SMSAlarmTemp=false;  // Флаг "Отправлена СМС о критической температуре"
boolean SMSVoltIBP=false;    // Флаг "Отправлена СМС о низком заряде аккумулятора"
//boolean EcoTempDust=false;   // Флаг "Экономия отопления"
int SMSschet=0;        // Подсчет кол-ва отправленных смс
int Fireschet=0;       // Подсчет кол-ва срабатываний пож.шлейфа
int dsshet=0;          // Подсчет кол-ва ошибок DS18B20
int dhtschet=0;        // Подсчет кол-ва ошибок DHT11
int dht2schet=0;       // Подсчет кол-ва повторных ошибок DHT11
int Dayschet=0;        // Подсчет кол-ва дней бесперебойной работы после последней прошивки

int   vlaga=0;         // Значение влажности в цикле ventilyaciya()
int pambilang;         // переменная для цикла sirena()

//_______Все для цикла void voltmetr()
float vout = 0.0;      // Напряжение на входе аналового входа
float Vpit = 0.0;      // Измеряемое напряжение на выходе ИБП
  int volt = 0;        // Напряжение на входе АЦП

int statushome=0;      // переменная статуса включения умного дома 1 - включен, 0 -выключен
int statusotp=0;       // статус отопления дома                0 - откл , 1- вкл , 2- экономия
int statusrzd=0;       // статус питания розеток дома          0 - откл , 1- вкл
int statusgaraj=0;     // статус питания гаража                0 - откл , 1- вкл
int statusbania=0;     // статус питания бани                  0 - откл , 1- вкл
int statusPump=0;      // статус питания станции водоснабжения 0 - откл , 1- вкл
int perimetr=0;        // статус включения охраны периметра    0 - откл , 1- вкл
int statusperimetr=0;  // статус периметра        1 - все двери закрыты , 0 - дверь не закрыта
int statuspoliv=0;     // статус полива                        0 - откл , 1- вкл , 2- Таймер
int statusAlarm=0;     // Переменная "Наличие тревоги"
int AlarmTemp=0;       // Переменная "Наличие тревоги по критической температуре"
int statusFireAlarm=1; // Переменная "Режим работы пож.сигнализации" - 0 - откл , 1- вкл , 2- проверка, 3-в тревоге
int signaliz=0;        // Переменная "Режим работы охр.сигнализации" - 0 - откл , 1- вкл , 2- постановка на охрану, 3-в тревоге
int statusPIK=0;       // статус работы тональной пищалки            - 0 - откл , 1- вкл
int ULsvet=2;          // Режим работы уличного освещения            - 0 - откл , 1- вкл , 2- АВТОРЕЖИМ

boolean statusBlock=false;  // статус блокировки освещения зала пользователем

int intervalPIK = 1000;//  интервал для цикла Pik()
int TonPIK = 2500;     //  частота тона пищалки

//_________ Уставки для работы по расписанию________________________
int TimeOFFpump = 0;     // Время выключения насосной станции  (По умолчанию 0:00)
int TimeONperimetr = 23; // Время включения охраны периметра   (По умолчанию 23:00)
int TimeOFFperimetr = 6; // Время выключения охраны периметра   (По умолчанию 6:00)
int TimeONdren = 20;     // Время включения дренажного насоса  (По умолчанию 20:00)
int TimeOFFdren = 21;    // Время выключения дренажного насоса (По умолчанию 21:00)
int TimeONnagr  = 4;     // Время включения нагревателя воды   (По умолчанию 06:00)
int TimeOFFnagr = 22;    // Время выключения нагревателя воды  (По умолчанию 23:00)

//_________ флаги для таймеров______________________________________
boolean Timer1On = false;  //Флаг таймера РЕЗЕРВ
boolean Timer2On = false;  //Флаг таймера постановки на охрану

//_________ переменные времени для таймеров_________________________
unsigned long EndPikMillis = 0; // храним время последнего тона для цикла Pik()
unsigned long NowTime1 = 0;         // переменная хранения времени таймера №1 
unsigned long StartTime1 = 0;       // переменная хранения времени запуска таймера №1 
unsigned long NowTime2 = 0;         // переменная хранения времени таймера №2 
unsigned long StartTime2 = 0;       // переменная хранения времени запуска таймера №2 


//_________ флаги для цикла Kvitirovanie()(сброс звука сирены)______________________________________
boolean KvitDI30 = false;     //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход 30
boolean KvitDI29 = false;     //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход 29
boolean KvitDI31 = false;     //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход 31
boolean KvitZalC = false;     //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура зал
boolean KvitUlicaC = false;   //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура улицы
boolean KvitKuhnyaC = false;  //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура кухни
boolean KvitPodpolC=false;    //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. температура в подполе  

//boolean KvitAI14 = false; //Флаг. false = Квитирование выкл., true - Квитирование уже вкл. Вход A14

long previousMillis = 0;    // храним время последнего замера влажности для цикла izmereniya()
long interval = 120000;     // интервал между замерами параметров для цикла  izmereniya() 2 минуты 

//______ Переменные для цикла avtosvet() взято с http://zelectro.com.ua/PIR_sensor ___________________________
long unsigned int lowIn_K;  // Время, в которое был принят сигнал отсутствия движения на кухне(LOW)
long unsigned int lowIn_V;  // Время, в которое был принят сигнал отсутствия движения в ванной(LOW)
long unsigned int lowIn_Z;  // Время, в которое был принят сигнал отсутствия движения в зале(LOW)
long unsigned int lowIn_S;  // Время, в которое был принят сигнал отсутствия движения в сенях(LOW)
int pause_K = 1; //Пауза, после которой движение считается оконченным (1 мин)
int pause_V = 1; //Пауза, после которой движение считается оконченным (1 мин)
int pause_Z = 4; //Пауза, после которой движение считается оконченным (4 мин)
int pause_S = 1; //Пауза, после которой движение считается оконченным (1 мин)
boolean lockLow_K = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean lockLow_V = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean lockLow_Z = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean lockLow_S = true; //Флаг. false = значит движение уже обнаружено, true - уже известно, что движения нет
boolean takeLowTime_K; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
boolean takeLowTime_V; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
boolean takeLowTime_Z; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
boolean takeLowTime_S; //Флаг. Сигнализирует о необходимости запомнить время начала отсутствия движения
int pirPin_K = 26;    //вывод подключения PIR датчика Кухни
int pirPin_V = 24;    //вывод подключения PIR датчика Ванной
int pirPin_Z = 22;    //вывод подключения PIR датчика Зал
int pirPin_S = 28;    //вывод подключения PIR датчика Сени

//_______Для работы терминала по  bluetooth___________________________
int inSize=0;  // Переменная которая будет содержать размер буфера терминала bluetooth
char str[128]; // Так как типа string тут нет, будем использовать массив символов

//_______Для работы терминала по  Sim900______________________________

String currStr = "";
boolean isStringMessage = false;  // Переменная принимает значение True, если текущая строка является сообщением

//___________________ Стартовый цикл _________________________________

void setup()

{

WDTCSR=(1<<WDCE)|(1<<WDE); //установить биты WDCE WDE (что б разрешить запись в другие биты

WDTCSR=(1<<WDIE)| (1<<WDP2)|(1<<WDP1); // разрешение прерывания + выдержка 1 секунда


  
 // ds.begin();
 // ds.setResolution(ZalC, 10);   
 // ds.setResolution(UlicaC, 10); 
  //ds.setResolution(KuhnyaC, 10); 
  
  pinMode(22, INPUT); digitalWrite(22,HIGH);    // вход датчик движения зал
  pinMode(24, INPUT); digitalWrite(24,HIGH);    // вход датчик движения ванна
  pinMode(26, INPUT); digitalWrite(26,HIGH);    // вход датчик движения кухня
  pinMode(28, INPUT); digitalWrite(28,HIGH);    // вход датчик движения сени
  pinMode(30, INPUT); digitalWrite(30,HIGH);    // вход сигнализатор "Вода в подполе"
  pinMode(32, INPUT); digitalWrite(32,HIGH);    // Резерв
  pinMode(34, INPUT); digitalWrite(34,HIGH);    // Резерв
  pinMode(36, INPUT); digitalWrite(36,HIGH);    // Кнопка звонка домофона
  
  pinMode(23, INPUT); digitalWrite(23,HIGH);    // вход концевики ворот
  pinMode(25, INPUT); digitalWrite(25,HIGH);    // вход концевик входной двери
  pinMode(27, INPUT); digitalWrite(27,HIGH);    // вход концевик двери бани
  pinMode(29, INPUT); digitalWrite(29,HIGH);    // вход термостат "Баня готова"
  pinMode(31, INPUT); digitalWrite(31,HIGH);    // вход термостат "Очень высока температура в бане"
  pinMode(33, INPUT); digitalWrite(33,HIGH);    // Дымовой шлейф №1
  pinMode(35, INPUT); digitalWrite(35,HIGH);    // Дымовой шлейф №2
  pinMode(37, INPUT); digitalWrite(37,HIGH);    // Нет напряжения после УЗО
    
  pinMode( 5, OUTPUT);     // Пьезо динамик
  pinMode(13, OUTPUT);     // Лампа УД включен
  
  pinMode(38, OUTPUT);     // Свет в Кухня
  pinMode(40, OUTPUT);     // Свет в Ванна
  pinMode(42, OUTPUT);     // Свет в Зал
  pinMode(44, OUTPUT);     // Свет в Сени
  pinMode(46, OUTPUT);     // Питание насосной станции
  pinMode(48, OUTPUT);     // Питание дренажного насоса
  pinMode(50, OUTPUT);     // Питание водонагревателя
  pinMode(52, OUTPUT);     // Освещение двора
  
  digitalWrite(38,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  digitalWrite(40,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  digitalWrite(42,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  digitalWrite(44,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  digitalWrite(46,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  digitalWrite(48,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  digitalWrite(50,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  digitalWrite(52,HIGH);   // Подаем единицы на плату реле (сигнал инвентированный)
  
  pinMode(39, OUTPUT);     // Питание гаража
  pinMode(41, OUTPUT);     // Питание бани
  pinMode(43, OUTPUT);     // Питание розеток дома 
  pinMode(45, OUTPUT);     // Питание вентиляции
  
  pinMode(47, OUTPUT);     // Клапан полива
  pinMode(49, OUTPUT);     // Сирены
  pinMode(51, OUTPUT);     // Номер дома
  pinMode(53, OUTPUT);     // Управление отоплением
  
  Serial.begin(9600);      // Связь по терминалу
  Serial1.begin(9600);     // HC-05 Bluetooth http://robocraft.ru/blog/electronics/587.html#comment4652
  Serial2.begin(19200);     // GSM SMS-передача плата SIM900
  //Serial3.begin(9600);    // Плата голосового оповещения на attiny2313 и SD-карте
  if(EEPROM.read(0)==10){ReadPar();} // Чтение настроек из памяти, если они туда были сохранены ранее
  delay(2000);
  SMSVoltON=true;
  NastroykaGSM();           // Настройка работы с SIM900
  irrecv.enableIRIn();      // Запуск ИК-приемника
  tone(5, 2000, 200);       // Звук, когда все готово!  выключил
  delay(4000);
  t = rtc.getTime();
  RTCChas = t.hour;   // t.hour - запрос часов
  RTCMinuta = t.min;  // t.min  - запрос минут
  SMSschet = EEPROM.read(51); // чтение  кол-ва ранее отправленных СМС
  startOneSMS();
  Serial2.print("SmartHome vkluchen - "); vremya2();  EndSMS();// время включения
}

void loop()
{
   RTCtimer();
   izmereniya();
   alarms();
   irremote();
   bluetooth();
   sms_read();
   osvechenie(); // Управление освещением во дворе

   if (!statusFireAlarm==0){FireAlarm();}                                     // Работа пожарной сигнализации
   if (statushome==1) {avtosvet();}                                           // Автоматическое управление освещением в доме меньше 11%
   if (statushome==1){digitalWrite(13,HIGH);}   else {digitalWrite(13, LOW);} // Лампа "Умный дом включен"
   //if (statushome==1){ventilyaciya();}                                      // Управление вентиляцией в подполе по датчику влажности DHT11 
   if (statusotp==1) {otoplenie();} else {digitalWrite(53, LOW);}             // Управление работой газового котла 1 - вкл., 0 - откл.
   if (!signaliz==0){signalizSMS();}                                          // Работа сигнализации сигнализации при режимах 1,2,3
   if (statusPIK==1){Pik();}                                                  // Работа тональной пищалки
   if (perimetr==1){Operimetr();}                                             // Охрана периметра участка
   if ((statusPump==1) && (digitalRead(30)==LOW)) {digitalWrite(46,LOW);} else {digitalWrite(46, HIGH);} // Питание станции водоснабжения (Сигнал инвертированный)
   if (statusrzd==1){digitalWrite(43,HIGH);}    else {digitalWrite(43, LOW);} // Питание розеток дома 
   if (statusgaraj==1){digitalWrite(39,HIGH);}  else {digitalWrite(39, LOW);} // Питание гаража
   if (statusbania==1){digitalWrite(41,HIGH);}  else {digitalWrite(41, LOW);} // Питание бани
   if (statuspoliv==0) {digitalWrite(47, LOW);}                               // Выключение клапана полива
   if (statuspoliv==1) {digitalWrite(47, HIGH);}                              // Включение клапана полива на постоянку
   if (statuspoliv==2) {digitalWrite(47, HIGH); timerPoliv();}                // Клапан полива включен по таймеру
   if ((perimetr==1 && statusperimetr==0) || statusAlarm==1) { sirena();}     // Работа малой сирены
   
   //if (analogRead(14)>100)    {KvitAI14=false;}                       // Сброс квитирования при возвращении параметра в норму
   if (digitalRead(29)==LOW)  {KvitDI29=false;}                         // Сброс квитирования при возвращении параметра в норму
   if (digitalRead(30)==LOW)  {KvitDI30=false;}                         // Сброс квитирования при возвращении параметра в норму
   if (digitalRead(31)==LOW)  {KvitDI31=false;}                         // Сброс квитирования при возвращении параметра в норму

}

void izmereniya()   //  Замер температур с датчиков DS18B20 и влажности с датчика DHT11 

{  // http://arduino.ru/tutorials/BlinkWithoutDelay на основе
   unsigned long currentMillis = millis();
   if(currentMillis - previousMillis > interval) { // Замеры в интервале 
    //dht.read(DHT11PIN);                  // Замеры температур с DHT11
    int t = sens.readTemperature(3); // чтение датчика на пине 2
  int h = sens.readHumidity(3);    // чтение датчика на пине 2
  

delay(100);                          // Необязательная задержка
    // vlaga = dht.humidity;                // Уровень влажности % с DHT11
    // TempPodpol = dht.temperature;        // Температура в подполе  с DHT11
    // if (TempPodpol < 3 || TempPodpol > 35){ // Перезапрос. Борьба с помехами.
      // dhtschet++;                           // +1 к счетчику ошибок DHT11
      // delay(300);                           // Необязательная задержка
      // dht.read(DHT11PIN);                   // Замеры температур с DHT11
      // vlaga = dht.humidity;                 // Уровень влажности % с DHT11
     //  TempPodpol = dht.temperature;         // Температура в подполе  с DHT11
    // if (TempPodpol < 3 || TempPodpol > 35){ // Перезапрос. Борьба с помехами.
    //   dht2schet++;                          // +1 к счетчику повторных ошибок DHT11
     
    //   }
    }



  ISR (WDT_vect)  { //вектор прерывания W

static boolean n=0; // флаг работы: запрос температуры или её чтение

n=!n;

if (n) {ds.reset();  // сброс шины
        ds.write(0xCC);//обращение ко всем датчикам
        ds.write(0x44);// начать преобразование (без паразитного питания) 
       }
else   {ds.reset();
        ds.select(KuhnyaC);   
        ds.write(0xBE); // Read Scratchpad (чтение регистров) 
        TempKuhnyaC =  ds.read() | (ds.read()<<8); //прочитаны 2 байта      
        TempKuhnyaC = TempKuhnyaC / 16;
        // получение с 2-го датчика
        ds.reset();
        ds.select(ZalC);   
        ds.write(0xBE); // Read Scratchpad (чтение регистров) 
        TempZalC =  ds.read() | (ds.read()<<8); //прочитаны 2 байта 
        TempZalC = TempZalC/16;
        ds.reset();
        ds.select(UlicaC);   
        ds.write(0xBE); // Read Scratchpad (чтение регистров) 
        TempUlicaC =  ds.read() | (ds.read()<<8); //прочитаны 2 байта      
        TempUlicaC = TempUlicaC / 16;
        // получение с 3-го датчика
        ds.reset();
       ds.select(FreezeC);   
        ds.write(0xBE); // Read Scratchpad (чтение регистров) 
        TempFreezeC =  ds.read() | (ds.read()<<8); //прочитаны 2 байта 
        TempFreezeC = TempFreezeC/16 ;
}

}

    // ds.requestTemperatures();            // Замеры температур с DS18B20
    // delay(750);                          // Необязательная задержка
   // TempZalC    = ds.getTempC(ZalC);     // Считываем температуру в зале
    // delay(100);
    // TempUlicaC  = ds.getTempC(UlicaC);   // Считываем температуру на улице
    // delay(100);
    // TempKuhnyaC = ds.getTempC(KuhnyaC);  // Считываем температуру в кухне
    // delay(100);
    // if(TempZalC== -127 || TempUlicaC== -127 || TempKuhnyaC== -127) // Перезапрос при ошибке датчика
    // {
     //  ds.requestTemperatures(); delay(750); dsshet++ ; // +1 к счетчику ошибок DS18B20
     //  TempZalC    = ds.getTempC(ZalC);     // Считываем температуру в зале
     //  delay(100);
     //  TempUlicaC  = ds.getTempC(UlicaC);   // Считываем температуру на улице
     //  delay(100);
     //  TempKuhnyaC = ds.getTempC(KuhnyaC);  // Считываем температуру в кухне
     //  delay(100);
     // }
    { 
     UlicaS = analogRead(A15)/10;           // Считываем освещенность на улице
     voltmetr();                            // Считываем напряжения на выходе ИБП (норма 13,5в)
     previousMillis = currentMillis;}       // Сброс таймера
}



void voltmetr()  //____________Цикл "Вольтметр"__измерение напряжения на выходе ИБП
// Взято с http://digitrode.ru/computing-devices/mcu_cpu/87-voltmetr-na-arduino.html
{
   volt = analogRead(A0);                       // А0 аналоговый вход вольтметра
   vout = (volt * 5.0) / 1024.0;             
   Vpit = vout / (10000.0/(100000.0+10000.0));  // По формуле Vpit = vout / (R2/(R1+R2)) 
   if (Vpit<0.09) { Vpit=0.0;}                  // Округление до нуля 
}

void osvechenie() // Работа уличного освещения двора
{
 if ( ULsvet==2 )   // Если режим работы автоматический
 {
  if (UlicaS > 8){digitalWrite(52,HIGH);}  // Освещение двора выключить при освещении больше 8%  (сигнал инвертированный)
  if (UlicaS < 4) {digitalWrite(52,LOW);}  // Освещение двора включить при освещении меньше 4% (сигнал инвертированный)
 }
}
  
void avtosvet()   //______Цикл управления автоматическим освещением____________________________________
{

  //______Ниже для зала______________________________________
  if(digitalRead(pirPin_Z) == HIGH && statusBlock==false && UlicaS < 30) //Если обнаружено движение, нет блокировки, и освещенность улицы меньше 20%
  {    
    if(lockLow_Z) //Если до этого момента еще не включили реле
    { lockLow_Z = false; digitalWrite(42, LOW); delay(50);}     //Включаем свет.     
    takeLowTime_Z = true;
  }  
  if(digitalRead(pirPin_Z) == LOW) //Ели движения нет
  { //Если время окончания движения еще не записано     
    if(takeLowTime_Z){lowIn_Z = millis();takeLowTime_Z = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
    if(!lockLow_Z && millis() - lowIn_Z > (pause_Z * 60000))               //Если время без движение превышает паузу => движение окончено
    { lockLow_Z = true; digitalWrite(42, HIGH); delay(50);}      //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения                
  } 
  if (statushome==1 && UlicaS > 35) {digitalWrite(42,HIGH);}     // Отключение реле управления освещением больше 35%

  //______Ниже для кухни______________________________________
  if(digitalRead(pirPin_K) == HIGH && statusDay==false && UlicaS < 30) //Если обнаружено движение с 23 до 8 включаем подсветку
  {    
    if(lockLow_K) //Если до этого момента еще не включили реле
    { lockLow_K = false; digitalWrite(38, LOW); delay(50);}   //Включаем свет.     
    takeLowTime_K = true;}  
  if(digitalRead(pirPin_K) == LOW) //Ели движения нет
  { //Если время окончания движения еще не записано     
    if(takeLowTime_K){lowIn_K = millis();takeLowTime_K = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
    if(!lockLow_K && millis() - lowIn_K > (pause_K * 60000))     //Если время без движение превышает паузу => движение окончено
    { lockLow_K = true; digitalWrite(38, HIGH); delay(50);}      //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения                
  }
  if (statushome==1 && UlicaS > 35) {digitalWrite(38,HIGH);}     // Отключение реле управления освещением больше 20%

  //______Ниже для ванной комнаты_____________________________
  if(digitalRead(pirPin_V) == HIGH && UlicaS < 30) //Если обнаружено движение
  {    
    if(lockLow_V) //Если до этого момента еще не включили реле
    { lockLow_V = false; digitalWrite(40, LOW); delay(50);}     //Включаем свет.     
    takeLowTime_V = true;}  
  if(digitalRead(pirPin_V) == LOW) //Ели движения нет
  { //Если время окончания движения еще не записано     
    if(takeLowTime_V){lowIn_V = millis();takeLowTime_V = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
    if(!lockLow_V && millis() - lowIn_V > (pause_V * 60000))     //Если время без движение превышает паузу => движение окончено
    { lockLow_V = true; digitalWrite(40, HIGH); delay(50);}      //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения                
  }
  if (statushome==1 && UlicaS > 35) {digitalWrite(40,HIGH);}     // Отключение реле управления освещением больше 35%

  //______Ниже для сеней______________________________________
  if(digitalRead(pirPin_S) == HIGH && UlicaS < 16) //Если обнаружено движение
  {    
    if(lockLow_S) //Если до этого момента еще не включили реле
    { lockLow_S = false; digitalWrite(44, LOW); delay(50);}     //Включаем свет.     
    takeLowTime_S = true;}  
  if(digitalRead(pirPin_S) == LOW) //Ели движения нет
  { //Если время окончания движения еще не записано     
    if(takeLowTime_S){lowIn_S = millis();takeLowTime_S = false;} //Сохраним время окончания движения изменим значения флага, чтобы больше не брать время, пока не будет нового движения
    if(!lockLow_S && millis() - lowIn_S > (pause_S * 60000))               //Если время без движение превышает паузу => движение окончено
    { lockLow_S = true; digitalWrite(44, HIGH); delay(50);}      //Изменяем значение флага, чтобы эта часть кода исполнилась лишь раз, до нового движения                
  }
  if (statushome==1 && UlicaS > 20) {digitalWrite(44,HIGH);}     // Отключение реле управления освещением больше 20%
}

//   void ventilciya()
//     {
//   if (vlaga > 60) {digitalWrite(45, HIGH);} // Включение вентилятора при влажности более 60%
//   if (vlaga < 40) {digitalWrite(45, LOW);}  // Выключение вентилятора при влажности менее 40%
//   }



void homeON() //____________Цикл включения умного дома____________________________________________________
{
  statushome=1;      // статус умного дома                   0 - откл , 1- вкл
//  statusotp=1;       // статус отопления дома                0 - откл , 1- вкл
  statusrzd=1;       // статус питания розеток дома          0 - откл , 1- вкл
//  statusgaraj=1;     // статус питания гаража                0 - откл , 1- вкл
//  statusbania=1;     // статус питания бани                  0 - откл , 1- вкл    
}

void homeOFF() //____________Цикл выключения умного дома________________________
{
  statushome=0;      // статус питания дома                  0 - откл , 1- вкл
  statusrzd=0;       // статус питания розеток дома          0 - откл , 1- вкл
  statusgaraj=0;     // статус питания гаража                0 - откл , 1- вкл
  statusbania=0;     // статус питания бани                  0 - откл , 1- вкл
  statusPump=0;      // статус питания станции водоснабжения 0 - откл , 1- вкл
  digitalWrite(38,HIGH); // выключение реле (сигнал инвертированный)
  digitalWrite(40,HIGH); // выключение реле (сигнал инвертированный)
  digitalWrite(42,HIGH); // выключение реле (сигнал инвертированный)
  digitalWrite(44,HIGH); // выключение реле (сигнал инвертированный)  
  digitalWrite(46,HIGH); // выключение реле (сигнал инвертированный)
  digitalWrite(48,HIGH); // выключение реле (сигнал инвертированный)  
  digitalWrite(50,HIGH); // выключение реле (сигнал инвертированный)    
  SMSAlarmTemp=false;   // сброс флага отправки СМС о критической темпертуры
  SMSBanyaTemp=false;   // сброс флага отправки СМС о критической темпертуры в бане
  SMSPodpol=false;      // сброс флага отправки СМС о воде в подполе
}


void otoplenie() // Цикл управления газовым котлом (Сигнал инвертированный!(Особенность подключения к котлу))
{
  if ( statusotp==0) // Отключено
     {  digitalWrite(53,HIGH);} // Отключить отопление
  
  if ( statusotp==1) // Климат-контроль
     {  if ( TempZalC > (tempDust+1)){digitalWrite(53,HIGH);} // Отключить отопление если температура больше желаемой на 1грС
        if ( !TempZalC== -127 && (TempZalC < tempDust) )   {digitalWrite(53,LOW);}  // Включить отопление если температура меньше желаемой
     }
  if ( statusotp==2) // Экономия
     {  if ( TempZalC > (tempDECOust+1)){digitalWrite(53,HIGH);} // Отключить отопление если температура больше желаемой на 1грС
        if ( !TempZalC== -127 && (TempZalC < tempDECOust) )   {digitalWrite(53,LOW);}  // Включить отопление если температура меньше желаемой
     }
}  

void timerPoliv()    // Таймер клапана полива огорода 0 - откл , 1- вкл , 2- Таймер
{

  NowTime1 = millis();
  if(Timer1On == true) { StartTime1 = NowTime1 ; Timer1On = false; statuspoliv=2;}
  if( statuspoliv==2 && NowTime1 - StartTime1 > 900000) // выдержка 15 минут
    { statuspoliv=0; } // Сброс таймера
}

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

у тебя вектор прерывания  ISR (WDT_vect)  находится в цикле izmereniya (), то есть в  loop. Нужно вытащить его за луп. как бы смешно это не звучало. 

balbes323
Offline
Зарегистрирован: 06.12.2016

Serg1 мне кажется, у меня есть, что тебе нужно, завтра выложу в гугл, сброшу тебе ссылку.

Serg1
Offline
Зарегистрирован: 04.12.2015

MaksVV, спасибо, скомпилировалось без ошибок.

balbes323
Offline
Зарегистрирован: 06.12.2016

Serg1, вот. Спасибо одному хорошему парню, который выложил основную часть кода. Я туда прикрутил GSM, но надо бы доработать, чтобы можно было значения из текста смс вытащить и куда нужно вставить. Пока с этим не разобрался, если кто поможет, буду очень благодарен. Использовал nano v3, сим900, дисплей 1602, энкодер, плату реле, часы 3231, пищалку.Подключил микрофон от мобилы и динамик, можно с него позвонить и поговорить с хозяином.В качестве питания ББП20 с акб 1,2 А*ч,  на 10 часов при отключении хватает. Позже добавлю контроль 220в. Понравился алгоритм измерения температуры с датчика, глюков не заметил.

#include <Wire.h> // i2c (для RTC)
#include <RealTimeClockDS1307.h> // RTC
#include <EEPROM.h> // EE
#include <LiquidCrystal.h> // LCD 16*2
#include <TimerOne.h> // прерывания по таймеру1 
#include <OneWire.h> // 1wire для DS18B20
#include <DallasTemperature.h> // DS18B20
 
#define ONE_WIRE_BUS 4
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
DeviceAddress DS18B20Address;
#define encoderA    2 // энкодер - поворот вправо (об землю)
#define encoderB    3 // энкодер - поворот влево (об землю)
#define encoderK    A3 // энкодер - кнопка (об землю)
#define BeepPin     11 // пищалка
#define BeepToneNo  2000 // тон звука "No", герц
#define BeepToneYes 4000 // тон звука "Yes", герц
#define BeepToneNoDuration 200 // длительность звука "No", мс
#define BeepToneYesDuration 200 // длительность звука "Yes", мс
#define Relay  12 // нога, к которой подключено реле
#define RelayOn LOW // полярность сигнала включения реде (HIGH/LOW)
 
// LCD connection RS, E, D4, D5, D6, D7
// R/W - to ground
LiquidCrystal lcd(10, 9, 8, 7, 6, 5);
 
byte block1[8] = {
  0x06,0x09,0x09,0x06,0x00,0x04,0x0E,0x1F }; // значок градуса с пламенем снизу
byte block2[8] = {
  0x06,0x09,0x09,0x06,0x00,0x00,0x00,0x00 }; // значок градуса
 
 String currStr = "";
boolean isStringMessage = false;  // Переменная принимает значение True, если текущая строка является сообщением

#define TstatTimerMax 120 //минимальная пауза между включениями горелки, сек
unsigned int TstatTimer = 20; //таймер паузы между включениями/выключениями, начальная установка 20 сек для устаканивания системы после сброса
 
float DS18B20Temperature = 0; //сырая температура от датчика
float Temperature = 0; //вычисленная температура с коррекцией
float DS18B20TempTmp; //времянка
byte DS18B20iteration = 0; //счётчик измерений температуры для усреднения
 
float TstatTemp = 23; //температура термостатирования, может изменяться настройками
float TemperatureCorr = 0; //коррекция температуры, может изменяться настройками
float Hysteresis = 0.1; // гистерезис термостата, может изменяться настройками
float HysteresisOld; 
int Hours = 0; // времянка часов RTC для отображения и установки
int Minutes = 0; // времянка минут RTC для отображения и установки
int Seconds;
boolean PrintYesNo = false; // показывать ли после времени Yes/No (косвенно - указание на режим установка/отображение)
boolean SetH = false; // выделение часов при отображении
boolean SetM = false; // выделение минут при отображении
boolean SetYesNo = false; // выделение Yes/No при установке часов
 
boolean blink500ms = false; // мигающий бит, инвертируется каждые 500мс
boolean plus1sec = false; // ежесекундно взводится
boolean Zvonok = true;
boolean BeepEnabled = true; 
byte MenuTimeoutTimer;
 
byte Timer1Hours = 0;
byte Timer1Minutes = 0;
boolean Timer1Enabled = false;
boolean Timer1Activated = false;
float Timer1Temp = 23; //температура термостатирования по таймеру1, может изменяться настройками
byte Timer2Hours = 0;
byte Timer2Minutes = 0;
boolean Timer2Enabled = false;
boolean Timer2Activated = false;
float Timer2Temp = 23; //температура термостатирования по таймеру2, может изменяться настройками
byte Timer3Hours = 0;
byte Timer3Minutes = 0;
boolean Timer3Enabled = false;
boolean Timer3Activated = false;
float Timer3Temp = 23; //температура термостатирования по таймеру3, может изменяться настройками
float AlarmTemp = 20; // температура для замерзательного орала
 
// encoder vars
static boolean rotating=false;      // debounce management
boolean A_set = false;             
boolean B_set = false;
boolean encoderR = false;
boolean encoderL = false;
 
// EEPROM addresses
#define TstatTempEEaddr 0 // EE - адрес для сохранения температуры термостатирования, 4 байта(float)!
#define TemperatureCorrEEaddr 4 // EE - адрес для сохранения коррекции температуры, 4 байта(float)!
#define HysteresisEEaddr 8 // EE - адрес для сохранения гистерезиса, 4 байта(float)!
#define Timer1HoursEEaddr 12 // EE - адрес для сохранения часов таймера 1 (byte)
#define Timer1MinutesEEaddr 13 // EE - адрес для сохранения минут таймера 1 (byte)
#define Timer1EnabledEEaddr 14 // EE - адрес для сохранения статуса таймера 1 (boolean)
#define Timer1TempEEaddr 15 // EE - адрес для сохранения температуры таймера 1, 4 байта(float)!
#define Timer2HoursEEaddr 19 // EE - адрес для сохранения часов таймера 2 (byte)
#define Timer2MinutesEEaddr 20 // EE - адрес для сохранения минут таймера 2 (byte)
#define Timer2EnabledEEaddr 21 // EE - адрес для сохранения статуса таймера 2 (boolean)
#define Timer2TempEEaddr 22 // EE - адрес для сохранения температуры таймера 2, 4 байта(float)!
#define Timer3HoursEEaddr 26 // EE - адрес для сохранения часов таймера 3 (byte)
#define Timer3MinutesEEaddr 27 // EE - адрес для сохранения минут таймера 3 (byte)
#define Timer3EnabledEEaddr 28 // EE - адрес для сохранения статуса таймера 3 (boolean)
#define Timer3TempEEaddr 29 // EE - адрес для сохранения температуры таймера 3, 4 байта(float)!
#define BeepEnabledEEaddr 33 // EE - адрес для сохранения признака разрешения звука (boolean)
#define AlarmTempEEaddr 34 // EE - адрес для сохранения значения недопустимого снижения температуры, 4 байта(float)!
 
// ===== SETUP ========================================================================
void setup() {
  Serial.begin(19200);
  pinMode(Relay, OUTPUT);
  digitalWrite(Relay, HIGH);
  lcd.begin(16, 2);
  lcd.createChar(1, block1);
  lcd.createChar(2, block2);
  pinMode(encoderA, INPUT);
  digitalWrite(encoderA, HIGH);
  pinMode(encoderB, INPUT);
  digitalWrite(encoderB, HIGH);
  pinMode(encoderK, INPUT);
  digitalWrite(encoderK, HIGH);
  attachInterrupt(0, doEncoderA, CHANGE);   // encoder pin on interrupt 0 (pin 2)
  attachInterrupt(1, doEncoderB, CHANGE);  // encoder pin on interrupt 1 (pin 3)
  Timer1.initialize(500000); // Timer0 interrupt - set a timer of length 500000 microseconds
  Timer1.attachInterrupt( timerIsr ); // attach the service routine here
  if (EEPROM.read(Timer1HoursEEaddr) > 23) { // если первая запись однокристалки - записать начальные значения в EE
    EEPROM.write(BeepEnabledEEaddr, BeepEnabled);
    EEPROM_float_write(TstatTempEEaddr, TstatTemp);
    EEPROM_float_write(TemperatureCorrEEaddr, TemperatureCorr);
    EEPROM_float_write(HysteresisEEaddr, Hysteresis);
    EEPROM.write(Timer1HoursEEaddr, Timer1Hours);
    EEPROM.write(Timer1MinutesEEaddr, Timer1Minutes);
    EEPROM.write(Timer1EnabledEEaddr, Timer1Enabled);
    EEPROM_float_write(Timer1TempEEaddr, Timer1Temp);
    EEPROM.write(Timer2HoursEEaddr, Timer2Hours);
    EEPROM.write(Timer2MinutesEEaddr, Timer2Minutes);
    EEPROM.write(Timer2EnabledEEaddr, Timer2Enabled);
    EEPROM_float_write(Timer2TempEEaddr, Timer2Temp);
    EEPROM.write(Timer3HoursEEaddr, Timer3Hours);
    EEPROM.write(Timer3MinutesEEaddr, Timer3Minutes);
    EEPROM.write(Timer3EnabledEEaddr, Timer3Enabled);
    EEPROM_float_write(Timer3TempEEaddr, Timer3Temp);
    EEPROM_float_write(AlarmTempEEaddr, AlarmTemp);
  }
  BeepEnabled = EEPROM.read(BeepEnabledEEaddr);
  TstatTemp = EEPROM_float_read(TstatTempEEaddr);
  TemperatureCorr = EEPROM_float_read(TemperatureCorrEEaddr);
  Hysteresis = EEPROM_float_read(HysteresisEEaddr);
  Timer1Hours = EEPROM.read(Timer1HoursEEaddr);
  Timer1Minutes = EEPROM.read(Timer1MinutesEEaddr);
  Timer1Enabled = EEPROM.read(Timer1EnabledEEaddr);
  Timer1Temp = EEPROM_float_read(Timer1TempEEaddr);
  Timer2Hours = EEPROM.read(Timer2HoursEEaddr);
  Timer2Minutes = EEPROM.read(Timer2MinutesEEaddr);
  Timer2Enabled = EEPROM.read(Timer2EnabledEEaddr);
  Timer2Temp = EEPROM_float_read(Timer2TempEEaddr);
  Timer3Hours = EEPROM.read(Timer3HoursEEaddr);
  Timer3Minutes = EEPROM.read(Timer3MinutesEEaddr);
  Timer3Enabled = EEPROM.read(Timer3EnabledEEaddr);
  Timer3Temp = EEPROM_float_read(Timer3TempEEaddr);
  AlarmTemp = EEPROM_float_read(AlarmTempEEaddr);
 
  DS18B20.begin();
  DS18B20.getAddress(DS18B20Address, 0);
  DS18B20.setResolution(DS18B20Address, 12);
  DS18B20.setWaitForConversion(false);
  DS18B20.requestTemperatures();
  NastroykaGSM();
  delay(5000);
  tone(BeepPin,2000,50);
  delay(50);
  tone(BeepPin,3000,50);
  delay(50);
  tone(BeepPin,4000,50);
  delay(50);
  startOneSMS(); Serial.print("TERMOSTAT-ON"); EndSMS();
}
 
// ===== MAIN CYCLE ===================================================================
void loop()

{ 
  sms_read();
  
  lcd.setCursor(8, 0); //инфо на LCD
  if ((Temperature < AlarmTemp)&(blink500ms)) {
  lcd.print(F("*"));
  } else {
  lcd.print(F(" "));
  }
  lcd.print(F("t="));
  if (Temperature < 10) {
    lcd.print(F(" "));
  }
  lcd.print(Temperature,1);
  lcd.write(0x02); // значок градуса
 
  // если таймер 1 включен - надпись светится, если сработал - мигает
  lcd.setCursor(0, 1); //инфо на LCD
  if ((Timer1Enabled)&!((Timer1Activated)&(blink500ms))) {
    lcd.print(F("T1"));
  }
  else {
    lcd.print(F("  "));
  }
 
  // если таймер 2 включен - надпись светится, если сработал - мигает
  lcd.setCursor(3, 1); //инфо на LCD
  if ((Timer2Enabled)&!((Timer2Activated)&(blink500ms))) {
    lcd.print(F("T2"));
  }
  else {
    lcd.print(F("  "));
  }
 
  // если таймер 3 включен - надпись светится, если сработал - мигает
  lcd.setCursor(6, 1); //инфо на LCD
  if ((Timer3Enabled)&!((Timer3Activated)&(blink500ms))) {
    lcd.print(F("T3"));
  }
  else {
    lcd.print(F("  "));
  }
 
  lcd.setCursor(9, 1); //инфо на LCD
  lcd.print(F("s="));
  lcd.print(TstatTemp,1);
  if ( digitalRead(Relay) == RelayOn ) {
    lcd.write(0x01); // значок градуса с пламенем
  }
  else {
    lcd.write(0x02); // значок градуса
  }
 
  // печатаем текущее время
  PrintYesNo = false;
  PrintRTC(0,0);
 
  // термостатирование
  if ( TstatTimer == 0 )
  {
    if ( Temperature > ( TstatTemp + Hysteresis ) ) // гистерезис
    {
      if ( digitalRead(Relay) == RelayOn ) // если горелка включена -
      {
        digitalWrite(Relay, !RelayOn); // выключить горелку
        TstatTimer = TstatTimerMax; // горелку держать выключённой не менее заданного в TstatTimerMax времени
      }
    }
    if (Temperature < TstatTemp)
    {
      if ( digitalRead(Relay) == !RelayOn ) // если горелка выключена -
      {
        digitalWrite(Relay, RelayOn); // включить горелку
        TstatTimer = TstatTimerMax; // горелку держать включённой не менее заданного в TstatTimerMax времени
      }
    }
  }
   
  // если прошла 1 секунда - делаем ежесекундные дела
  if (plus1sec) {
    plus1sec = false; // сбрасываем до следующей секунды
    // обновляем часы
    RTC.readClock();
    Hours=RTC.getHours();
    Minutes=RTC.getMinutes();
    Seconds=RTC.getSeconds();
 
    // измеряем температуру воздуха
    DS18B20TempTmp = DS18B20.getTempCByIndex(0); // получить температуру от датчика
    DS18B20.requestTemperatures();  // запустить новое измерение
    if (DS18B20TempTmp != -127)
    {
    DS18B20Temperature += DS18B20TempTmp; // суммируем для усреднения
    DS18B20iteration ++;
    if (DS18B20iteration == 10)
      {
      DS18B20iteration = 0;
      Temperature = (DS18B20Temperature / 10) + TemperatureCorr; //усреднённая + коррекция
      DS18B20Temperature = 0;
      }
    }
     
    // если уставку термостата поменяли вручную - запись её в EE, не чаще 1 раза в минуту
    //(экономия ресурса EE)
    if ((EEPROM_float_read(TstatTempEEaddr) != TstatTemp)&(Seconds == 0)) {
      EEPROM_float_write(TstatTempEEaddr, TstatTemp);
    }
 
    // проверка Timer1 и изменение уставки термостата при совпадении   
    if ((Hours == Timer1Hours)&(Minutes == Timer1Minutes)&(Timer1Enabled)&(Seconds == 0)) { // время T1 совпадает с RTC
      Timer1Activated = true;
      Timer2Activated = false;
      Timer3Activated = false;
      TstatTemp = Timer1Temp;
      EEPROM_float_write(TstatTempEEaddr, TstatTemp);
      if (BeepEnabled) {
        tone(BeepPin,4000,5);
      }
    }
 
    // проверка Timer2 и изменение уставки термостата при совпадении   
    if ((Hours == Timer2Hours)&(Minutes == Timer2Minutes)&(Timer2Enabled)&(Seconds == 0)) { // время T2 совпадает с RTC
      Timer1Activated = false;
      Timer2Activated = true;
      Timer3Activated = false;
      TstatTemp = Timer2Temp;
      EEPROM_float_write(TstatTempEEaddr, TstatTemp);
      if (BeepEnabled) {
        tone(BeepPin,4000,5);
      }
    }
 
    // проверка Timer3 и изменение уставки термостата при совпадении   
    if ((Hours == Timer3Hours)&(Minutes == Timer3Minutes)&(Timer3Enabled)&(Seconds == 0)) { // время T3 совпадает с RTC
      Timer1Activated = false;
      Timer2Activated = false;
      Timer3Activated = true;
      TstatTemp = Timer3Temp;
      EEPROM_float_write(TstatTempEEaddr, TstatTemp);
      if (BeepEnabled) {
        tone(BeepPin,4000,5);
      }
    }
 
 
    if (Temperature < AlarmTemp) {
    tone(BeepPin,4000,5);
    }
  }
 
  // обработка поворота энкодера на лету (ручное изменение уставки температуры))
  rotating = true;  // reset the debouncer
  if ((encoderR)^(encoderL)) {
    if (encoderR) {
      TstatTemp += 0.1;
    }
    else
    {
      TstatTemp -= 0.1;
    }
    TstatTemp = constrain(TstatTemp, 10, 35);
    encoderR = false;
    encoderL = false;
    Timer1Activated = false;
    Timer2Activated = false;
    Timer3Activated = false;
    }
 
  // ================ по нажатию кнопки энкодера - меню настроек ====================
  if(digitalRead(encoderK) == 0) {
    MenuTimeoutTimer = 10; //таймер таймаута, секунд
    lcd.clear();
    lcd.setCursor(0, 0); //инфо на LCD
    lcd.print(F("< SETUP >")); 
    if (BeepEnabled) {
      tone(BeepPin,4000,50);
    }
    delay(200);
    int menuitem = 0;
    
 
    do {
      rotating = true;  // reset the debouncer
      if ((encoderR)^(encoderL)) {
        MenuTimeoutTimer = 10; //таймер таймаута, секунд
        if (encoderR) { menuitem += 1; }
        else  { menuitem -= 1; }
        if ( menuitem > 9 ) { menuitem = 0; } // границы пунктов меню
        if ( menuitem < 0 ) { menuitem = 9; }
        encoderR = false;
        encoderL = false;
      }   
    
     // индикация пункта меню (номер пункта - в menuitem)
      lcd.setCursor(0, 1); //инфо на LCD
      switch(menuitem)
      {
      case 0:
        lcd.print(F("0.BACK          ")); 
        break;
      case 1:
        lcd.print(F("1.TIMER1 SET    ")); 
        break;
      case 2:
        lcd.print(F("2.TIMER2 SET    ")); 
        break;
      case 3:
        lcd.print(F("3.TIMER3 SET    ")); 
        break;     
      case 4:
        lcd.print(F("4.CLOCK SET     ")); 
        break;
      case 5:
        lcd.print(F("5.HYSTERESIS SET")); 
        break;
      case 6:
        lcd.print(F("6.T-CORRECT SET ")); 
        break;
      case 7:
        lcd.print(F("7.SOUND SET     ")); 
        break;
      case 8:
        lcd.print(F("8.T-ALARM SET   ")); 
        break; 
      case 9:
        lcd.print(F("ZVONOK   ")); 
        break;
            }
      if (MenuTimeoutTimer == 0) {
        menuitem = 0;
      }
 
    }
    while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
    // если нажата кнопка энкодера или таймаут - обработка пункта меню (номер пункта - в menuitem)
    if (BeepEnabled) {
      tone(BeepPin,4000,50);
    }
    switch(menuitem)
    {
    // ====== пункт 0 - выход
    case 0:
      if (BeepEnabled) {
        tone(BeepPin,BeepToneNo,BeepToneNoDuration);
      } //звук "NO"
      break; // case 0 out
 
    // ====== пункт 1 - установка Timer1
    case 1:
      MenuTimeoutTimer = 30; //таймер таймаута, секунд
      lcd.clear();
      lcd.setCursor(0, 0); //инфо на LCD
      lcd.print(F("SETUP TIMER1")); 
      delay(200);
      Hours=Timer1Hours;
      Minutes=Timer1Minutes;
      SetYesNo = false;
      PrintYesNo = true;
      SetTime(0,1); // в позиции 0,1 - запрос ввода времени
      if (MenuTimeoutTimer != 0) {
        if (SetYesNo) // если при установке времени выбрано "Yes"
        {
          if (BeepEnabled) {
            tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
          }
          Timer1Hours = Hours;
          Timer1Minutes = Minutes;
          Timer1Enabled = true;
          EEPROM.write(Timer1HoursEEaddr, Timer1Hours);
          EEPROM.write(Timer1MinutesEEaddr, Timer1Minutes);
          EEPROM.write(Timer1EnabledEEaddr, Timer1Enabled);
 
          MenuTimeoutTimer = 10; //таймер таймаута, секунд
          lcd.clear();
          lcd.setCursor(0, 0); //инфо на LCD
          lcd.print(F("Timer1 Temp. Set")); 
          delay(200);
          do {
            lcd.setCursor(0,1);
            if (blink500ms) {
              lcd.print(F("     ")); 
            }
            else {
              lcd.print(Timer1Temp, 1); 
              lcd.write(0x02); // значок градуса
            }
            rotating = true;  // reset the debouncer
            if (encoderR) {
              Timer1Temp += 0.1;
              encoderR = false;
            }
            if (encoderL) {
              Timer1Temp -= 0.1;
              encoderL = false;
            }
            Timer1Temp = constrain(Timer1Temp, 10, 35); // крайние значения
          }
          while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
 
          if (MenuTimeoutTimer != 0) { // если после выбора температуры нажата кнопка энкодера
            EEPROM_float_write(Timer1TempEEaddr, Timer1Temp);
            if (BeepEnabled) {
              tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
            }
          }
          else { // если не нажата - используем старую температуру
            Timer1Temp = EEPROM_float_read(Timer1TempEEaddr);
            if (BeepEnabled) {
              tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
            }
          }      
 
        }
        else // если при установке времени выбрано "No"
        {
          if (BeepEnabled) {
            tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
          }
          Timer1Enabled = false;
          EEPROM.write(Timer1EnabledEEaddr, Timer1Enabled);
          Timer1Hours = EEPROM.read(Timer1HoursEEaddr);
          Timer1Minutes = EEPROM.read(Timer1MinutesEEaddr);
        }
      }
      else {
        if (BeepEnabled) {
          tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
        }
      }
      break; // case 1 out
 
    // ====== пункт 2 - установка Timer2
    case 2:
      MenuTimeoutTimer = 30; //таймер таймаута, секунд
      lcd.clear();
      lcd.setCursor(0, 0); //инфо на LCD
      lcd.print(F("SETUP TIMER2")); 
      delay(200);
      Hours=Timer2Hours;
      Minutes=Timer2Minutes;
      SetYesNo = false;
      PrintYesNo = true;
      SetTime(0,1); // в позиции 0,1 - запрос ввода времени
      if (MenuTimeoutTimer != 0) {
        if (SetYesNo) // если при установке времени выбрано "Yes"
        {
          if (BeepEnabled) {
            tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
          }
          Timer2Hours = Hours;
          Timer2Minutes = Minutes;
          Timer2Enabled = true;
          EEPROM.write(Timer2HoursEEaddr, Timer2Hours);
          EEPROM.write(Timer2MinutesEEaddr, Timer2Minutes);
          EEPROM.write(Timer2EnabledEEaddr, Timer2Enabled);
 
          MenuTimeoutTimer = 10; //таймер таймаута, секунд
          lcd.clear();
          lcd.setCursor(0, 0); //инфо на LCD
          lcd.print(F("Timer2 Temp. Set")); 
          delay(200);
          do {
            lcd.setCursor(0,1);
            if (blink500ms) {
              lcd.print(F("     ")); 
            }
            else {
              lcd.print(Timer2Temp, 1); 
              lcd.write(0x02); // значок градуса
            }
            rotating = true;  // reset the debouncer
            if (encoderR) {
              Timer2Temp += 0.1;
              encoderR = false;
            }
            if (encoderL) {
              Timer2Temp -= 0.1;
              encoderL = false;
            }
            Timer2Temp = constrain(Timer2Temp, 10, 35); // крайние значения
          }
          while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
 
          if (MenuTimeoutTimer != 0) { // если после выбора температуры нажата кнопка энкодера
            EEPROM_float_write(Timer2TempEEaddr, Timer2Temp);
            if (BeepEnabled) {
              tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
            }
          }
          else { // если не нажата - используем старую температуру
            Timer2Temp = EEPROM_float_read(Timer2TempEEaddr);
            if (BeepEnabled) {
              tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
            }
          }      
 
        }
        else // если при установке времени выбрано "No"
        {
          if (BeepEnabled) {
            tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
          }
          Timer2Enabled = false;
          EEPROM.write(Timer2EnabledEEaddr, Timer2Enabled);
          Timer2Hours = EEPROM.read(Timer2HoursEEaddr);
          Timer2Minutes = EEPROM.read(Timer2MinutesEEaddr);
        }
      }
      else {
        if (BeepEnabled) {
          tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
        }
      }
      break; // case 2 out
 
    // ====== пункт 3 - установка Timer3
    case 3:
      MenuTimeoutTimer = 30; //таймер таймаута, секунд
      lcd.clear();
      lcd.setCursor(0, 0); //инфо на LCD
      lcd.print(F("SETUP TIMER3")); 
      delay(200);
      Hours=Timer3Hours;
      Minutes=Timer3Minutes;
      SetYesNo = false;
      PrintYesNo = true;
      SetTime(0,1); // в позиции 0,1 - запрос ввода времени
      if (MenuTimeoutTimer != 0) {
        if (SetYesNo) // если при установке времени выбрано "Yes"
        {
          if (BeepEnabled) {
            tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
          }
          Timer3Hours = Hours;
          Timer3Minutes = Minutes;
          Timer3Enabled = true;
          EEPROM.write(Timer3HoursEEaddr, Timer3Hours);
          EEPROM.write(Timer3MinutesEEaddr, Timer3Minutes);
          EEPROM.write(Timer3EnabledEEaddr, Timer3Enabled);
 
          MenuTimeoutTimer = 10; //таймер таймаута, секунд
          lcd.clear();
          lcd.setCursor(0, 0); //инфо на LCD
          lcd.print(F("Timer3 Temp. Set")); 
          delay(200);
          do {
            lcd.setCursor(0,1);
            if (blink500ms) {
              lcd.print(F("     ")); 
            }
            else {
              lcd.print(Timer3Temp, 1); 
              lcd.write(0x02); // значок градуса
            }
            rotating = true;  // reset the debouncer
            if (encoderR) {
              Timer3Temp += 0.1;
              encoderR = false;
            }
            if (encoderL) {
              Timer3Temp -= 0.1;
              encoderL = false;
            }
            Timer3Temp = constrain(Timer3Temp, 10, 35); // крайние значения
          }
          while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
 
          if (MenuTimeoutTimer != 0) { // если после выбора температуры нажата кнопка энкодера
            EEPROM_float_write(Timer3TempEEaddr, Timer3Temp);
            if (BeepEnabled) {
              tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
            }
          }
          else { // если не нажата - используем старую температуру
            Timer3Temp = EEPROM_float_read(Timer3TempEEaddr);
            if (BeepEnabled) {
              tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
            }
          }      
 
        }
        else // если при установке времени выбрано "No"
        {
          if (BeepEnabled) {
            tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
          }
          Timer3Enabled = false;
          EEPROM.write(Timer3EnabledEEaddr, Timer3Enabled);
          Timer3Hours = EEPROM.read(Timer3HoursEEaddr);
          Timer3Minutes = EEPROM.read(Timer3MinutesEEaddr);
        }
      }
      else {
        if (BeepEnabled) {
          tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
        }
      }
      break; // case 3 out
 
    // ====== пункт 4 - установка RTC
    case 4:
      MenuTimeoutTimer = 30; //таймер таймаута, секунд
      lcd.clear();
      lcd.setCursor(0, 0); //инфо на LCD
      lcd.print(F("SETUP CLOCK")); 
      delay(200);
      RTC.readClock();
      Hours=RTC.getHours();
      Minutes=RTC.getMinutes();
      SetYesNo = false;
      PrintYesNo = true;
      SetTime(0,1); // в позиции 0,1 - запрос ввода времени
      if (MenuTimeoutTimer != 0) {
        if (SetYesNo)
        {
          if (BeepEnabled) {
            tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
          }
          RTC.setHours(Hours);
          RTC.setMinutes(Minutes);
          RTC.setSeconds(0);
          RTC.setClock();
        }
        else
        {
          if (BeepEnabled) {
            tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
          }
        }
      }
      else {
        if (BeepEnabled) {
          tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
        }
      }
      break; // case 4 out
 
    // ====== пункт 5 - установка гистерезиса
    case 5:
      MenuTimeoutTimer = 30; //таймер таймаута, секунд
      HysteresisOld = Hysteresis;
      lcd.clear();
      lcd.setCursor(0, 0); //инфо на LCD
      lcd.print(F("SETUP HYSTERESIS")); 
      delay(200);
      do {
        lcd.setCursor(0,1);
        if (blink500ms) {
          lcd.print("   "); 
        }
        else {
          lcd.print(Hysteresis, 1); 
          lcd.write(0x02); // значок градуса
        }
        rotating = true;  // reset the debouncer
        if (encoderR) {
          Hysteresis += 0.1;
          encoderR = false;
        }
        if (encoderL) {
          Hysteresis -= 0.1;
          encoderL = false;
        }
        Hysteresis = constrain(Hysteresis, 0.1, 1); // крайние значения
      }
      while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
      if (MenuTimeoutTimer != 0) {
        EEPROM_float_write(HysteresisEEaddr, Hysteresis); // запись в ЕЕПРОМ
        if (BeepEnabled) {
          tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
        }
      }
      else {
        Hysteresis = HysteresisOld;
        if (BeepEnabled) {
          tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
        }
      }
      break; // case 5 out
 
    // ====== пункт 6 - установка коррекции температуры
    case 6:
      MenuTimeoutTimer = 30; //таймер таймаута, секунд
      lcd.clear();
      lcd.setCursor(0, 0); //инфо на LCD
      lcd.print(F("SETUP T-CORRECT ")); 
      delay(200);
      do {
        lcd.setCursor(0,1);
        if (blink500ms) {
          lcd.print(F("    ")); 
        }
        else {
          if (TemperatureCorr >= 0) {
            lcd.print(F("+"));
          }
 
          lcd.print(TemperatureCorr, 1); 
          lcd.write(0x02); // значок градуса
        }
        rotating = true;  // reset the debouncer
        if (encoderR) {
          TemperatureCorr += 0.1;
          encoderR = false;
        }
        if (encoderL) {
          TemperatureCorr -= 0.1;
          encoderL = false;
        }
        TemperatureCorr = constrain(TemperatureCorr, -10, 10); // крайние значения
      }
      while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
 
      if (MenuTimeoutTimer != 0) {
        EEPROM_float_write(TemperatureCorrEEaddr, TemperatureCorr); // запись в ЕЕПРОМ
        if (BeepEnabled) {
          tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
        }
      }
      else {
        TemperatureCorr = EEPROM_float_read(TemperatureCorrEEaddr);
        if (BeepEnabled) {
          tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
        }
      }
      break; // case 6 out     
 
    // ====== пункт 7 - вкл/выкл звука
    case 7:
      MenuTimeoutTimer = 30; //таймер таймаута, секунд
      lcd.clear();
      lcd.setCursor(0, 0); //инфо на LCD
      lcd.print(F("SOUND SET       ")); 
      delay(200);
      do {
        lcd.setCursor(0,1);
        if (BeepEnabled) {
          lcd.print(F("BEEP ON         ")); 
        }     
        else {
          lcd.print(F("BEEP OFF        ")); 
        }
 
        rotating = true;  // reset the debouncer
        if ((encoderR)^(encoderL)) {
          BeepEnabled = !BeepEnabled;
          encoderR = false;
          encoderL = false;
        }
      }
      while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
 
      if (MenuTimeoutTimer != 0) {
        if (BeepEnabled) {
          tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
        }
        EEPROM.write(BeepEnabledEEaddr, BeepEnabled);
      }
      if (MenuTimeoutTimer == 0) {
        BeepEnabled = EEPROM.read(BeepEnabledEEaddr);
      }
      break; // case 7 out
 
      // ====== пункт 8 - установка коррекции температуры 
    case 8:
      MenuTimeoutTimer = 30; //таймер таймаута, секунд
      lcd.clear();
      lcd.setCursor(0, 0); //инфо на LCD
      lcd.print(F("ALARM-TEMP SET  ")); 
      delay(200);
      do {
        lcd.setCursor(0,1);
        if (blink500ms) {
          lcd.print(F("    ")); 
        }
        else {
          if (AlarmTemp >= 0) {
            lcd.print(F("+"));
          }
 
          lcd.print(AlarmTemp, 0); 
          lcd.write(0x02); // значок градуса
        }
        rotating = true;  // reset the debouncer
        if (encoderR) {
          AlarmTemp += 1;
          encoderR = false;
        }
        if (encoderL) {
          AlarmTemp -= 1;
          encoderL = false;
        }
        AlarmTemp = constrain(AlarmTemp, 5, 40); // крайние значения
      }
      while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
 
      if (MenuTimeoutTimer != 0) {
        EEPROM_float_write(AlarmTempEEaddr, AlarmTemp); // запись в ЕЕПРОМ
        if (BeepEnabled) {
          tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
        }
      }
      else {
        AlarmTemp = EEPROM_float_read(AlarmTempEEaddr);
        if (BeepEnabled) {
          tone(BeepPin,BeepToneNo,BeepToneNoDuration); //звук "NO"
        }
      }
      break; // case 8 out
      
      case 9:
      MenuTimeoutTimer = 10; //таймер таймаута, секунд
      lcd.clear();
      lcd.setCursor(0, 0); //инфо на LCD
      lcd.print(F("ZVONOK SET       ")); 
      delay(200);
      do {
        lcd.setCursor(0,1);
        if (Zvonok) {
          lcd.print(F("YES         ")); 
        }     
        else {
          lcd.print(F("NO        ")); 
        }
 
        rotating = true;  // reset the debouncer
        if ((encoderR)^(encoderL)) {
          Zvonok = !Zvonok;
          encoderR = false;
          encoderL = false;
        }
      }
      while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
 
      if (MenuTimeoutTimer != 0) {
        if (Zvonok) {
          tone(BeepPin,BeepToneYes,BeepToneYesDuration); //звук "YES"
         Serial.print("ATD+79206888901;\r");
        }
        
      }
      
      break; // case 7 out
    }
 
    delay(200);
    lcd.clear();
  }
}
 
// ===== SUBROUTINES ==================================================================
 
// ========================================
void SetTime(char x, char y)
{
  // ========= set hours
  SetH = true;
  do {
    PrintRTC(x,y);
    rotating = true;  // reset the debouncer
    if (encoderR) {
      Hours += 1;
      if(Hours > 23) {
        Hours = 0;
      };
      encoderR = false;
    }
    if (encoderL) {
      Hours -= 1;
      if(Hours < 0) {
        Hours = 23;
      };
      encoderL = false;
    }
  }
  while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
  if (BeepEnabled) {
    tone(BeepPin,4000,50); //звук "YES"
  }
  SetH = false;
  delay(200);
  // ========= set minutes
  SetM = true;
  do {
    PrintRTC(0,1);
    rotating = true;  // reset the debouncer
    if (encoderR) {
      Minutes += 1;
      if(Minutes > 59) {
        Minutes = 0;
      };
      encoderR = false;
    }
    if (encoderL) {
      Minutes -= 1;
      if(Minutes < 0) {
        Minutes = 59;
      };
      encoderL = false;
    }
  }
  while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
  if (BeepEnabled) {
    tone(BeepPin,4000,50); //звук "YES"
  }
  if (PrintYesNo) {
    SetM = false;
    delay(200);
    // ========= set yes-no
    SetYesNo = false;
    do {
      PrintRTC(0,1);
      rotating = true;  // reset the debouncer
      if ((encoderR)||(encoderL)) {
        SetYesNo = !SetYesNo;
        encoderR = false;
        encoderL = false;
      }
    }
    while ((digitalRead(encoderK)==1)^(MenuTimeoutTimer==0));
    delay(200);
  }
 
}
 
// ========================================
void PrintRTC(char x, char y)
{
  lcd.setCursor(x,y);
  if (SetH&&blink500ms) {
    lcd.print(F("  "));
  }
  else {
    if (Hours < 10) {
      lcd.print(F("0"));
    }   
    lcd.print(Hours);
  }
 
  // мигающее двоеточие, если не в режиме установки времени
  if (!(SetH||SetM||PrintYesNo||blink500ms))
  {
    lcd.print(F(" "));
  }
  else {
    lcd.print(F(":"));
  }
 
  if (SetM&&blink500ms) {
    lcd.print(F("  "));
  }
  else {
    if (Minutes < 10) {
      lcd.print(F("0"));
    }   
    lcd.print(Minutes);
  }
  lcd.print(F(" "));
 
  if (PrintYesNo) {
    lcd.print(F("["));
    if (!(SetH||SetM||blink500ms))
    {
      lcd.print(F("   "));
    }
    else {
      if (SetYesNo)
      {
        lcd.print(F("YES"));
      }
      else {
        lcd.print(F("NO "));
      }
    }
    lcd.print(F("]"));
  }
 
}
 
// ========= чтение/запись float в EE =====
void EEPROM_float_write(int addr, float val) // запись в ЕЕПРОМ
{
  byte *x = (byte *)&val;
  for(byte i = 0; i < 4; i++) EEPROM.write(i+addr, x[i]);
}
 
float EEPROM_float_read(int addr) // чтение из ЕЕПРОМ
{  
  byte x[4];
  for(byte i = 0; i < 4; i++) x[i] = EEPROM.read(i+addr);
  float *y = (float *)&x;
  return y[0];
}
// ========================================
 
// ============================ Encoder interrupts =============================
// Interrupt on A changing state
void doEncoderA(){
  if ( rotating ) {
    delay (1) ;  // wait a little until the bouncing is done
  }
  // Test transition, did things really change?
  if( digitalRead(encoderA) != A_set ) {  // debounce once more
    A_set = !A_set;
    // adjust counter + if A leads B
    if ( A_set && !B_set )
    {
      MenuTimeoutTimer = 10; //таймер таймаута, секунд
      if (BeepEnabled) {
        tone(BeepPin,4000,5);
      }
      encoderR = true;
      rotating = false;  // no more debouncing until loop() hits again
    }
  }
}
// Interrupt on B changing state, same as A above
void doEncoderB(){
  if ( rotating ) {
    delay (1);
  }
  if( digitalRead(encoderB) != B_set ) {
    B_set = !B_set;
    //  adjust counter - 1 if B leads A
    if( B_set && !A_set ) {
      MenuTimeoutTimer = 10; //таймер таймаута, секунд
      if (BeepEnabled) {
        tone(BeepPin,4000,5);
      }
      encoderL = true;
      rotating = false;
    }
  }
}
// ============================ Timer0 interrupt =============================
// run every 500ms
void timerIsr()
{
  blink500ms = !blink500ms; // инверсия мерцающего бита
  if(blink500ms) {
    plus1sec = true; // ежесекундно взводится
    if (TstatTimer != 0) {
      TstatTimer --; // ежесекундный декремент этого таймера
    }
    if (MenuTimeoutTimer != 0) {
      MenuTimeoutTimer --; // ежесекундный декремент этого таймера
    }
  }
}
void sms_read() //_____Цикл чтения входящих СМС-сообщений______________     
{
    if (!Serial.available()) return;
 
    char currSymb = Serial.read();    
    if ('\r' == currSymb)
       {
         if (isStringMessage)
           {
        
    if (!currStr.compareTo("ZAPROS"))   { SMSzapros();}//запрос состояния

// Далее подтверждение параметров по СМС
    if (!currStr.compareTo("+25"))   { TstatTemp = 25; startOneSMS(); Serial.print(TstatTemp);Serial.print(" TstatTemp-OK"); }
    if (!currStr.compareTo("+24"))   { TstatTemp = 24; startOneSMS(); Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");} 
    if (!currStr.compareTo("+23"))   { TstatTemp = 23; startOneSMS(); Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}                                      
    if (!currStr.compareTo("+22"))   { TstatTemp = 22; startOneSMS(); Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
    if (!currStr.compareTo("+21"))   { TstatTemp = 21; startOneSMS(); Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
    if (!currStr.compareTo("+20"))   { TstatTemp = 20; startOneSMS(); Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
    if (!currStr.compareTo("+19"))   { TstatTemp = 19; startOneSMS(); Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
    if (!currStr.compareTo("+18"))   { TstatTemp = 18; startOneSMS(); Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
    if (!currStr.compareTo("+17"))   { TstatTemp = 17; startOneSMS(); Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
    if (!currStr.compareTo("+16"))   { TstatTemp = 16; startOneSMS(); Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
    if (!currStr.compareTo("+15"))   { TstatTemp = 15; startOneSMS(); Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
    if (!currStr.compareTo("+0.1"))   { Hysteresis = 0.1; startOneSMS(); Serial.print(Hysteresis);Serial.print(" Hysteresis-OK");}
    if (!currStr.compareTo("+0.2"))   { Hysteresis = 0.2; startOneSMS(); Serial.print(Hysteresis);Serial.print(" Hysteresis-OK");}
    if (!currStr.compareTo("+0.3"))   { Hysteresis = 0.3; startOneSMS(); Serial.print(Hysteresis);Serial.print(" Hysteresis-OK");}
    if (!currStr.compareTo("+0.4"))   { Hysteresis = 0.4; startOneSMS(); Serial.print(Hysteresis);Serial.print(" Hysteresis-OK");}
    if (!currStr.compareTo("+0.5"))   { Hysteresis = 0.5; startOneSMS(); Serial.print(Hysteresis);Serial.print(" Hysteresis-OK");}
    if (!currStr.compareTo("+1"))   { Hysteresis = 1; startOneSMS(); Serial.print(Hysteresis);Serial.print(" Hysteresis-OK");}
    if (!currStr.compareTo("ZVONOK"))   { Serial.print("AT+CMIC=10;");delay (100);Serial.print("ATD+79206888901;");}
        isStringMessage = false;
        
           }
         else { if (currStr.startsWith("+CMT")) {     // если текущая строка начинается с "+CMT",
                          isStringMessage = true;}}    // то следующая строка является сообщением
        currStr = "";
      } 
    else if ('\n' != currSymb) { currStr += String(currSymb);}
}

void SMSzapros() // СМС отчет для хозяина
{
    startOneSMS();
    if ((Timer1Enabled)&!(Timer1Activated)) {Serial.print("TIMER 1  ");Serial.print("T1=");Serial.print(Timer1Temp);Serial.print("/TU=");
  Serial.print(Temperature);Serial.print(" Hyst=");Serial.print(Hysteresis);EndSMS();}
    if ((Timer2Enabled)&!(Timer1Activated)) {Serial.print("TIMER 2  ");Serial.print("T2=");Serial.print(Timer2Temp);Serial.print("/TU=");
  Serial.print(Temperature);Serial.print(" Hyst=");Serial.print(Hysteresis);EndSMS();EndSMS();}
    if ((Timer3Enabled)&!(Timer1Activated)) {Serial.print("TIMER 3  ");Serial.print("T3=");Serial.print(Timer3Temp);Serial.print("/TU=");
  Serial.print(Temperature);Serial.print(" Hyst=");Serial.print(Hysteresis);EndSMS();}
   else {Serial.print("TIMER OFF  ");Serial.print("TSET/TT=");Serial.print(TstatTemp);Serial.print("/");Serial.print(Temperature);Serial.print(" Hyst=");Serial.print(Hysteresis);EndSMS();}
    if (digitalRead(12)==HIGH) {Serial.println("  NAGREV-OFF"); } else { Serial.println("  NAGREV-ON");EndSMS();}
    EndSMS();                                 
}

void NastroykaGSM()
{
  Serial.print("AT+CMGF=1\r");         //устанавливает текстовый режим смс-сообщения
    delay(100);
  Serial.print("AT+IFC=1,1\r");       //устанавливает программный контроль потоком передачи данных
    delay(100);
  Serial.print("AT+CPBS=\"SM\"\r");    //открывает доступ к данным телефонной книги SIM-карты
    delay(100);
  Serial.print("AT+GSMBUSY=1,1\r");   //запрет всех входящих звонков
    delay(100);
  Serial.print("AT+CMGD=4,\r");  //Очищаем накопившиеся СМС
    delay(100);
  Serial.print("AT+CNMI=1,2,2,1,0\r"); //включает оповещение о новых сообщениях
    delay(100);
}

void startOneSMS() //__________________Цикл подготовки модуля к отправке СМС-сообщений по первому номеру
{
      Serial.print("AT+CMGF=1\r");
      delay(100);
      Serial.println("AT + CMGS = \"+79206888901\""); 
      delay(100);
}
void EndSMS() //__________________Цикл окончания и отправки СМС-сообщения_______________________
{
   delay(100);
   Serial.println((char)26);    // Команда отправки СМС
   delay(5000);
}

 

balbes323
Offline
Зарегистрирован: 06.12.2016

NAZ, у меня все в одном корпусе, импульсные трансы на сим900 не влияют, т.к. он экранирован и частоты не те, а вот на остальное вполне возможно. Иногда при включении нагрузки возникают какие-то наводки, и на дисплей выходит какая-то хрень, но программа в ардуине продолжает работать. Все глюки дисплея пропадают после нажатия на кнопку энкодера. Лучше ставить блоки питания в металлическом корпусе или вообще внешние.

naz
Offline
Зарегистрирован: 15.11.2016

balbes323 пишет:

NAZ, у меня все в одном корпусе, импульсные трансы на сим900 не влияют, т.к. он экранирован и частоты не те, а вот на остальное вполне возможно. Иногда при включении нагрузки возникают какие-то наводки, и на дисплей выходит какая-то хрень, но программа в ардуине продолжает работать. Все глюки дисплея пропадают после нажатия на кнопку энкодера. Лучше ставить блоки питания в металлическом корпусе или вообще внешние.

Спасибо за ответ. Вообщем-то собрал я всё в одном корпусе поскорее и отвёз на дачу. Не до экспериментов, у нас в Челябинске температура сейчас до -37, надо греть дом, а без контроллера побаиваюсь калориферы оставлять включёнными. Уже в работе мой контроллер, он получился в виде смс- розетки, дополнительно умеет температуру выслать по запросу. Работает стабильно, не падает уже 3 недели.

balbes323
Offline
Зарегистрирован: 06.12.2016

Ребят, у кого проблемы с отладкой модулей сим900. Я делаю так: сущеструет переходник usb-rs232, например, такой http://chip69.ru/catalog/1483, или на ch340. Стоит копейки. Подключаю через него сим900, настраиваю с компа через терминал. Либо подключаю на ардуину на нужный порт и смотрю в терминале, что она отсылает в ответ на запрос. Сначала шлем +CMT, следующей строкой запрос и смотрим, что получает и в каком формате сим с дуни. Если что-то не так, правим скетч в нужном месте, и отсылаем снова. Полный список АТ команд есть в инете или в даташите.

stambylov
stambylov аватар
Offline
Зарегистрирован: 10.05.2012

Летом 2016 написал прогу для дачнтков, и собрал все

Специально разработанная для дачников!



Состав системы:
- 2 датчика температуры-влажности(один устанавливается на улице, второй в доме)
- 2 датчика движения(устанавливаются в доме)
- 1 датчик на открытие входной двери
- сирена с маяком
- Бесперебойный бокс(при отсутствии питание ваша система всегда работает)

Управление производится посредством телефона.
Возможности:
- Постановка и снятие с охраны.
- Запрос баланса
- Запрос состояния системы(Состояние контроля дома, напряжение 220В, напряжение аккумулятора, температура и влажность, сигнал сотовой сети)
- Квитирование тревог(сброс тревоги)
- При пропадании напряжения 220В, придет смс
- При возобновлении напряжения 220В, придет смс
- При разряде аккумулятора, придет смс
- При срабатывании по датчикам, придет смс, включится сирена
- При открывании бокса, придет смс, включится сирена

ссылка на фото

yavi
Offline
Зарегистрирован: 26.12.2016

Друзья, простите, если немного оффтоп. Ищется термоконтроллер для управления батареей отопления наподобие http://www.homematic.ru/Catalog/showDetailscfb4.php?g.. , но ардуино совместимый. Хочется иметь возможность отправить команду на поддержание определенной температуры, либо, как вариант, просто открыть/закрыть клапан. Сейчас проблема именно в поиске подходящего терморегулятора. Вроде в этом проекте такого нет, может кто-то делал такое или знает где взять?

MaksVV
Offline
Зарегистрирован: 06.08.2015

мне кажется надёжнее будет по проводам. Регулятор типа этого http://www.herz-armaturen.ru/thermal-actuators/1-7711-13/

а вот описание  http://www.herz-armaturen.ru/upload/normal/7711.pdf . Не сочтите за рекламу. Нужен также БП на 24В. Управлять посредством ПИД регулирования, обычными или твердотельными реле, которые будут коммутировать 24В на привод. 

yavi
Offline
Зарегистрирован: 26.12.2016

Благодарю

Serg1
Offline
Зарегистрирован: 04.12.2015

Коллеги, спаял плату с опторазвязками для ПИР датчиков и концевиков и призадумался:

А как же решается вопрос защиты от наводок на кабельных линиях идущих к датчикам типа  DS18 и  DTH22 ??.

 

MaksVV
Offline
Зарегистрирован: 06.08.2015

в этой теме уже обсуждалось, я ссылки приводил с радиокота - ищите

snewday
Offline
Зарегистрирован: 09.01.2017

Slavyanin55]</p> <p>[quote=MaksVV пишет:

Пусть всё будет freeware типа! А я вот всё жду, кто заделает приложение на андроиде совместимое с моей системой. Вот это была бы тема.

Здравствуйте! Отличный проект, огромная работа! Сам только на старте! Удачи в бесконечном пути к совершенству! Я по поводу андроида - обратите внимение на прграмму Virtuino. Мне очень понравилась, и лучше я ничего не нашёл.

snewday
Offline
Зарегистрирован: 09.01.2017

Slavyanin55]</p> <p>[quote=MaksVV пишет:

Пусть всё будет freeware типа! А я вот всё жду, кто заделает приложение на андроиде совместимое с моей системой. Вот это была бы тема.

Здравствуйте! Отличный проект, огромная работа! Сам только на старте! Удачи в бесконечном пути к совершенству! Я по поводу андроида - обратите внимение на прграмму Virtuino. Мне очень понравилась, и лучше я ничего не нашёл.

Slavyanin55
Slavyanin55 аватар
Offline
Зарегистрирован: 01.06.2014

https://yadi.sk/d/PUVyBzOJ38tTQe

Вот обновил программу. И библиотеки работающие туда же положил. Проблем быть не должно. 

В экселевском файле есть таблица подключений к плате мега, и есть таблица команд по серийному порту №1. Теперь они цифровые 4-х значные. Так тратится гораздо меньше оперативы, повышается скорость реакции, ну и голову ломать не придется с придумыванием команды.

Добавлен кухонный 4-х канальный таймер с управление от ИК- пульта телевизора самсунг.

Добавлен определитель номера по примеру MaksaVV. Теперь программа реагирует только на смс от своих номеров. И отсылает ответ, тому кто команду послал.Пример stambylovа  я пока не осилил, но применю его точно.

Ну и так порядки навел.

Пользуйтесь, предлагайте, будем совершенствоваться дальше.

MaksVV
Offline
Зарегистрирован: 06.08.2015

Слава, респект! можно усовершенствовать имхо часть кода, где квитирование, чето намудрено как то. Предлагаю ввести переменную одну Mute вместо всех Kvit...ов, убрать также цикл Kvitirovanie (). Запуск квитирания: вместо Kvitirovanie () набираем просто Mute = 1. Вот пример вкладки Alarm. 

int pambilang;         // переменная для цикла sirena()

int  TEMPMINZ = 15;  // Переменная. Уставка сигнализации минимальной температуры в зале    (По умолчанию 15гр.*С)
int  TEMPMINU = -45; // Переменная. Уставка сигнализации минимальной температуры на улице  (По умолчанию -45гр.*С)
int  TEMPMINK = 15;  // Переменная. Уставка сигнализации минимальной температуры в кухне   (По умолчанию 15гр.*С)
int  TEMPMINP = 5;   // Переменная. Уставка сигнализации минимальной температуры в подполе (По умолчанию 5гр.*С)

int  TEMPMAXZ = 35;  // Переменная. Уставка сигнализации максимальной температуры в зале    (По умолчанию 35гр.*С)
int  TEMPMAXU = 50;  // Переменная. Уставка сигнализации максимальной температуры на улице  (По умолчанию 50гр.*С)
int  TEMPMAXK = 35;  // Переменная. Уставка сигнализации максимальной температуры в кухне   (По умолчанию 35гр.*С)
int  TEMPMAXP = 35;  // Переменная. Уставка сигнализации максимальной температуры в подполе (По умолчанию 35гр.*С)

void alarms()  //______________Цикл "тревожные сигналы"____
{
       if (digitalRead(30)==HIGH)       {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS(); statusPump=0; if } // Сработка датчика затопления подпола
  //else if (analogRead(14)<100)     {if (!Mute) {sirena(); AlarmTimer++;} alarmsSMS();}               // Сработка датчика уровня дренажной емкости
  else if (digitalRead(29)==HIGH)       {if (!Mute) {sirena(); AlarmTimer++;}}                            // Сработка датчика готовности бани
  else if (digitalRead(31)==HIGH)       {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS(); statusbania=2;}// Сработка датчика предельной температуры в бане
  else if ( !TempZalC==0 && TempZalC <= TEMPMINZ)      {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS();}  // Сигнализация низкой  температуры в зале
  else if ( TempZalC >= TEMPMAXZ)      {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS();}  // Сигнализация высокой температуры в зале
  else if ( !TempUlicaC==0 && TempUlicaC <= TEMPMINU)  {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS();}  // Сигнализация низкой  температуры на улице
  else if ( TempUlicaC >= TEMPMAXU)  {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS();}  // Сигнализация высокой температуры на улице
  else if ( !TempKuhnyaC==0 && TempKuhnyaC <= TEMPMINK){if (!Mute) {sirena(); AlarmTimer++;}  AlarmTemp=1; alarmsSMS();}  // Сигнализация низкой  температуры в кухне
  else if ( TempKuhnyaC >= TEMPMAXK){if (!Mute) {sirena(); AlarmTimer++;}  AlarmTemp=1; alarmsSMS();}  // Сигнализация высокой температуры в кухне
//  else if (  TempPodpol < TEMPMINP) {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS();}  // Сигнализация низкой температуры в в подполе +3
//  else if (  TempPodpol > TEMPMAXP) {if (!Mute) {sirena(); AlarmTimer++; } AlarmTemp=1; alarmsSMS();}  // Сигнализация высокой температуры в подполе +35
//  else if (Vpit<=12.0 && SMSVoltIBP==false)             { startOneSMS(); Serial2.println("Alarm! Min zaryad akkumulyatora IBP!"); EndSMS(); SMSVoltIBP=true;}             // Низкий заряд аккумулятора
//  else if (Vpit>=14.0 && SMSVoltIBP==false)             { startOneSMS(); Serial2.println("Alarm! Max zaryad akkumulyatora IBP!"); EndSMS(); SMSVoltIBP=true;}             // Перезаряд аккумулятора
  else { AlarmTemp=0; AlarmTimer=0;}

   if ( AlarmTimer > 300000) {AlarmTimer=0; Mute = true;} // Через 5 минут автоматчекое квитирование тревоги и сброс таймера
   
   if (Mute) {if ( statusperimetr==0){perimetr=0;} AlarmTimer = 0;}
   
           
   if ( TempZalC > TEMPMINZ+2 )    {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;}  // Сброс квитирования при возвращении параметра в норму
   if ( TempZalC < TEMPMAXZ-2 )    {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;}  // Сброс квитирования при возвращении параметра в норму
   if ( TempUlicaC > TEMPMINU+2 )  {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;}  // Сброс квитирования при возвращении параметра в норму
   if ( TempUlicaC < TEMPMAXU-2 )  {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;}  // Сброс квитирования при возвращении параметра в норму
   if ( TempKuhnyaC > TEMPMINK+2 ) {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;}  // Сброс квитирования при возвращении параметра в норму
   if ( TempKuhnyaC < TEMPMAXK-2 ) {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;}  // Сброс квитирования при возвращении параметра в норму
   if ( TempPodpol > TEMPMINP)     {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;}  // Сброс квитирования при возвращении параметра в норму
   if ( TempPodpol < TEMPMAXP)     {SMSAlarmTemp==false; Mute = false; AlarmTimer = 0;}  // Сброс квитирования при возвращении параметра в норму
   //if (analogRead(14)>100)    {KvitAI14=false;}    // Сброс квитирования при возвращении параметра в норму
   if (digitalRead(29)==LOW)  {Mute=false; AlarmTimer = 0;}      // Сброс квитирования при возвращении параметра в норму
   if (digitalRead(30)==LOW)  {Mute=false; AlarmTimer = 0;}      // Сброс квитирования при возвращении параметра в норму
   if (digitalRead(31)==LOW)  {Mute=false; AlarmTimer = 0;}      // Сброс квитирования при возвращении параметра в норму
   
   if (digitalRead(37)==HIGH && SMSVoltOFF==false) {
             startOneSMS(); Serial2.print("Propalo pitanie 220V!_"); vremya2(); EndSMS();
             SMSVoltOFF=true; SMSVoltON=false; homeOFF(); statusotp=2; ULsvet=3; } // Отключение питания 220В потребителей от греха подальше и для экономии аккумулятора(выключаются реле)
           
   if ((digitalRead(37)==LOW && SMSVoltON==false) && (RTCMinuta==0 || RTCMinuta==15|| RTCMinuta==30 || RTCMinuta==45))
          { startOneSMS(); Serial2.print("Pitanie 220V vosstanovleno!_"); vremya2(); EndSMS();
          if (ULsvet==3){ ULsvet=2; } // включить освещение двора если оно было выключено автоматически
          SMSVoltON=true; SMSVoltOFF=false; } // Восстановление питания 220В

}

void alarmsSMS()    //______Цикл отправки алармов по СМС__________________________________________________
{      
  if (digitalRead(30)==HIGH && SMSPodpol==false) //Отправка СМС о затоплении подпола
     { startOneSMS(); Serial2.println("Alarm!Voda v podpole!"); vremya2(); EndSMS(); 
       startTwoSMS(); Serial2.println("Alarm!Voda v podpole!"); vremya2(); EndSMS(); SMSPodpol=true;}

  if (AlarmTemp==1 && SMSAlarmTemp==false) //Отправка СМС о критической температуре
     { 
     //if((TempPodpol  <  TEMPMINP)||(TempPodpol  >  TEMPMAXP)) { volume(); mp3_play (1); delay(4000);} // Проигрываем сообщение по оповещению, подпол
       if((TempZalC    <= TEMPMINZ)||(TempZalC    >= TEMPMAXZ)) { volume(); mp3_play (2); delay(4000);} // Проигрываем сообщение по оповещению, зал    
       if((TempUlicaC  <= TEMPMINU)||(TempUlicaC  >= TEMPMAXU)) { volume(); mp3_play (5); delay(4000);} // Проигрываем сообщение по оповещению, улица       
       if((TempKuhnyaC <= TEMPMINK)||(TempKuhnyaC >= TEMPMAXK)) { volume(); mp3_play (4); delay(4000);} // Проигрываем сообщение по оповещению, кухня  

       startOneSMS();
       Serial2.println("Alarm!Temperatura!");
       Serial2.print("Podpol:");  Serial2.print(TempPodpol);  Serial2.println("*C,");
       Serial2.print("Zal:");     Serial2.print(TempZalC);    Serial2.println("*C");
       Serial2.print("Ylica:");   Serial2.print(TempUlicaC);  Serial2.println("*C");
       Serial2.print("Kuhnya:");  Serial2.print(TempKuhnyaC); Serial2.println("*C");
       EndSMS();
         startTwoSMS();
       Serial2.println("Alarm!Temperatura!");
       Serial2.print("Podpol:");  Serial2.print(TempPodpol);  Serial2.println("*C,");
      if (dsZshet<4){Serial2.print("Zal:");   Serial2.print(TempZalC);   Serial2.println("*C");} else{ Serial2.println("net svyazi");}
      if (dsUshet<4){Serial2.print("Ylica:"); Serial2.print(TempUlicaC); Serial2.println("*C");} else{ Serial2.println("net svyazi");}
      if (dsKshet<4){Serial2.print("Kuhnya:");Serial2.print(TempKuhnyaC);Serial2.println("*C");} else{ Serial2.println("net svyazi");}
      EndSMS(); SMSAlarmTemp=true;
    }

  if (digitalRead(31)==HIGH && SMSBanyaTemp==false) //Отправка СМС о критической температуре в бане
       { 
         volume(); mp3_play (3); // Проигрываем сообщение по оповещению
         startOneSMS(); Serial2.println("Alarm!Predelnaya temperatura v bane!"); vremya2(); EndSMS();
         SMSBanyaTemp=true;
       }
}

void sirena()
{
  pambilang++;
  if(pambilang > 500){ tone(5, 1500, 400); pambilang = 0;}
  //for (int m = 1600; m<=2200; m++){tone (5, m, 75);} // (пин пищалки,частота,длина тона)
  //for (int m = 2200; m>=1600; m--){tone (5, m, 75);}
  //if(pambilang==4){noTone(5); pambilang = 0;}
}

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

Serg1
Offline
Зарегистрирован: 04.12.2015

Слава, Макс, молодцы!

В процессе пайки возникли вопросы и сомнения:

модуль BT  HC-05 у вас подключены напрямую или уровни сигналов согласованы? ( на плате указаны уровни сигн 3,3 в).

Датчики Даллас опрашиваются с какой периодичностью? (можно выставить таймер до 8 сек вроде, а сколько выставлено в обсуждаемом коде).

Slavyanin55
Slavyanin55 аватар
Offline
Зарегистрирован: 01.06.2014

Serg1 пишет:

модуль BT  HC-05 у вас подключены напрямую или уровни сигналов согласованы? ( на плате указаны уровни сигн 3,3 в).

У меня блютус модуль был подключен просто через килоомные резисторы. Но лучше делай по уму через делитель по два резистора.

А сейчас я esp8266 приляпал. Терпит и без резисторов она. Осваиваю HTML. Пытаюсь делать простенькие странички для веба. А тут на днях коллега похвастался вот таким экранчиком Nextion HMI nx3224t024_011, так мне его тоже захотелось поставить.

Кстати, есть на примете HTML редактор какой? чтобы там натащил готовых полей да кнопок и готово?

Serg1 пишет:

Датчики Даллас опрашиваются с какой периодичностью? (можно выставить таймер до 8 сек вроде, а сколько выставлено в обсуждаемом коде).

Ну у меня раз в 2 минуты. Можно и чаще, главное чтобы не один раз в цикл. А вот Макс хитрый ход предложил. Тоже буду его осознавать.

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

Slavyanin55
Slavyanin55 аватар
Offline
Зарегистрирован: 01.06.2014

MaksVV пишет:

Слава, респект! можно усовершенствовать имхо часть кода, где квитирование, чето намудрено как то. Предлагаю ввести переменную одну Mute вместо всех Kvit...ов, убрать также цикл Kvitirovanie (). Запуск квитирания: вместо Kvitirovanie () набираем просто Mute = 1. Вот пример вкладки Alarm

Неа, у меня же задумка такая, что если параметр какой то вышел за предел, то квитирование "затыкает" только его, пока он не пришел в норму. И если в этот момент другой какой то параметр вышел за пределы, то сирена включается снова. Снова жмешь кнопку МУТЕ и тревога по этому параметру прекращается. Правда не всегда такое получается почему то :)) Но задумка такая. А если ввести одну mute==true то её вообще можно в цикл сирена() запихать и всё, но она будет блокировать работу сирены по всем тревогам. Или я не понял чего то?

MaksVV пишет:

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

Да! делать однозначно надо! Хитрый код.

Кстати да, когда датчики глючат, то выдают либо 0, или 255. Сделал игнорирование по этим двум числам  и всё тишина. А то последнее время раз в две недели ложная тревога была.