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

pev0270
Offline
Зарегистрирован: 02.11.2015

Serg1 пишет:

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

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

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

Вот погодозависимый алгоритм, часть1: http://radiokot.ru/circuit/digital/home/112/

часть2: http://radiokot.ru/circuit/digital/home/130/

Там для газового котла, (один контакт управления) но думаю это не проблема. Главное принцип понять погодозависимости...

Обидно что исходник не посмотреть...

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

Доброй ночи разработчики! Сваял я термостат для управления двумя нагревателями, алгоритм такой, если температура ниже заданной, включаем обогреватель 1, при этом, если разница текущей и установленной температурой больше х градусов, включается нагреватель 2. Если меньше х, нагреватель 2 отключается и температура доводится первым до установленной+гистерезис. Но, если у первого мощи не хватает и разница температур меньше х , температура не растет и второй не включается. Возникла у меня необходимость сделать контроль роста температуры и перевести управление вторым нагревателем на этот контроль. Идею вижу так, если за время Т температура поднялась на Х градусов, включение нагревателя 2 не требуется, если поднялась на Y градусов или не поднялась или опустилась, включаем нагреватель 2. При этом модуля часов у меня там не предусмотрено. Всю голову сломал нах и гугл не помогает. Может кто подскажет? P.S. Сильно не пинайте, это не окончательная версия кода, но уже пытается работать...

#include <EEPROM.h> // EE
#include <LiquidCrystal.h> // LCD 16*2 
#include <OneWire.h> // 1wire для DS18B20
#include <DallasTemperature.h> // DS18B20 
#define ONE_WIRE_BUS 12  // датчики DS18B20 на 11 пин
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature ds(&oneWire);  // Везде где встречается ds - это работа с датчиками Dallas DS18B20
DeviceAddress ds1 =    { 0x28, 0xFF, 0xA6, 0xC0, 0x74, 0x16, 0x04, 0x88 }; // Сетевой адрес датчика 1
DeviceAddress ds2 = { 0x28, 0x8D, 0x76, 0x7C, 0x06, 0x00, 0x00, 0x24 }; // Сетевой адрес датчика 2
int tempC; // для работы с DS18B20
int  Temp_1   = 20;  // Переменная. Чтение с датчика 1
int  Temp_2= 20;  // Переменная. Чтение с датчика 2
int  Temp1    = 20;  // Переменная. Итоговая температура датчик 1    (По умолчанию 20гр.*С)
int  Temp2 = 20;  // Переменная. Итоговая температура датчик 2  (По умолчанию 20гр.*С)

#define encoderA    2 // энкодер - поворот вправо (об землю)
#define encoderB    3 // энкодер - поворот влево (об землю)
#define encoderK    A6 // энкодер - кнопка (об землю)
#define Relay1  10 // нога, к которой подключено реле
#define Relay2  11 // нога, к которой подключено реле
#define Relay1On LOW // полярность сигнала включения реле (HIGH/LOW)
#define Relay2On LOW // полярность сигнала включения реле (HIGH/LOW)
#define Error  13 //ошибка
#define ErrorOn LOW // полярность сигнала включения реле (HIGH/LOW)
#define Ventcont  A0 //контроль работы вентилятора (маностат)
#define OpenCam A1 // открыта крышка тэна
#define Stop A2 //кнопка стоп
 
// LCD connection RS, E, D4, D5, D6, D7
LiquidCrystal lcd(9, 8, 7, 6, 5, 4);
 
byte block1[8] = {
  0x06,0x09,0x09,0x06,0x00,0x04,0x0E,0x1F }; // значок градуса с пламенем снизу
byte block2[8] = {
  0x06,0x09,0x09,0x06,0x00,0x00,0x00,0x00 }; // значок градуса
 
int ds1shet=0;         // Подсчет кол-ва ошибок DS18B20 1
int ds2shet=0;         // Подсчет кол-ва ошибок DS18B20 2
int statusotp=0; // статус нагрева                0 - откл , 1- вкл ,
float TstatTemp = 23; //температура термостатирования, может изменяться настройками
float Hysteresis = 0.1; // гистерезис термостата, может изменяться настройками
float HysteresisOld; 
float AlarmTemp = 20;
float AlarmhTemp = 95; 
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 HysteresisEEaddr 4 // EE - адрес для сохранения гистерезиса, 4 байта(float)!
#define AlarmTempEEaddr 8 // EE - адрес для сохранения значения недопустимого снижения температуры, 4 байта(float)!
#define AlarmhTempEEaddr 12 // EE - адрес для сохранения значения недопустимого повышения температуры, 4 байта(float)!
long previousMillis = 0;    // храним время последнего замера
long interval = 10000;
 
// ===== SETUP ========================================================================
void setup() {
  ds.begin();
  ds.setResolution(ds1, 10);    
  ds.setResolution(ds2, 10); 
  
  pinMode(Relay1, OUTPUT);
  digitalWrite(Relay1, HIGH);
  pinMode(Relay2, OUTPUT);
  digitalWrite(Relay2, HIGH);  
  pinMode(Ventcont, INPUT);
  digitalWrite(Ventcont, HIGH); 
  pinMode(OpenCam, INPUT);
  digitalWrite(OpenCam, HIGH);
  pinMode(Stop, INPUT);
  digitalWrite(Stop, HIGH);
  pinMode(Error, OUTPUT);
  digitalWrite(Error, 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)

  if (EEPROM.read(TstatTempEEaddr) > 10) { // если первая запись однокристалки - записать начальные значения в EE
    EEPROM_float_write(TstatTempEEaddr, TstatTemp);
    EEPROM_float_write(HysteresisEEaddr, Hysteresis);
    EEPROM_float_write(AlarmTempEEaddr, AlarmTemp);
    EEPROM_float_write(AlarmhTempEEaddr, AlarmhTemp);
  }
  TstatTemp = EEPROM_float_read(TstatTempEEaddr);
  Hysteresis = EEPROM_float_read(HysteresisEEaddr);
  AlarmTemp = EEPROM_float_read(AlarmTempEEaddr);
  AlarmhTemp = EEPROM_float_read(AlarmhTempEEaddr);
}
 
// ===== MAIN CYCLE ===================================================================
void loop()
{   
  lcd.setCursor(0, 0); //инфо на LCD
  lcd.print(F("t="));
  if (Temp1 < 10) {
    lcd.print(F(" "));}
  lcd.print(Temp1,1);
  lcd.write(0x02); // значок градуса
  lcd.setCursor(8, 0); //инфо на LCD
  lcd.print(F("t1="));
  if (Temp2 < 10) {
    lcd.print(F(" "));}
  lcd.print(Temp2,1);
  lcd.write(0x02); // значок градуса   
  lcd.setCursor(0, 1); //инфо на LCD
  lcd.print(F("set="));
  lcd.print(TstatTemp,1);
  if ( digitalRead(Relay1) == Relay1On ) {lcd.write(0x01);} // значок градуса с пламенем 
  else {lcd.write(0x02);} // значок градуса
  
 unsigned long currentMillis = millis();
   if(currentMillis - previousMillis > interval) { // Замеры в интервале 
    
     ds.requestTemperatures();           // Замеры температур с DS18B20
     delay(150);                          // Необязательная задержка
     Temp_1    = ds.getTempC(ds1);    // Считываем температуру с датчика 1
     if(-55 < Temp_1 && Temp_1 < 120){Temp1 = Temp_1; ds1shet=0;} delay(50);// Если нет ошибки, то обновляем температур
     Temp_2 = ds.getTempC(ds2);  // Считываем температуру датчика 2
     if(-55 < Temp_2 && Temp_2 < 120){Temp2 = Temp_2; ds2shet=0;} delay(50);// Если нет ошибки, то обновляем температуру
     if(Temp1 < -55 || Temp1 > 120)   {ds1shet++;} // +1 к счетчикам ошибок
     if(Temp2 < -55 || Temp2 > 120){ds2shet++;} // +1 к счетчикам ошибок 
     
     if (Temp1 < AlarmTemp){digitalWrite(Error, ErrorOn);}    
     if (Temp1 > AlarmhTemp){statusotp==0;digitalWrite(Error, ErrorOn);}       
     if (Temp2 < AlarmTemp){digitalWrite(Error, ErrorOn);} 
     if (Temp2 > AlarmhTemp){statusotp==0;digitalWrite(Error, ErrorOn);} 
 previousMillis = currentMillis;}
      
      if (statusotp==0){digitalWrite(Relay1, !Relay1On); digitalWrite(Relay2, !Relay2On);} // Отключить нагрев
      if (ds1shet >2 && ds2shet >2) {statusotp=0;digitalWrite(Error, ErrorOn);} // Если нет связи с датчиками температуры отключить нагрев
      
  if (statusotp==1) // Климат-контроль по датчику температуры в зале
     {  if ( Temp1 >( TstatTemp + Hysteresis )){digitalWrite(Relay1, !Relay1On);} // Отключить нагрев если температура больше желаемой
        if ( Temp1 <( TstatTemp - Hysteresis )){digitalWrite(Relay1, Relay1On);}  // Включить нагрев если температура меньше желаемой
        if ( ds1shet >2){statusotp=2;}                    // если нет связи с датчиком 1 перейти на датчик 2
     }
  if (statusotp==2) // Климат-контроль по датчику температуры в кухне
     {  if ( Temp2 >( TstatTemp + Hysteresis )){digitalWrite(Relay1, !Relay1On);} // Отключить нагрев если температура больше желаемой
        if ( Temp2 <( TstatTemp - Hysteresis )){digitalWrite(Relay1, Relay1On);}  // Включить нагрев если температура меньше желаемой
        if ( ds2shet >2){statusotp=1;}                       // если нет связи с датчиком 2 перейти на датчик 1
     }
  if ((( TstatTemp - Temp1)>10)&&(digitalRead(Relay1) == Relay1On)){digitalWrite(Relay2, Relay2On);}
  if (( TstatTemp - Temp1)<10)  {digitalWrite(Relay2, !Relay2On);}
  if ((( TstatTemp - Temp2)>10)&&(digitalRead(Relay1) == Relay1On)){digitalWrite(Relay2, Relay2On);}
  if (( TstatTemp - Temp2)<10)  {digitalWrite(Relay2, !Relay2On);}
  if (digitalRead(Relay1) == !Relay1On) {digitalWrite(Relay2, !Relay2On);} 
  if (digitalRead(Ventcont) == LOW) {statusotp==0;digitalWrite(Error, ErrorOn);} 
  if (digitalRead(OpenCam) == LOW) {statusotp==0;}  
  if (digitalRead(Stop) == LOW) {statusotp==0;} 
 
  // обработка поворота энкодера на лету (ручное изменение уставки температуры))
  rotating = true;  // reset the debouncer
  if ((encoderR)^(encoderL)) {
    if (encoderR) {TstatTemp += 1;}
    else
    {TstatTemp -= 1;}
    TstatTemp = constrain(TstatTemp, 10, 90);
    encoderR = false;
    encoderL = false;
    }
 
  // ================ по нажатию кнопки энкодера - меню настроек ====================
  if(digitalRead(encoderK) == 0) {
    lcd.clear();
    lcd.setCursor(0, 0); //инфо на LCD
    lcd.print(F("< SETUP >"));         
    delay(200);
    int menuitem = 0;

    do {
      rotating = true;  // reset the debouncer
      if ((encoderR)^(encoderL)) {
        if (encoderR) { menuitem += 1; }
        else  { menuitem -= 1; }
        if ( menuitem > 3 ) { menuitem = 0; } // границы пунктов меню
        if ( menuitem < 0 ) { menuitem = 3; }
        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.HYSTERESIS SET")); 
        break;
      case 2:
        lcd.print(F("2.L-ALARM SET   ")); 
        break;
      case 3:
        lcd.print(F("3.H-ALARM SET   ")); 
        break; 
            }
      }
    while (digitalRead(encoderK)==1);   // если нажата кнопка энкодера или таймаут - обработка пункта меню (номер пункта - в menuitem)  
    
    switch(menuitem)
 {
    // ====== пункт 0 - выход
    case 0:     
      break; // case 0 out 
      
    // ====== пункт 1 - установка гистерезиса
    case 1:
      HysteresisOld = Hysteresis;
      lcd.clear();
      lcd.setCursor(0, 0); //инфо на LCD
      lcd.print(F("SETUP HYSTERESIS")); 
      delay(200);
      do {
        lcd.setCursor(0,1);
          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, 5); // крайние значения
 }
      while (digitalRead(encoderK)==1);
      if (EEPROM_float_read(HysteresisEEaddr) != Hysteresis) {
      EEPROM_float_write(HysteresisEEaddr, Hysteresis);      
      }
      else {
        Hysteresis = HysteresisOld;
      }
      break; // case 1 out
 
      // ====== пункт 2 - установка коррекции L alarm температуры 
    case 2:
     // MenuTimeoutTimer = 30; //таймер таймаута, секунд
      lcd.clear();
      lcd.setCursor(0, 0); //инфо на LCD
      lcd.print(F("L ALARM-TEMP SET")); 
      delay(200);
      do {
        lcd.setCursor(0,1);
          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, 50); // крайние значения
 }
      while (digitalRead(encoderK)==1);
      if (EEPROM_float_read(AlarmTempEEaddr) != AlarmTemp) {
      EEPROM_float_write(AlarmTempEEaddr, AlarmTemp); 
      }
      else {
        AlarmTemp = EEPROM_float_read(AlarmTempEEaddr);
      }
      break; // case 2 out

      // ====== пункт 3 - установка коррекции H alarm температуры 
    case 3:
      lcd.clear();
      lcd.setCursor(0, 0); //инфо на LCD
      lcd.print(F("H ALARM-TEMP SET")); 
      delay(200);
      do{
        lcd.setCursor(0,1);
          lcd.print(AlarmhTemp, 0); 
          lcd.write(0x02); // значок градуса
        
        rotating = true;  // reset the debouncer
        if (encoderR) {
          AlarmhTemp += 1;
          encoderR = false;
        }
        if (encoderL) {
          AlarmhTemp -= 1;
          encoderL = false;
        }
        AlarmhTemp = constrain(AlarmhTemp, 50, 105); // крайние значения
      }
      while (digitalRead(encoderK)==1);
      if (EEPROM_float_read(AlarmhTempEEaddr) != AlarmhTemp) {
      EEPROM_float_write(AlarmhTempEEaddr, AlarmhTemp); 
      }
      else {
        AlarmhTemp = EEPROM_float_read(AlarmhTempEEaddr);
      }
      break; // case 3 out
       
    delay(200);
    lcd.clear();
  }
}
}
 
// ===== SUBROUTINES ==================================================================
 
// ========= чтение/запись 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 =============================
void doEncoderA(){
  if ( rotating ) {
    delay (1) ;   }
  if( digitalRead(encoderA) != A_set ) {  // debounce once more
    A_set = !A_set;
    if ( A_set && !B_set )
    {
      encoderR = true;
      rotating = false;    }}}
void doEncoderB(){
  if ( rotating ) {
    delay (1);  }
  if( digitalRead(encoderB) != B_set ) {
    B_set = !B_set;
    if( B_set && !A_set ) {
      encoderL = true;
      rotating = false;}}}

 

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

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

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

balbes323 пишет:

 При этом модуля часов у меня там не предусмотрено. Всю голову сломал нах и гугл не помогает. Может кто подскажет? 

использовать таймер на millis() .  измерять температуру в начале и в конце таймера. Их разность и будет дельта за это время. 

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

.

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

Макс, я с миллисом не очень разобрался, в моем коде уже есть интервал для замера температур, но он короткий. Можно ли объявить еще интервал и если да, как это делается? И еще, вчера не тот код выложил, вечером выложу правильный.

MaksVV
Offline
Зарегистрирован: 06.08.2015
long previousTime = 0;    // храним время последнего начала отсчета таймера (переменные можно называть по-разному, чтобы отличать таймеры)
long intervalTime = 60000;     // интервал 1 мин например (60000 мсек)
bool zamer_1 = false;          // флаг для замера t1

void setup() {
  
бла бла 
}

void loop() {
 
 if (zamer_1==false) { t1 = бла бла ;  zamer_1 = true } //замеряем здесь t1, флаг zamer_1 после замера делаем true, чтобы один раз только замерялось при одном цикле таймера
 
 unsigned long currentTime = millis();

   if(currentTime - previousTime > intervalTime) { // Если таймер кончился, замеряем t2

    t2 = бла бла  

тут сравниваем t2-t1 и делаем что-то в зависимости от величины дельта температур
   
    previousTime = currentTime; zamer_1 = false;  } // сбрасываем таймер, флаг zamer_1 тоже сбрасываем

// далее таймер запускается снова

}

 

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

Коллеги, может кому интересно, приладил в программу запись на СД карту. С индикацией процесса записи(светодиод светится пол секунды, когда запись идёт. Запись осуществляется раз в 2 минуты по условию, когда на часах выставляется ..2 мин 0 секунд.

 if(RTCSekunda==0){                                   // если секунды равны 00
        if(RTCMinuta%2==0){//запись каждые  --2 мин
          digitalWrite(31, HIGH);   // идет запись на карту
                

 // make a string for assembling the data to log:
  String dataString = "";
t = rtc.getTime();
    dataString += (t.date, DEC);// день
     dataString += " ";
dataString += String(rtc.getMonthStr());//месяц
 dataString += " ";
dataString += String(t.hour, DEC);
dataString += ":";
dataString += String(t.min, DEC);

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";

delay(500);

  // 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);

    digitalWrite(31, LOW);    // окончание записи на карту
  }
  // if the file isn't open, pop up an error:
  else {
    Serial.println("error opening datalog.txt");

Но есть косячёк- пока длится нулевая секунда, программа успевает сделать запись 2-3 раза. понимаю, что если вставить задержку не 500мс а 900, то будет все хор, но мы же боремся за оптимизацию программы. Ка же сделать красиво и оптимально?

Внедрил код как у MaksVV на опрос Датчиков DS18. Установил таймер на 8 сек. Работает!  Только не получается сделать отображение температуры с точностью до десятой доли ,хотя прописывал:

TempBoilerC =  ds.read() | (ds.read()<<8); //прочитаны 2 байта      

        TempBoilerC = TempBoilerC /16.0;

 

obuhanoe
Offline
Зарегистрирован: 18.05.2016

Slavyanin55,  прочитал Вашу тему очень интересно, большое спасибо.

Возник один вопрос - хочу реализовать резервное питание через ИБП. Как у вас это реализовано физически и как реализовано в коде?

Спасибо.

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

Коллеги, можно мне со своим вопросом встрять? Кто-то решал задачу контроля состояния шилда SIM900?
У меня на даче стоит смс- розетка уже третий месяц. На улице бывало до -30, и я не даю уйти дому в минус с помощью калориферов.
Проблема в том, что иногда шилд выключается (а Мега 2560 продолжает работать) или теряет сеть, и поэтому перестаёт отвечать на смс запросы. Хочется его перезагрузить, а для этого надо спросить его состояние, и если нет сети или он выключен-то сделать нужное действие. У кого-нибудь есть протестированный кусочек кода?

dr.lmg
dr.lmg аватар
Offline
Зарегистрирован: 07.01.2016

У меня есть, правда проверка состояния идет на момент запуска самой меги, но можно и просто на опрос состояния сделать.
Другой момент, как модуль отваливается по питанию, а сама мега работает?
Я использую библиотеку SIM900, соответственно, у меня не АТ команды.

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

При перезагрузке Меги или в момент включения подаётся 3-х секундный импульс на 9 ножку шилда, который и включает шилд. Каким образом шилд выключается- не знаю. У нас, бывает, пропадает питание по всему саду, но при восстановлении по идее и Мега, и шилд должны включиться. Просто он перестаёт отвечать, я еду на дачу и руками перезагружаю. Да, собственно, мне и не важна причина, главное - повысить надёжнось. Мега должна проверять шилд ну, хотя бы через час, и послать ему импульс на включение (или на выключение/ включение).

Библиотеку не стал использовать, т.к. вроде AT команд хватает.

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

obuhanoe пишет:

Slavyanin55,  прочитал Вашу тему очень интересно, большое спасибо.

Возник один вопрос - хочу реализовать резервное питание через ИБП. Как у вас это реализовано физически и как реализовано в коде?

Спасибо.

Тоже интересует этот вопрос. Думаю не на ИБП тратиться, а поставить старый 12- вольтовый автомобильный аккумулятор, не совсем дохлый. При наличии сети он должен подзаряжаться слабым током, а при обесточивании- послать смс. При восстановлении энегроснабжения- тоже смс. Как-то так, не должно быть сложно.

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

obuhanoe пишет:

Slavyanin55,  прочитал Вашу тему очень интересно, большое спасибо.

Возник один вопрос - хочу реализовать резервное питание через ИБП. Как у вас это реализовано физически и как реализовано в коде?

Спасибо.

Тоже интересует этот вопрос. Думаю не на ИБП тратиться, а поставить старый 12- вольтовый автомобильный аккумулятор, не совсем дохлый. При наличии сети он должен подзаряжаться слабым током, а при обесточивании- послать смс. При восстановлении энегроснабжения- тоже смс. Как-то так, не должно быть сложно.

dr.lmg
dr.lmg аватар
Offline
Зарегистрирован: 07.01.2016

Naz, не совсем понимаю, как у Вас реализовано общение gsm модуля. По идее скрипт, чтобы прочитать полученную смс, должен регулярно обращатся к gsm. Тут и должно проверятся условие, есть смс, нет смс, модуль не отвечает. Если не отвечает - ресет на пин. Вот и все.

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

Все очень просто. Посмотрите void nastroyka gsm. В начале работы мы настраиваем gsm модуль посредством АТ команд, чтобы он при получении смс сразу сливал его в мегу. А мега просто ждет, что упадет в сериал и реагирует соответственно. Почитайте в google АТ команды gsm модемов и все станет ясно.

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

Попробуйте проверять состояние модема командой AT+CPAS к примеру раз в час, если не ответил, или ответил не так, даем ему с любого пина ардуины ресет, если я не ошибаюсь, на сим 900 это пин16, далее ждем загрузки и снова даем настройку.

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

Спасибо, все получилось)

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

naz пишет:

Коллеги, можно мне со своим вопросом встрять? Кто-то решал задачу контроля состояния шилда SIM900?
У меня на даче стоит смс- розетка уже третий месяц. На улице бывало до -30, и я не даю уйти дому в минус с помощью калориферов.
Проблема в том, что иногда шилд выключается (а Мега 2560 продолжает работать) или теряет сеть, и поэтому перестаёт отвечать на смс запросы. Хочется его перезагрузить, а для этого надо спросить его состояние, и если нет сети или он выключен-то сделать нужное действие. У кого-нибудь есть протестированный кусочек кода?

Рабочий урезаный код моей проги, работает у меня уже более года)

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

Я люблю работать с памятью ардуины, т.к. хочу управлять сам своим ус-вом

В данном примере нет работы с памятью.


#include <SoftwareSerial.h>
SoftwareSerial gsm(2, 3); // 2-txd, 3-rxo
#define led 13                 // светодиод

String NBoss = "79817425566";

int i = 0;
int Automatic = 0;
int StartGSM = 0;

// Переменные для чтения смс
String currStr = "";
String dataSmsN = "";
int flag1 = 0;
int flag2 = 0;
String currStrN = "";
char currSymb = 0;
String dataSms = "";
String dataBalance = "";
//String dataBalanceNumber = "";
String dataBalanceTemp = "";
String val = "";
int ch = 0;
char data = 0;

// Переменные для обработки смс +CSQ
int intNumberLevelFirst = 0;
int intNumberLevelSecond = 0;
int IntSignalLevel = 0;
int FlagSignal = 0;

int countLed = 0;
long counter = 0;
long timerForSignalGSM = 1000000;
int timerSearchGSM = 20;// таймер для регистрации сети GSm 20*2000=40 сек

int tempBalans = 0; // переменная, хранящая метку о запросе баланса
int tempZaprosBalansa = 0; // переменная, хранящая метку о запросе каждый день баланса

int SendSmsDeviceOn = 0;

void setup() {
  // Мигание светодиода на плате, говорит о работоспособности системы
  pinMode(led, OUTPUT); digitalWrite(led, LOW);

  // Читаем из памяти данные о состоянии системы
  Automatic = 1;//EEPROM.read(0); // Убрал для примера

  
  // делаем задержку на поиск сотовой сети
  for (i=0; i<=timerSearchGSM; i++){
    if (Automatic == 1){digitalWrite(led, HIGH);delay(250);}
    if (Automatic == 1){digitalWrite(led, LOW);delay(250);}
  }
}

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

  // Работоспособность системы
  countLed++;
  if (countLed >= 500){
      digitalWrite(led, HIGH);
    }
    if (countLed >= 1000){
      digitalWrite(led, LOW);
      countLed = 0;
    }

// Проверяем включено ли было устройство, если система на охране или снята с охраны и сеть есть
  if (Automatic <=1 && SendSmsDeviceOn == 1 && FlagSignal == 1 && StartGSM == 6){
    smsSendAlarm("Hi, Device on!");
    SendSmsDeviceOn = 0;
  }

  
    // Проверка уровня сигнала во время работы системы каждые 20сек(400000)
    // Смысл этой процедуры: проверка по таймеру и если уровень сигнала нормальный и вроде бы сиситема работает нормально,
    // делаем проверку уровня сигнала для проверки работоспособности системы, если сигнала нет, смотрим код, где все начинается заново
    
    counter++;
    if (counter >= timerForSignalGSM && FlagSignal == 1 && StartGSM == 6){
      gsm.println("AT+CSQ");
      delay(300);
      // Обнуляем счетчик
      counter = 0;
    }

//*********************
    if (gsm.available()) {          //есть данные от GSM модуля
    
    currStr = "";                      //выждем, чтобы строка успела попасть в порт целиком раньше чем будет считана
    currStrN = "";
    dataBalanceTemp = "";
    dataSms = "";
    val = "";
    flag1 = 0;
    flag2 = 0;
    while (gsm.available()) {      //сохраняем входную строку в переменную val
      ch = gsm.read();  //int
      val += char(ch);      // String
      data = ch;      // char = int
      if ('\r' == data) {
        currStr = "";
      } else if ('\n' != data) {
          currStr += String(data);
          dataSms = currStr;
        }
        //+CMT: "+79819998877","","16/04/18,20:25:08+12"
      if (data == '+' && flag1 == 0){flag1 = 1;}
      if (data == 'C' && flag1 == 1){flag1 = 2;}
      if (data == 'M' && flag1 == 2){flag1 = 3;}
      if (data == 'T' && flag1 == 3){flag1 = 4;}
      if (data == '+' && flag1 == 4){currStrN = "";flag1 = 5;}
      if (data != '"' && flag1 == 5){currStrN += String(data); dataSmsN = currStrN;}
      if (data == '"' && flag1 == 5){flag1 = 6;}
      
      //+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 (data == ':' && flag2 == 7){dataBalanceTemp = ""; flag2 = 8; goto c;}
//      if (data != ':' && flag2 == 8){dataBalanceTemp += String(data); dataBalanceNumber = dataBalanceTemp; flag2 = 9;}
      
    }
    
// Смотрим данные полученные //режим кодировки СМС - обычный (для англ.)
    if (val.indexOf("+CMGF") > -1){
      if (dataSms.indexOf("OK") > -1) {
        StartGSM = 1;
      }
    }
// Смотрим данные полученные //устанавливает программный контроль потоком передачи данных
    if (val.indexOf("+IFC") > -1){
      if (dataSms.indexOf("OK") > -1) {
        StartGSM = 2;
      }
    }
// Смотрим данные полученные //открывает доступ к данным телефонной книги SIM-карты
    if (val.indexOf("+CPBS") > -1){
      if (dataSms.indexOf("OK") > -1) {
        StartGSM = 3;
      }
    }
// Смотрим данные полученные //включает оповещение о новых сообщениях, новые сообщения
    if (val.indexOf("+CNMI") > -1){
      if (dataSms.indexOf("OK") > -1) {
        StartGSM = 4;
      }
    }
// Смотрим данные полученные //запрет всех входящих звонков.
    if (val.indexOf("+GSMBUSY") > -1){
      if (dataSms.indexOf("OK") > -1) {
        StartGSM = 5;
      }
    }
// Смотрим данные полученные //команда удалит все сообщения
    if (val.indexOf("+CMGDA") > -1){
      if (dataSms.indexOf("OK") > -1) {
        StartGSM = 6;
      }
    }
// Смотрим данные полученные от модуля +CSQ: 22,0
    if (val.indexOf("+CSQ") > -1) {
      for (i=0; i<=20; i++){
        if (val[i] == 58) {
          intNumberLevelFirst = val[i+2]-48;
          if (val[i+3] == 44){ intNumberLevelSecond = 0;}
          if (val[i+3] != 44){ intNumberLevelSecond = val[i+3]-48;}
          if (val[i+3] == 44){IntSignalLevel = intNumberLevelFirst;}
          if (val[i+3] != 44){IntSignalLevel = (intNumberLevelFirst*10) + intNumberLevelSecond;}
        }
      }
      if (IntSignalLevel == 99 || IntSignalLevel == 0){
        for (i=0; i<=timerSearchGSM; i++){
          if (Automatic == 0){// можно что-то включить, например светодиод}
          delay(1000);
          if (Automatic == 0){// можно что-то выключить, например светодиод}
          delay(1000);
        }
        FlagSignal = 0; StartGSM = 0;
      }
      if (IntSignalLevel <=32 && IntSignalLevel !=0){
        FlagSignal = 1;
      }
    }
    
// Смотрим данные полученные от модуля пришло смс
    if (val.indexOf("+CMTI:") > -1) { // +CMTI: "SM",
      StartGSM = 0;
    }
    
// Смотрим данные полученные от модуля, Получили смс с балансом, теперь отсылаем 
    if (val.indexOf("+CUSD:") > -1) { 
      if (dataBalance != "" && tempBalans == 1) {
        smsSendAlarm("Hi, " + dataBalance);
        tempBalans = 0;
        dataBalance = "";
      }
      if (dataBalance[8]-48 >= 1 && dataBalance[9]-48 >= 0 && dataBalance[10]-48 >= 0){
        // ничего не делаем
      }else if (tempZaprosBalansa == 1){
        smsSendAlarm("Hi, balance < 100r, vash balance = " + dataBalance);
        tempZaprosBalansa = 0;
        dataBalance = "";
      }
    }






//----------------------- определение факта приема СМС и сравнение номера(ов) с заданным(и)
    if (val.indexOf("+CMT") > -1) {
// Здесь обрабатываем смс
    }//+cmt
    
  }
}// коней if gsm
}
}


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

 

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

dr.lmg пишет:
Naz, не совсем понимаю, как у Вас реализовано общение gsm модуля. По идее скрипт, чтобы прочитать полученную смс, должен регулярно обращатся к gsm. Тут и должно проверятся условие, есть смс, нет смс, модуль не отвечает. Если не отвечает - ресет на пин. Вот и все.

Сделано так: регулярно опрашивается буфер UART, соединённый с gsm. И если буфер пуст- непонятно, то ли нет входящего смс, то ли шилд сеть потерял/ вырубился.

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

Спасибо, друзья, за ответы, попробую. stambilov, хотелось бы без gsm библиотеки обойтись..

 

Maksim82
Offline
Зарегистрирован: 03.02.2017

Добрый день. Сегодня наткнулся на данную тему, очень заинтересовала. Есть желание сделать умную квартиру, на дом ещё не заработал. Работаю на производстве, у нас стоят контроллеры BECKHOFF, очень интересная штука, почитал на них собирают умные дома, на самой старой серии bc9000. Хотел купить б/у но продают только в Штатах и в Германии, а стоимость за пересылку кусается. А тут увидел на Меге такой проект и загорелся попробовать. До этого на меге собрал только 3d принтер, так что опыта не много. Я так понимаю у Вас проект существует уже с 14 года. Хотел спросить, много у вас элементов сгорало и ломалось за это время? Пробежался по форуму и не увидел спецификации, думаю она есть, но не нашел. Хотел посмотреть какие шильды датчики и релюшки нужно купить для базовой конфигурации.

 

RuslanRec
Offline
Зарегистрирован: 02.11.2016

Доброго всем дня, доехал конструктор до наших краев. Подскажите несведующему, последнюю прошивку не могу залить на mega2560  выходит ошибка при компиляции. В какую сторону смотреть? Бибилиотеки вроде перекинул в папку с Arduino.

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

может нужно выбрать нужный МК в настройках а именно мегу 2560. (Инструменты => плата)

dr.lmg
dr.lmg аватар
Offline
Зарегистрирован: 07.01.2016

Maksim82, при правильном подборе и сборке всех элементов там ломаться и сгорать нечему.

Maksim82
Offline
Зарегистрирован: 03.02.2017

Я заказал уже на пробу мегу и кней температурные датчики, релюшку импульсную, платку с обычными реле. вайфайный модуль и плату изернет. несколько объемников и всякой мелочёвки ещё. Хотел сделать базу какую то к которой можно было бы подключать разные датчики. Думал тут какую то статистику и спецификацию почерпнуть, но все молчат.

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

Какая статистика тебя интересует? Тут все пилят проект под свои нужды, добавляя что-то от себя и заимствуя у других. Сформулируй вопрос понятно, что не получается, что пытаешься сделать, что недопонял и тебе подскажут. Для того форум и существует. Если что, моя почта s-tver@mail.ru, чем смогу.

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

Maksim82 пишет:

 спецификацию почерпнуть

так, что на ум быстро пришло

Мега, gsm sim800L+ антенна выносная + модуль питания к нему, часы ds3231, дисплей 4 строчный i2с, гора термодатчиков ds18b20, гора PIR датчиков,  гора оптопар pc817, платы реле, mp3 модуль, датчик инфракрасный для приема сигналов от пульта, пищалка от материнской платы компьютера, wi-fi модуль, bluetooth модуль, ethernet модуль, блок питания 12в и 5В, ИБП для блока питания с АКБ, 4g wi-fi роутер, бухта провода в экране 4 жилы или 8 жил.

Maksim82
Offline
Зарегистрирован: 03.02.2017

ООО половину уже купил, оптопары не взял пожалу и gsm модуль, дисплей ещё от принтера остался без применения. спасибо. Хотел спросить, делаю пока всю подготовку, квартира ещё строится, сдаваться будет на нулевой стадии отделки, так что поле для прокладки обширное. Хотел по проводам спросить. Думаю к каждой розетке и выключателю проложить витую пару экранированную и легко достать и запас по проводам будет, там всётаки 8 жил. сечения будет достаточно?

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

Доброй ночи, товарищи! Вот сваял окончательную версию термостата для управления конвекторами,  поставил, все работает,  все устраивает. Месяц работы, полет нормальный. Ежедневный отчет по GSM приходит исправно.Управляется по GSM тоже ок. Можно даже позвонить туда и оттуда и полноценно поговорить.Но вот сижу и думаю... Хата моя стоит за 300 км от меня, там мать живет, программистов нет.
ВООБЩЕ. НИКАКИХ.
А  если датчик температуры накрылся? Он же адресный, придется тогда брать ноут и новыйдатчик и ехать менять, т.к. без скетча никто ничего не сможет сделать. Далее, возниклаидея прикрутить еще датчик на улицу. Тут уже адрес нужен и ремонтопригодностьсводится к 1 человеку, который это сделал. Вот сижу и думаю, ведь можно и без адресовопросить все датчики на шине, но как контроллер узнает, какой из них какой, если адресане прописаны? Но если это реализовать, то обслуживание и ремонт наших систем упростится в разы.
Может, у кого есть идеи по этому поводу?

#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 11
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature DS18B20(&oneWire);
DeviceAddress DS18B20Address;

#define encoderA    12 // энкодер - поворот вправо (об землю)
#define encoderB    13 // энкодер - поворот влево (об землю)
#define encoderK    A3 // энкодер - кнопка (об землю)
#define BeepPin     9 // пищалка
#define BeepToneNo  2000 // тон звука "No", герц
#define BeepToneYes 4000 // тон звука "Yes", герц
#define BeepToneNoDuration 200 // длительность звука "No", мс
#define BeepToneYesDuration 200 // длительность звука "Yes", мс
#define Relay  10 // нога, к которой подключено реле
#define RelayOn LOW // полярность сигнала включения реде (HIGH/LOW)
 
// LCD connection RS, E, D4, D5, D6, D7
// R/W - to ground
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
 
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, если текущая строка является сообщением
boolean SMSsent = false;
boolean SMSsenti = false;
boolean SMSDelete=false;
boolean TimeSMSzapros=false;

#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)&& (!SMSsent)){
      tone(BeepPin,4000,5);startOneSMS();Serial.print("TREVOGA!!! ");Serial.print("TT=");Serial.print(Temperature);EndSMS();
      SMSsent = true;SMSsenti = false;}
    
   if ((Temperature > AlarmTemp)&& (!SMSsenti)){
      tone(BeepPin,4000,5);startOneSMS();Serial.print("TREVOGA-OFF  ");Serial.print("TT=");Serial.print(Temperature);EndSMS();
      SMSsenti = true;SMSsent = false;}
    
   if(Hours == 0 && Minutes == 2 && SMSDelete==false){
      Serial.print("AT+CMGDA=«DEL ALL»\r"); SMSDelete=true;} // Удаляем в 0:02 все СМС.
      if(Minutes != 2){SMSDelete=false;} 
    
   if(Hours == 10 && Minutes == 0 && TimeSMSzapros==false){
      SMSzapros(); TimeSMSzapros=true;} // в 12:00 отправляем СМС о состоянии.
      if(Minutes != 0){TimeSMSzapros=false;} // сброс флага TimeSMSzapros
  }
 
  // обработка поворота энкодера на лету (ручное изменение уставки температуры))
  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"
         Dozvon();
        }
        
      }
      
      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("ZVONOK"))   { Dozvon();} 
    
    if (!currStr.compareTo("ZAPROS"))   { SMSzapros();}   
    if (!currStr.compareTo("+30"))   { TstatTemp = 30;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
    if (!currStr.compareTo("+29"))   { TstatTemp = 29;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
    if (!currStr.compareTo("+28"))   { TstatTemp = 28;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
    if (!currStr.compareTo("+27"))   { TstatTemp = 27;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
    if (!currStr.compareTo("+26"))   { TstatTemp = 26;startOneSMS();Serial.print(TstatTemp);Serial.print(" TstatTemp-OK");}
    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");}
    EndSMS();
    
        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(" HIST=");Serial.print(Hysteresis);}
    if ((Timer2Enabled)&!(Timer1Activated)) {Serial.print("TIMER 2  ");Serial.print("T2=");Serial.print(Timer2Temp);Serial.print("/TU=");
  Serial.print(Temperature);Serial.print(" HIST=");Serial.print(Hysteresis);}
    if ((Timer3Enabled)&!(Timer1Activated)) {Serial.print("TIMER 3  ");Serial.print("T3=");Serial.print(Timer3Temp);Serial.print("/TU=");
  Serial.print(Temperature);Serial.print(" HIST=");Serial.print(Hysteresis);}
   else {Serial.print("TIMER OFF  ");Serial.print("TSET/TT=");Serial.print(TstatTemp);Serial.print("/");Serial.print(Temperature);Serial.print(" HIST=");Serial.print(Hysteresis);}  
    if (digitalRead(12)==HIGH) {Serial.println("  NAGREV-OFF"); } else { Serial.println("  NAGREV-ON");}
    EndSMS();                                 
}

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

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);
}
void Dozvon() //__________________Цикл дозвона абоненту (для аудиоконтроля)___________________
{
Serial.println("AT+CMIC=0,12");    // Команда для установки чувствительности микрофона Поэкспериментировать с цифрой.
// 0,- это канал микрофона (1,2,3),15 это уровень см.инструкцию к СИМ900
delay(200);

Serial.println("ATD+79206888901;");  // Набираем номер
}

 

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

Hyperline SFTP4-C7A-S22-IN-LSZH-WH-500 (SSTP4-C8-SOLID-INDOOR-LSZH-500)У меня все вот таким проложено, у него двойной экран, нормально работает. Но дорогой, сцуко.

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

Maksim82 пишет:

 Хотел по проводам спросить. Думаю к каждой розетке и выключателю проложить витую пару экранированную и легко достать и запас по проводам будет, там всётаки 8 жил. сечения будет достаточно?

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

anshor
anshor аватар
Offline
Зарегистрирован: 21.06.2016

Здравствуйте, повторяю Ваш проект немного переделывая под себя. Добавил ключ Ibutton для снятия и постановки на охрану. У меня вопрос по схеме. Зачем в опторазвязке светодиоды? Понятно что удобно посмотреть при настройке, а в дальнейшей работе может от них отказаться  ведь даже 20 милиампер умноженых на 15 штук при работе от аккумулятора в мороз очень значительно. Или я неправ специалисты подскажите??? 

Short Circuit
Short Circuit аватар
Offline
Зарегистрирован: 17.05.2015

поставьте синие светодиоды и килоом 10-20 с ними.....  будут вообще фигню потреблять, но индицировать достаточно ярко.

m-zzz
Offline
Зарегистрирован: 30.05.2015

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

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

И все.. пофигу на адрес, к пину (например 10) подключен датчик на улице...

И все. с "десятки" получаем уличную температуру..

Сдох датчик, отключили и воткнули новый.. все..

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

Никаких идей более нет..

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

m-zzz пишет:

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

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

И все.. пофигу на адрес, к пину (например 10) подключен датчик на улице...

И все. с "десятки" получаем уличную температуру..

Сдох датчик, отключили и воткнули новый.. все..

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

Никаких идей более нет..

 

Вот красивые датчики температуры-влажности, можно даже покрасить в любой цвет

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

Ссылка на Али

Код для датчиков:

//Подключаемые Библиотеки
#include <SoftwareSerial.h>   //Библиотека для работы с Serial port
#include <DHT.h>              //Библиотека для работы с датчиками температуры-влажности

// Объявление датчиков температуры и влажности
#define TempOutSide 3       //Температура и влажность на улице, подкл.на цифровой пин 3
#define DHTTYPE DHT21        // DHT (AM2301)
DHT dht1(TempOutSide, DHTTYPE);

// Переменные
float h = 0;
float t = 0;
float tOut;
float hOut;
int Error = 777;          // код ошибки для вывода

void setup() {
  Serial.begin(9600);
   // Подключаем датчики температуры и влажности
  dht1.begin();
}

void loop() {
  // Читаем данные с датчика
  h = dht1.readHumidity();
  t = dht1.readTemperature();
  if (isnan(t) || isnan(h)) {
    tOut = Error;
    hOut = Error;
  } else {
    tOut = t;
    hOut = h;
  }

  // Выводим данные с датчика
  Serial.print("TE: "); // Температура
  Serial.println(tOut);
  Serial.print("ME: ");
  Serial.println(hOut); // Влажность
}

 

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

Вот наконец то собрал все, протестировал)) скоро поеду ставить, потом фотки выложу, а сейчас вот так выглядит мой бутерброд:

22 реле управления светом

1 реле управление активации датчика освещенности

22 индикации состояния света

1 индикация состояния д.освещенности

6 датчиков температуры-влажности

3 токовых датчика для отображения тока по фазам, также отображение мощности в КВт

1 понижающая плата с 12 на 5В

rw4cju.ru
Offline
Зарегистрирован: 12.08.2015

Всем доброе время суток.

Собираю похожую систему. В основе MEGA2560 R3. Установлена в стеновом боксе. Внутри 4 этажерки платы.

1. Плата питания.

2 Плата индикации LCD 16*2. 7 светодиодов. 7 переключателей (тумблеры).

3. Плата реле 8 шт входные цепи. Оптопара +74НС245 (формирователь) всего 12 входов.  Интернет шилд ENC28c60 также на этой плате дополнительные элементы питания, цепи подключения и защиты внешних датчиков (DS18b20. DHT11. DHT22. а также в плане датчиков газа) остальные датчики контакные.движения. и пр. также получают питание и подключаются к этой плате

4. Плата Мега. Плата на которой сама Ардуно Мега, через BLS раземы устанавливается (спиной вверх )  Также на ней установлено 3 (панельки) для портов RX-TX (UATR) - RS485 (MAX485). Плата DS1302 (часы) Для подключения внешних блоков. Уже наработана база по модулям и опыт по МОДБАС-у.

В остальном сеть на витой паре. Сервер МаjorDomo Контроллер управления воротами (откатные). калитка (эл. замок. видеокамера (домофон) контроллер ключей. Датчики температуры в комантах и постойках (погреб. баня. мастерская). и пр.

Управлене нагрузками реле. Видеонаблюдение 4 камеры на видеорегистраторе. Сама схема постоянно развивается с 2011 г. в основном на данный момент это преход на микроконтроллеры и датчики на основе NRF24 (MySensors).

Фотографии чуть позже... пока не дома.

 

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

Вот наконец то подключил все компоненты аля умного дома.

Видео обзор сделаю чуть позже.

Вот как получилось:

rw4cju.ru
Offline
Зарегистрирован: 12.08.2015

stambylov пишет:

Вот как получилось:

Хорошо выглядит!!!!

Можно Ваш скетч поглядеть. Интресует именно отображение (информативная часть).

У меня вся система (логика) ранее была на сервере (системная плата Атом) но сейчас,после приобретения несколько плат Mega 2560 все решил пренести основные задачи на них. Автоматику. Еще есть небольшой сервер на ESP8266 (AMS http://majordomo.smartliving.ru/forum/viewtopic.php?f=19&t=2890 ) он в основном как информациооное поле. На планшет и пр. выдает информацию.

Если кому интересно, могу приложить ЛУТ плату для Mega (развязка)  ее можно доработать под свои задачи.

Плата https://yadi.sk/d/mvUavlbc3EvUqF

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

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

Хочу чтоб электрокотел с 23 ч до 7 утра работал по максимуму( по штатной уставке 22 градуса) а  в остальное время на минимуме (в режиме экономии 5 град).

Поделитесь, если не жалко кусочком кода.

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

rw4cju.ru пишет:

stambylov пишет:

Вот как получилось:

Хорошо выглядит!!!!

Можно Ваш скетч поглядеть. Интресует именно отображение (информативная часть).

У меня вся система (логика) ранее была на сервере (системная плата Атом) но сейчас,после приобретения несколько плат Mega 2560 все решил пренести основные задачи на них. Автоматику. Еще есть небольшой сервер на ESP8266 (AMS http://majordomo.smartliving.ru/forum/viewtopic.php?f=19&t=2890 ) он в основном как информациооное поле. На планшет и пр. выдает информацию.

Если кому интересно, могу приложить ЛУТ плату для Mega (развязка)  ее можно доработать под свои задачи.

Плата https://yadi.sk/d/mvUavlbc3EvUqF

 

Привет, код страницы смотрите под кодом Arduino

Весь код не скину, урезанный смотрите:

#include <DHT.h>              //Библиотека для работы с датчиками температуры-влажности
#include <Ethernet.h>         //Библиотека для работы с EthernetShield
#include <SD.h>
// size of buffer used to capture HTTP requests
#define BUFFER_SIZE 56

/*
  SD card read/write

 * Arduino  Uno     Mega
 ** MOSI    pin 11   51
 ** MISO    pin 12   50
 ** CLK     pin 13   52
 ** CS      pin 4    53
   * Pin layout should be as follows:
 * Signal     Pin              Pin               Pin
 *            Arduino Uno      Arduino Mega      MFRC522 board
 * ------------------------------------------------------------
 * Reset      9                5                 RST
 * SPI SS     10               53                SDA/CS
 * SPI MOSI   11               51                MOSI
 * SPI MISO   12               50                MISO
 * SPI SCK    13               52                SCK

 */
#define ETH_SS 53
#define SD_SS 4

//Подключение EthernetShield
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };   //physical mac address
byte ip[] = { 192, 168, 0, 103 };                      // ip in lan (that's what you need to use in your browser. ("192.168.1.178")
byte gateway[] = { 192, 168, 0, 1 };                   // internet access via router
byte subnet[] = { 255, 255, 255, 0 };                  //subnet mask
EthernetServer server(80);                             //server port     
String readString;

File webFile;                     // the web page file on the SD card

//Подключенные пины
// Индикация с импульсного реле освещения
#define iRele1 2                  //Освещение. Периметр дома
#define iRele2 3                  //Освещение.
#define iRele3 5                  //Освещение.
#define iRele4 6                  //Освещение.
#define iRele5 7                  //Освещение.
#define iRele6 8                  //Освещение.
#define iRele7 9                  //Освещение.
#define iRele8 11                 //Освещение.
#define iRele9 12                 //Освещение.
#define iRele10 13                //Освещение.
#define iRele11 14                //Освещение.
#define iRele12 15                //Освещение. 
#define iRele13 16                //Освещение.
#define iRele14 A0                //Освещение. 
#define iRele15 A4                //Освещение.
#define iRele16 A5                //Освещение.
#define iRele17 A6                //Освещение. 
#define iRele18 A7                //Освещение. 
#define iRele19 A8                //Освещение. 
#define iRele20 A9                //Освещение. 
#define iRele21 A10               //Освещение. 
#define iRele22 A11               //Активация д.освещения

// Импульсное Реле на освещение
#define Rele1 22                //Освещение.
#define Rele2 23                //Освещение. 
#define Rele3 24                //Освещение. 
#define Rele4 25                //Освещение. 
#define Rele5 26                //Освещение. 
#define Rele6 27                //Освещение. 
#define Rele7 28                //Освещение. 
#define Rele8 29                //Освещение. 
#define Rele9 30                //Освещение. 
#define Rele10 31               //Освещение.
#define Rele11 32               //Освещение. 
#define Rele12 33               //Освещение. 
#define Rele13 34               //Освещение. 
#define Rele14 35               //Освещение. 
#define Rele15 36               //Освещение. 
#define Rele16 37               //Освещение. 
#define Rele17 38               //Освещение. 
#define Rele18 39               //Освещение. 
#define Rele19 40               //Освещение. 
#define Rele20 41               //Освещение. 
#define Rele21 42               //Освещение. 
#define Rele22 43

// Объявление датчиков температуры и влажности
#define TempOutSide 44       //Температура и влажность на улице
#define TempInSide1 45       //Температура и влажность в доме 1 этаж Холл
#define TempInSide2 46       //Температура и влажность в доме 1 этаж Кабинет
#define TempInSide3 47       //Температура и влажность в доме 2 этаж Холл
#define TempInSide4 48       //Температура и влажность в доме 2 этаж Спальня
#define TempInSide5 49       //Температура и влажность в доме 2 этаж Детская 2-Настя

#define Power220 17          //Состояние напряжения сети 220В

//#define L1 A1          //Ток фазы 1
//#define L2 A2          //Ток фазы 2
//#define L3 A3          //Ток фазы 3
//#define 10// зарезервировано под Ethernet Shield

#define DHTTYPE DHT21        // DHT 21 (AM2301)

DHT dht1(TempOutSide, DHTTYPE);
DHT dht2(TempInSide1, DHTTYPE);
DHT dht3(TempInSide2, DHTTYPE);
DHT dht4(TempInSide3, DHTTYPE);
DHT dht5(TempInSide4, DHTTYPE);
DHT dht6(TempInSide5, DHTTYPE);

float h = 0;
float t = 0;
float tempL1 = 0;
float tempL2 = 0;
float tempL3 = 0;
float tOut;
float tIn1;
float tIn2;
float tIn3;
float tIn4;
float tIn5;
float hOut;
float hIn1;
float hIn2;
float hIn3;
float hIn4;
float hIn5;
int analogValue = 500;    // Значение для индикации состояния реле
int Error = 777;          // код ошибки для вывода на веб страницу по датчикам
void setup() {
  // Выхода Реле на освещение
  pinMode(Rele1, OUTPUT); digitalWrite(Rele1, !LOW);
  pinMode(Rele2, OUTPUT); digitalWrite(Rele2, !LOW);
  pinMode(Rele3, OUTPUT); digitalWrite(Rele3, !LOW);
  pinMode(Rele4, OUTPUT); digitalWrite(Rele4, !LOW);
  pinMode(Rele5, OUTPUT); digitalWrite(Rele5, !LOW);
  pinMode(Rele6, OUTPUT); digitalWrite(Rele6, !LOW);
  pinMode(Rele7, OUTPUT); digitalWrite(Rele7, !LOW);
  pinMode(Rele8, OUTPUT); digitalWrite(Rele8, !LOW);
  pinMode(Rele9, OUTPUT); digitalWrite(Rele9, !LOW);
  pinMode(Rele10, OUTPUT); digitalWrite(Rele10, !LOW);
  pinMode(Rele11, OUTPUT); digitalWrite(Rele11, !LOW);
  pinMode(Rele12, OUTPUT); digitalWrite(Rele12, !LOW);
  pinMode(Rele13, OUTPUT); digitalWrite(Rele13, !LOW);
  pinMode(Rele14, OUTPUT); digitalWrite(Rele14, !LOW);
  pinMode(Rele15, OUTPUT); digitalWrite(Rele15, !LOW);
  pinMode(Rele16, OUTPUT); digitalWrite(Rele16, !LOW);
  pinMode(Rele17, OUTPUT); digitalWrite(Rele17, !LOW);
  pinMode(Rele18, OUTPUT); digitalWrite(Rele18, !LOW);
  pinMode(Rele19, OUTPUT); digitalWrite(Rele19, !LOW);
  pinMode(Rele20, OUTPUT); digitalWrite(Rele20, !LOW);
  pinMode(Rele21, OUTPUT); digitalWrite(Rele21, !LOW);
  pinMode(Rele22, OUTPUT); digitalWrite(Rele22, !LOW);

  // Индикация с реле освещения
  pinMode(iRele1, INPUT);
  pinMode(iRele2, INPUT);
  pinMode(iRele3, INPUT);
  pinMode(iRele4, INPUT);
  pinMode(iRele5, INPUT);
  pinMode(iRele6, INPUT);
  pinMode(iRele7, INPUT);
  pinMode(iRele8, INPUT);
  pinMode(iRele9, INPUT);
  pinMode(iRele10, INPUT);
  pinMode(iRele11, INPUT);
  pinMode(iRele12, INPUT);
  pinMode(iRele13, INPUT);
  
  pinMode(Power220, INPUT);
  
  // Подключаем датчики температуры и влажности
  dht1.begin();
  dht2.begin();
  dht3.begin();
  dht4.begin();
  dht5.begin();
  dht6.begin();
  
  pinMode(ETH_SS, OUTPUT);
  SD.begin(SD_SS);
  digitalWrite(SD_SS, HIGH);
  digitalWrite(ETH_SS, HIGH);
  Ethernet.begin(mac, ip, gateway, subnet);
  server.begin();
}

void loop() {
   // Начинаем слушать EthernetSheild
  EthernetClient client = server.available();
  byte buff[BUFFER_SIZE];
 if (client&&(readString == "")) {
//  Serial.println("Start Ethernet");
    while (client.connected()) {   
      if (client.available()) {
        char c = client.read();
        if (readString.length() < 100) {
          readString += c;}
         if (c == '\n') {
          if (readString.indexOf("index0.htm") >0) {
            // send a standard http response header
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");
            client.println("Connection: close");
            client.println();
            // send web page
            webFile = SD.open("home0.htm"); // Открываем файл home0.htm для передачи в браузер
            if (webFile) {
                while (true) {
                    int n = webFile.read((char*)buff, BUFFER_SIZE);
                    if (!n)
                        break;
                    client.write(buff, n);
                }
                webFile.close();
            }
            readString=""; // Очищаем полученные данные с Web старницы
          }
          else
           if (readString.indexOf("icon.gif") >0) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: image/gif");
            client.println();
            webFile = SD.open("icon.gif");
            if (webFile) {
                while (true) {
                    int n = webFile.read((char*)buff, BUFFER_SIZE);
                    if (!n)
                        break;
                    client.write(buff, n);
                }
                webFile.close();
            }
            readString="";
          }
          else
          if (readString.indexOf("lampochka1.png") >0) {
            client.println("HTTP/1.1 200 OK");
            client.println();
            webFile = SD.open("l1.png");
            if (webFile) {
                while (true) {
                    int n = webFile.read((char*)buff, BUFFER_SIZE);
                    if (!n)
                        break;
                    client.write(buff, n);
                }
                webFile.close();
                
            }
            readString="";
          }
          else
          if (readString.indexOf("i1.jpg") >0) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: image/jpeg");
            client.println();
            webFile = SD.open("i1.jpg");
            if (webFile) {
                while (true) {
                    int n = webFile.read((char*)buff, BUFFER_SIZE);
                    if (!n)
                        break;
                    client.write(buff, n);
                }
                webFile.close();
            }
            readString="";
          }
          else
          if (readString.indexOf("j.min.js") >0) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: application/x-javascript");
            client.println();
            webFile = SD.open("j.js");
            if (webFile) {
                while (true) {
                    int n = webFile.read((char*)buff, BUFFER_SIZE);
                    if (!n)
                        break;
                    client.write(buff, n);
                }
                webFile.close();
            }
            readString="";
          }
          else
          if (readString.indexOf("index") >0) {
            send:
           // Формируем  начальное HTML
            client.println("HTTP/1.1 200 OK");
            client.println("Access-Control-Allow-Origin: *");
            client.println("Content-Type: application/json;charset=utf-8");
            client.println("Server: Arduino");
            client.println("Connection: close");
            client.println();
            client.print("[");                           // This is tha starting bracket of the JSON data
            // читаем данные с датчиков
              h = dht1.readHumidity();
              t = dht1.readTemperature();
              if (isnan(t) || isnan(h)) {
                tOut = Error;
                hOut = Error;
              } else {
                tOut = t;
                hOut = h;
              }
              h = dht2.readHumidity();
              t = dht2.readTemperature();
              if (isnan(t) || isnan(h)) {
                tIn1 = Error;
                hIn1 = Error;
                
              } else {
                tIn1 = t;
                hIn1 = h;
              }
              h = dht3.readHumidity();
              t = dht3.readTemperature();
              if (isnan(t) || isnan(h)) {
                tIn2 = Error;
                hIn2 = Error;
                
              } else {
                tIn2 = t;
                hIn2 = h;
              }
              h = dht4.readHumidity();
              t = dht4.readTemperature();
              if (isnan(t) || isnan(h)) {
                tIn3 = Error;
                hIn3 = Error;
                
              } else {
                tIn3 = t;
                hIn3 = h;
              }
              h = dht5.readHumidity();
              t = dht5.readTemperature();
              if (isnan(t) || isnan(h)) {
                tIn4 = Error;
                hIn4 = Error;
                
              } else {
                tIn4 = t;
                hIn4 = h;
              }
              h = dht6.readHumidity();
              t = dht6.readTemperature();
              if (isnan(t) || isnan(h)) {
                tIn5 = Error;
                hIn5 = Error;
                
              } else {
                tIn5 = t;
                hIn5 = h;
              }
              // Отправка данных температур  ///////////////////////////////////////////////
              //Улица
              client.print("{\"key\": 1, \"value\": ");
              client.print(tOut);
              client.print("},");
              //Холл 1 этаж
              client.print("{\"key\": 2, \"value\": ");
              client.print(tIn1);
              client.print("},");
              //Кабинет
              client.print("{\"key\": 3, \"value\": ");
              client.print(tIn2);
              client.print("},");
              //Холл 2 этаж
              client.print("{\"key\": 4, \"value\": ");
              client.print(tIn3);
              client.print("},");
              //Спальня
              client.print("{\"key\": 5, \"value\": ");
              client.print(tIn4);
              client.print("},");
              //Настя
              client.print("{\"key\": 6, \"value\": ");
              client.print(tIn5);
              client.print("},");
              //
              //Отправка данных влажностей///////////////////////////////////////////////
              //Улица
              client.print("{\"key\": 8, \"value\": ");
              client.print(hOut);
              client.print("},");
              //Холл 1 этаж
              client.print("{\"key\": 9, \"value\": ");
              client.print(hIn1);
              client.print("},");
              //Кабинет
              client.print("{\"key\": 10, \"value\": ");
              client.print(hIn2);
              client.print("},");
              //Холл 2 этаж
              client.print("{\"key\": 11, \"value\": ");
              client.print(hIn3);
              client.print("},");
              //Спальня
              client.print("{\"key\": 12, \"value\": ");
              client.print(hIn4);
              client.print("},");
              //Настя
              client.print("{\"key\": 13, \"value\": ");
              client.print(hIn5);
              client.print("},");
              //Средняя температура на 1 этаже
              client.print("{\"key\": 15, \"value\": ");
              if (tIn1 == 999 || tIn2 == 999){
                client.print(Error);
              }else {
                client.print((tIn1+tIn2)/2);
              }
              client.print("},");
              //Средняя влажность на 1 этаже
              client.print("{\"key\": 17, \"value\": ");
              if (hIn1 == 999 || hIn2 == 999){
                client.print(Error);
              }else {
                client.print((hIn1+hIn2)/2);
              }
              client.print("},");
              //Повторно отправляем температуру улицы
              client.print("{\"key\": 19, \"value\": ");
              client.print(tOut);
              client.print("},");
              //Повторно отправляем влажность улицы
              client.print("{\"key\": 20, \"value\": ");
              client.print(hOut);
              client.print("},");
             //=============================================================================================
              //Состояние света 1
              client.print("{\"key\": 21, \"value\": ");
              client.print(digitalRead(iRele1));
              client.print("},");
              //Состояние света 2
              client.print("{\"key\": 22, \"value\": ");
              client.print(digitalRead(iRele2));
              client.print("},");
              //Состояние света 3
              client.print("{\"key\": 23, \"value\": ");
              client.print(digitalRead(iRele3));
              client.print("},");
              //Состояние света 4
              client.print("{\"key\": 24, \"value\": ");
              client.print(digitalRead(iRele4));
              client.print("},");
              //Состояние света 5
              client.print("{\"key\": 25, \"value\": ");
              client.print(digitalRead(iRele5));
              client.print("},");
              //Состояние света 6
              client.print("{\"key\": 26, \"value\": ");
              client.print(digitalRead(iRele6));
              client.print("},");
              //Состояние света 7
              client.print("{\"key\": 27, \"value\": ");
              client.print(digitalRead(iRele7));
              client.print("},");
              //Состояние света 8
              client.print("{\"key\": 28, \"value\": ");
              client.print(digitalRead(iRele8));
              client.print("},");
              //Состояние света 9
              client.print("{\"key\": 29, \"value\": ");
              client.print(digitalRead(iRele9));
              client.print("},");
              //Состояние света 10
              client.print("{\"key\": 30, \"value\": ");
              client.print(digitalRead(iRele10));
              client.print("},");
              //Состояние света 11
              client.print("{\"key\": 31, \"value\": ");
              client.print(digitalRead(iRele11));
              client.print("},");
              //Состояние света 12
              client.print("{\"key\": 32, \"value\": ");
              client.print(digitalRead(iRele12));
              client.print("},");
              //Состояние света 13
              client.print("{\"key\": 33, \"value\": ");
              client.print(digitalRead(iRele13));
              client.print("},");
              
              //Состояние света 14
              client.print("{\"key\": 34, \"value\": ");
              if (analogRead(iRele14) > analogValue){
                client.print("0");
              }else if (analogRead(iRele14) < analogValue){
                client.print("1");
              }
              client.print("},");
              
              //Состояние питания в доме
              client.print("{\"key\": 52, \"value\": ");
              client.print(digitalRead(Power220));
            //=============================================================================================
            client.print("}]");// Скобка ] закрытия отправленных данных
          } 
          else
          // Далее идут данные с Web страницы от нажатия кнопок
          if (readString.indexOf("?btnLighting21") >0) { // периметр дома
            ToggleLights(1);
            // Формируем  начальное HTML
            client.println("HTTP/1.1 200 OK");
            client.println("Access-Control-Allow-Origin: *");
            client.println("Content-Type: application/json;charset=utf-8");
            client.println("Server: Arduino");
            client.println("Connection: close");
            client.println();
            client.print("[{\"key\": 21, \"value\": ");
            client.print(digitalRead(iRele1));
            client.print("}]");
            readString="";
          }
          else
          {
            // Далее код
          }
          //останавливаем web-client
            client.stop();
           delay(100);
           readString="";
//           Serial.println("Stop Ethernet");
         }
      }// конец с ==
    }// конец client.ava
 }
         

}

//Переключение реле света
//RelayNumber - номер реле который нужно переключить
void ToggleLights(int RelayNumber){
  if (RelayNumber == 1){
       digitalWrite(Rele1, !HIGH);
       delay(100);
       digitalWrite(Rele1, !LOW);  
  }
  // ........
  if (RelayNumber == 21){
       digitalWrite(Rele21, !HIGH);
       delay(100);
       digitalWrite(Rele21, !LOW);  
  }

}

 

****************************************************************************

**********************************************************************************

КОД СТРАНИЦЫ HTM

<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>Умный дом</title>
  <script src="j.min.js"></script>
  
</head>
<body topmargin="0" leftmargin="0" rightmargin="0" bottommargin="0" text="#FFFFFF" bgcolor="#1D2228">
<style>
  .table{
    //width: 100%;
    //background: #eeeeee;
    //line-height: 32px;
    //border: 1px solid black;
  }
  .bars { 
    float: left;
    //height: 30px;
    //line-height: 30px;
    //border: 1px solid black;
    //padding-left: 10px;
    //padding-right: 10px;
    //background: #FFFF33;
    //color: #000000;
    }
  .row{
    //width: 100%;
    //clear: both;
  }
</style>
<div align="center">
	<table cellpadding="0" cellspacing="0" width="1024" height="28" bgcolor="#212121" border="1" bordercolor="#808080">
		<!-- MSTableType="nolayout" -->
		<tr>
			<td width="100" height="28">
<img border="0" src="icon.gif" width="101" height="101"></td>
			<td width="924" height="28">
			<table cellpadding="0" cellspacing="0" width="894" height="99">
				<!-- MSTableType="nolayout" -->
				<tr>
					<td width="27" height="27" valign="top">&nbsp;</td>
					<td width="561" height="27" valign="top"><b><font size="4">
					Умный дом</font></b></td>
					<td width="306" height="54" valign="top" rowspan="2"><div id="FailureStatus"><H5>Состояние системы:</H5></div></td>
				</tr>
				<tr>
					<td width="27" height="27" valign="top">&nbsp;</td>
					<td width="561" height="27" valign="top">
			<img src="temperature.png" align="left" width="26" height="29">
			<a>Наружная температура:&nbsp;</a><a id="Home-19" ></a>℃<span lang="en-us"><a>,&nbsp;влажность:&nbsp;</a><a id="Home-20"></a>%
			</td>
				</tr>
				<tr>
					<td width="27" height="24" valign="top">&nbsp;</td>
					<td width="561" height="24" valign="top">
			<img src="temperature.png" align="left" width="26" height="29">
			<a>Средняя температура на 1 этаже:&nbsp;</a><a id="Home-15" ></a>℃<span lang="en-us"><a>,&nbsp;влажность:&nbsp;</a><a id="Home-17"></a>%
			</td>
			<!--<span lang="ru">1 этаж. Средняя температура и влажность: 1</span><span lang="en-us">8</span><span lang="ru">.4 </span>  -->
					<td width="306" height="24" valign="top">
			<a style="text-decoration: none" href="home1.htm">
			<font color="#FFFFFF">Информер температуры</font></a></td>
				</tr>
				<tr>
					<td width="27" height="24" valign="top">&nbsp;</td>
					<td width="561" height="24" valign="top">
			<img src="temperature.png" align="left" width="26" height="29">
			<a>Средняя температура на 2 этаже:&nbsp;</a><a id="Home-16" ></a>℃<span lang="en-us"><a>,&nbsp;влажность:&nbsp;</a><a id="Home-18"></a>%
			</td>				
					<td width="306" height="24" valign="top">
			<a style="text-decoration: none" href="home2.htm">
			<font color="#FFFFFF">Информер температуры улицы</font></a></td>				</tr>
			</table>
			


			</td>
		</tr>
		</table>
</div>
<div align="center">
	<table cellpadding="0" cellspacing="0" width="1024" height="411" border="1" bordercolor="#808080" style="border-left-style: solid; border-left-width: 1px; border-right-style: solid; border-right-width: 1px; border-top-width: 1px; border-bottom-style: solid; border-bottom-width: 1px">
		<!-- MSTableType="layout" -->
		<tr>
			<td width="1024" height="409">
			<p align="left"><b><span lang="en-us">&nbsp;&nbsp;<font size="4">
			</font> </span><font size="4">Управление освещением</font></b></p>
			<table cellpadding="0" cellspacing="0" width="100%" height="435">
				<!-- MSTableType="nolayout" -->
				<tr>
					<td valign="top"><span lang="en">&nbsp;</span></td>
					<td align="center"><a id="indlights21"></a></td>
					<td align="center"><span lang="en">&nbsp;</span></td>
					<td align="center"><a id="indlights22"></a></td>
					<td align="center"><span lang="en">&nbsp;</span></td>
					<td align="center"><a id="indlights23"></a></td></td>
					<td align="center"><span lang="en">&nbsp;</span></td>
					<td align="center"><a id="indlights24"></a></td></td>
					<td align="center"><span lang="en">&nbsp;</span></td>
					<td align="center"><a id="indlights25"></a></td></td>
					<td align="center"><span lang="en">&nbsp;</span></td>
					<td align="center"><a id="indlights26"></a></td></td>
					<td align="center"><span lang="en">&nbsp;</span></td>
					<td align="center"><a id="indlights27"></a></td></td>
					<td align="center" height="95"><span lang="en">&nbsp;</span> <span lang="en">
					&nbsp;</span></td>
				</tr>
				<tr>
					<td></td>
					<td valign="top" align="center">
					<p align="center"><font face="Open Sans" color="#FFFFFF">
					Периметр дома</font></td>
					<td align="center">&nbsp;</td>
					<td valign="top" align="center"><font face="Open Sans" color="#FFFFFF">
					Веранда(люстра)</font></td>
					<td align="center">&nbsp;</td>
					<td align="center"><font face="Open Sans" color="#FFFFFF">
					Веранда (бра)</font></td>
					<td align="center">&nbsp;</td>
					<td align="center"><font face="Open Sans" color="#FFFFFF">
					Свет растений</font></td>
					<td align="center">&nbsp;</td>
					<td align="center"><font face="Open Sans" color="#FFFFFF">
					Свет на воротах</font></td>
					<td align="center">&nbsp;</td>
					<td align="center"><font face="Open Sans" color="#FFFFFF">
					Гирлянда</font></td>
					<td align="center">&nbsp;</td>
					<td align="center"><font face="Open Sans" color="#FFFFFF">
					Лестница</font></td>
					<td align="center" height="10"></td>
				</tr>
				<tr>
					<td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center" height="19">&nbsp;</td>
				</tr>
				<tr>
					<td>&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center" height="50">&nbsp;</td>
				</tr>
				<tr>
					<td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center" height="19">&nbsp;</td>
				</tr>
				<tr>
					<td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center" height="19">&nbsp;</td>
				</tr>
				<tr>
					<td>&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center" height="50">&nbsp;</td>
				</tr>
				<tr>
					<td>&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center" height="38">&nbsp;</td>
				</tr>
				<tr>
					<td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center" height="19">&nbsp;</td>
				</tr>
				<tr>
					<td>&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td></td>
					<td align="center">&nbsp;</td>
					<td align="center"><a id="indlights44"></a></td></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center"><a id="indlights45"></a></td></td>
					<td align="center" height="50">&nbsp;</td>
				</tr>
				<tr>
					<td>&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center"><font face="Open Sans" color="#FFFFFF">
					Периметр дома (<span lang="ru">Активация д.осв.</span>)</font></td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center">&nbsp;</td>
					<td align="center"><font color="FFFFFF" size="3" face="Open Sans">
					Выключить все</font></td>
					<td align="center" height="38">&nbsp;</td>
				</tr>
				<tr>
					<td width="13"><span lang="en">&nbsp;</span></td>
					<td align="center" width="134">&nbsp;</td>
					<td align="center" width="4">&nbsp;</td>
					<td align="center" width="135">&nbsp;</td>
					<td align="center" width="4">&nbsp;</td>
					<td align="center" width="134">&nbsp;</td>
					<td align="center" width="4">&nbsp;</td>
					<td align="center" width="134">&nbsp;</td>
					<td align="center" width="5">&nbsp;</td>
					<td align="center" width="136">&nbsp;</td>
					<td align="center" width="5">&nbsp;</td>
					<td align="center" width="136">&nbsp;</td>
					<td align="center" width="5">&nbsp;</td>
					<td align="center" width="137">&nbsp;</td>
					<td align="center" width="14" height="19">&nbsp;</td>
				</tr>
			</table>
			</td>
		</tr>
	</table>
</div>
<body>
<script>
  $(document).ready(function(){
  		var timeOut; //This variable is responsible for the frequency of data acquisition 
        getMyData(); //запрос данных с сервера arduino
    });

 function getMyData(){ 
    var myUrl = 'http://192.168.0.103/index&'+Date.now(); //var myUrl = 'http://192.168.0.109:80/';
    var myData = $.ajax({
          url: myUrl,              // eg.  http://10.1.1.99:8081/
          dataType : "json",      //We will be requesting data in JSON format
          timeout : 15000,        //this will cancel the request if it has not received a reply within 10 seconds.
          success: function(data){
          	  console.log('Success - you are a legend');
          	  $("#FailureStatus").html("<H5>Состояние системы: Активна</H5>");  //clear any failure messages.
	          $.each(data, function(index, element) { 
	          	//полученные данные [{"key": 1, "value": 0.40},{"key": 2, "value": 26.60},{"key": 3, "value": 26.70},{"key": 4, "value": 71.70},{"key": 5, "value": 17.30},{"key": 6, "value": 17.90}]
	            $('#Home-'+element.key).html("<span>" + element.value + "</span>");
	            	
	            	// ...
	            	
	                // Наличие питания в доме
	                if ((element.key == 52) && element.value == '0'){
	            		$('#Home-52').html("<span>" + "Питания нет" + "</span>");
	            		$('#indlights52').html("<img src='electro0.png'>");
	            	}else if ((element.key == 52) && element.value == '1'){
	            		$('#Home-52').html("<span>" + "Питание в норме" + "</span>");
	            		$('#indlights52').html("<img src='electro1.png'>");
	            	}
	            	// кнопка выкл.все
	            	$('#indlights45').html("<img src='switchOff.png'>");
				});
  	        }
	});
    myData.error(function(xhr, status, errorThrown){
         
      $("#FailureStatus").html("<span><H5>Состояние системы: Нет соединения! </H5></SPAN>"); 
       
      console.log('Failure'); 
      console.log("Error: " + errorThrown); 
      console.log("Состояние системы: " + status);
      console.dir(xhr);
    });

    timeOut = setTimeout('getMyData()', 15000); //отправка запроса ардуине каждую 5 сек.
}

</script>
</body>

</html>

 

vb
Offline
Зарегистрирован: 15.09.2016

Вам еще не хватает камеры наблюдения. Тут есть проект на Raspberry Pi (для расширения ) https://ngin.pro/smart-house/131-kamera-nablyudeniya-dlya-umnogo-doma-na...

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

vb пишет:

Вам еще не хватает камеры наблюдения. Тут есть проект на Raspberry Pi (для расширения ) https://ngin.pro/smart-house/131-kamera-nablyudeniya-dlya-umnogo-doma-na-raspberry-pi-arduino.html

Качество USB камер желает лучшего, картинка говно, а у кого денег не хватает и кому пофиг на качество видео и кому не надо записывать на сервер, то делайте....

Я лучше куплю нормальные IP-камеры.

IP камеры 2MP стоят от 2000 до 5000 на AliExpress

Поворотные IP камеры с HD качеством картинки и с 18-и кратным увеличением стоят от 12000 и ого-го, но они ах*енные.

Настраиваются легко, Можно настроить оповещения(фото) по e-mail, постить на сервер (Например: при движении в определенной области, или по внешнему триггеру, или по закрытии камеры чем либо....)

anshor
anshor аватар
Offline
Зарегистрирован: 21.06.2016

Подскажите библиотеку что бы заменить часы DS 1302 на DS 3231. Все что я находил с часами работают но в данном скетче выдают ошибки, а переделать ума не хватает. Спасибо если кто поможет.

bwn
Offline
Зарегистрирован: 25.08.2014

anshor пишет:

Подскажите библиотеку что бы заменить часы DS 1302 на DS 3231. Все что я находил с часами работают но в данном скетче выдают ошибки, а переделать ума не хватает. Спасибо если кто поможет.

Любая для DS1307. В них нет возможности настройки будильников, но это можно напрямую через Wire (если нужны).

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

Тут нужно не просто библиотеку нужную прицепить, но и в программе прописать:

#include <DS1307.h> //Подключение модуля DS1307
DS1307 rtc(20,21);//(sda 20,scl 21)
Serg1
Offline
Зарегистрирован: 04.12.2015

Наконец то (после 2х недель мучений)прицепил GSM модуль М590.

Для отладки добавил пару строк в п\программе SIM900:

void sms_read() //___Цикл чтения входящих СМС-сообщений___  
{
    if (!Serial2.available()) return;
 
    char currSymb = Serial2.read(); 
////
<strong>Serial.print(currStr);  //печатаем в монитор порта пришедшую строку currStr.</strong> ИЛИ CURRSYMB
 /////
    if ('\r' == currSymb)



И в п\программе Настройка ГСМ у меня вот такие настройки:

 Serial.println("GSM"); 
  Serial2.println("AT+CMGF=1");        //устанавливает текстовый режим смс-сообщения
    delay(50);
 Serial2.println("AT+CSCS=\"GSM\"");   //кодировка  смс-сообщения
    delay(50);
 Serial2.println("AT+CNMI=2,2,0,0,0"); //включает оповещение о новых сообщениях  было ("AT+CNMI=1,2,2,1,0\r")
    delay(500);
    Serial2.println("AT+CLIP=1");         //АОН вкл
   delay(50);
    // Serial2.println("AT+IFC=1,1");       //устанавливает программный контроль потоком передачи данных
    Serial2.println("AT+CPBS=\"SM\"");   //открывает доступ к данным телефонной книги SIM-карты
    delay(100);
   // Serial2.println("AT+CMGD=0,4"); // удаляем все смс, ки  "AT+CMGDA=\"DEL ALL\"\r")
  // delay(1400);
 Serial2.println("AT+CPAS");         
   delay(100);     //AT+CPAS – Возвращает готовность модема. “+CPAS: 0” – готов.
}


В результате программа работает как то странно:

При включении устройства мне на телефон прлетает СМС о протечке. Затем, с задержкой ок 5 сек в сериал выскакивают строки. Строка сначала не полная, затем дублируется полной строкой. И так по каждой команде. НО не все команды пишутся в сериал а только около 2\3.

Если печатать в сериал не строки а символы, то ситуация следующая- символы команд печатаются неспеша-по символу в секунду.

Печатаются правильно. Но тоже не все команды прописывает в сериал, а только первые 2\3.

Так вот. Я не понимаю:

1. Кто (где) ограничивает количество выводимых в сериал символов?

2. Если сначала мне летит смс, а потом идет вывод с сериал команд инициализации модема, то что это за бутафория выводится в сериал?

3. При запросе состояния мне прилетает смс, но в ней только : "HOME=OFFAlarm:ON  IBP:+23.74 V"  так и должно быть?

4. При включении системы у меня 4 тревоги- ворота, протечка, и что то еще. А прилетает СМС только о протечке. Это правильно?

 

anshor
anshor аватар
Offline
Зарегистрирован: 21.06.2016

Спасибо за подсказку. Разобрался похоже у меня комфликт библиотек между датчиком освещенности BH1750 и часами. не скажите можно ли их подружить?

Mizz
Offline
Зарегистрирован: 04.04.2017

Добрый день!

Благодарю за интересную и полезную информацию. Сам вынашиваю те же идеи. Пока до реализации дело не дошло. Любопытно было посмотреть как у вас это было реализовано на практике.

Хочу поделиться информацией касательно улучшения работы GSM модуля на SIM900 на Меге: https://geektimes.ru/post/286150/