Не корректно отрабатывает скетч GSM сигнализации.

restiv
Offline
Зарегистрирован: 03.01.2016

Уважаемые форумчане прошу вас подсказать где у меня ошибка в скетче. собрал схему (см. рисунок). Состоит из ардуино нано, GSM модуля SIM800L, контроллера заряда ТР4056 для литиевой батареи, 2 светодиода: красный и зеленый и датчика Холла. 

 

Скетч загрузил такой:


#include <SoftwareSerial.h>                                      // Библиотека програмной реализации обмена по UART-протоколу
SoftwareSerial SIM800(8, 9);                                     // RX, TX

int flag1=0;                                                     //Переменная 1 для выполнения программы сработки 1
int flag2=0;                                                     //Переменная 2 для выполнения программы взятия и снятия
int flag3=0;                                                     //Переменная 3 для выполнения программы контроля входящего напряжени
int flag4=0;                                                     //Переменная 4 для выполнения программы РЕЛЕ
int flag5=0;                                                     //Переменная 5 для выполнения программы Розетка
int flag6=0;                                                     //Переменная 1 для выполнения программы сработки 2
String n1 = "+7777777777";
String n2 = "+7777777778";
String sms0 = "Pod Ohranoi";
String sms1 = "Srabotka1";
String sms2 = "220 Volt Off";
String sms3 = "220 Volt On";
String sms4 = "Snyto";
String sms5 = "Relay1 ON";
String sms6 = "Relay1 OFF";
String sms7 = "Relay2 ON";
String sms8 = "Relay2 OFF";
String sms9 = "The system works normally.OK";
String sms10 = "Srabotka2";
String msgphone   = "";

uint8_t hours = 0;                                                // Переменная для счёта кол-ва часов
String _response    = "";                                         // Переменная для хранения ответа модуля
//long lastUpdate = millis();                                       // Время последнего обновления
long updatePeriod   = 15000;                                      // Проверять каждые 15 секунд
unsigned long lastUpdate = 0;                                      // Переменная для счёта миллисекунд

String phones = "+7777777777, +77777777778";                     // Белый список телефонов

void setup() { 
 pinMode(2, INPUT);                                               //  геркон или объемник 1
 pinMode(3, INPUT);                                               //  геркон или объемник 2
 pinMode(5, INPUT);                                               //  +5 вольт с делителя напряжения питания (следит за питанием 220 вольт)
 pinMode(6, OUTPUT);                                              //  Сюда подключаем зеленый Диод черз резистор минус к выходу 6 через резистор 560 Ом
 pinMode(7, OUTPUT);                                              //  Сюда подключаем красный Диод черз резистор минус к выходу 7 через резистор 560 Ом
 pinMode(10, OUTPUT);                                             //  Сюда подключаем выход на реле 1 управления сигнализацией
 pinMode(11, OUTPUT);                                             //  Сюда подключаем выход на реле 2  
 digitalWrite(10, HIGH);                                          // Выключаем реле 1 - посылаем высокий сигнал
 digitalWrite(11, HIGH);                                          // Выключаем реле 2 - посылаем высокий сигнал
 lastUpdate = millis();                                             // Запоминаем текущее время
 
  Serial.begin(9600);                                             // Скорость обмена данными с компьютером (это для отладки)
  SIM800.begin(9600);                                             // Скорость обмена данными с модемом
  Serial.println("Start!");

  sendATCommand("AT", true);                                      // Отправили AT для настройки скорости обмена данными
  delay(5000);                                                    // Ждем 5 секунд
  sendATCommand("AT+CMGDA=\"DEL ALL\"", true);                    // Удаляем все SMS, чтобы не забивать память

  // Команды настройки модема при каждом запуске
  _response = sendATCommand("AT+CLIP=1", true);                   // Включаем АОН
  _response = sendATCommand("AT+DDET=1", true);                   // Включаем DTMF
  _response = sendATCommand("AT+CMGF=1;&W", true);                // Включаем текстовый режима SMS (Text mode) и сразу сохраняем значение (AT&W)!
  lastUpdate = millis();                                          // Обнуляем таймер
}

String sendATCommand(String cmd, bool waiting) {
  String _resp = "";                                              // Переменная для хранения результата
  Serial.println(cmd);                                            // Дублируем команду в монитор порта
  SIM800.println(cmd);                                            // Отправляем команду модулю
  if (waiting) {                                                  // Если необходимо дождаться ответа...
    _resp = waitResponse();                                       // ... ждем, когда будет передан ответ
                                                                  // Если Echo Mode выключен (ATE0), то эти 3 строки можно закомментировать
    if (_resp.startsWith(cmd)) {                                  // Убираем из ответа дублирующуюся команду
      _resp = _resp.substring(_resp.indexOf("\r", cmd.length()) + 2);
    }
    Serial.println(_resp);                                        // Дублируем ответ в монитор порта (для отладки)
  }
  return _resp;                                                   // Возвращаем результат. Пусто, если проблема
}

String waitResponse() {                                           // Функция ожидания ответа и возврата полученного результата
  String _resp = "";                                              // Переменная для хранения результата
  long _timeout = millis() + 10000;                               // Переменная для отслеживания таймаута (10 секунд)
  while (!SIM800.available() && millis() < _timeout)  {};         // Ждем ответа 10 секунд, если пришел ответ или наступил таймаут, то...
  if (SIM800.available()) {                                       // Если есть, что считывать...
    _resp = SIM800.readString();                                  // ... считываем и запоминаем
  }
  else {                                                          // Если пришел таймаут, то...
    Serial.println("Timeout...");                                 // ... оповещаем об этом и...
  }
  return _resp;                                                   // ... возвращаем результат. Пусто, если проблема
}

bool hasmsg = false;                                              // Флаг наличия сообщений к удалению


void loop() 
 {
 if(millis() - lastUpdate >= 3600000) 
 {
  lastUpdate = millis();
  hours++;
  }
  if(hours >= 1)                                                    // Меняем время контроля системы на свое,144 часа.кол-во часов .
  {                                                  
    SIM800.println("AT+CMGS=\"" + n1 + "\"");                       // ...и отправляем полученную команду модему
    delay(500);                                                     // Ждем 0,5 секунд
    SIM800.println(sms9+ "\r\n" + ((char)26));                      // текст смс и После текста отправляем перенос строки и Ctrl+Z
    delay(5000);                                                    // Ждем 5 секунд                       
    hours = 0;                                     
    lastUpdate = millis();
  }

      if (lastUpdate + updatePeriod < millis() ) {                  // Пора проверить наличие новых сообщений
    do {
      _response = sendATCommand("AT+CMGL=\"REC UNREAD\",1", true);  // Отправляем запрос чтения непрочитанных сообщений
      if (_response.indexOf("+CMGL: ") > -1) {                      // Если есть хоть одно, получаем его индекс
        int msgIndex = _response.substring(_response.indexOf("+CMGL: ") + 7, _response.indexOf("\"REC UNREAD\"", _response.indexOf("+CMGL: ")) - 1).toInt();
        char i = 0;                                                 // Объявляем счетчик попыток
        do {
          i++;                                                      // Увеличиваем счетчик
          _response = sendATCommand("AT+CMGR=" + (String)msgIndex + ",1", true);  // Пробуем получить текст SMS по индексу
          _response.trim();                                         // Убираем пробелы в начале/конце
          if (_response.endsWith("OK")) {                           // Если ответ заканчивается на "ОК"
            if (!hasmsg) hasmsg = true;                             // Ставим флаг наличия сообщений для удаления
            sendATCommand("AT+CMGR=" + (String)msgIndex, true);     // Делаем сообщение прочитанным
            sendATCommand("\n", true);                              // Перестраховка - вывод новой строки
            parseSMS(_response);                                    // Отправляем текст сообщения на обработку
            break;                                                  // Выход из do{}
          }
          else {                                                    // Если сообщение не заканчивается на OK
            Serial.println ("Error answer");                        // Какая-то ошибка
            sendATCommand("\n", true);                              // Отправляем новую строку и повторяем попытку
          }
        } while (i < 10);
        break;
      }
      else {
        lastUpdate = millis();                                      // Обнуляем таймер
        if (hasmsg) {
          delay(4000);                                              // Ждем 4 секунд
          sendATCommand("AT+CMGDA=\"DEL ALL\"", true);              // Удаляем все сообщения
          hasmsg = false;
        }
        break;
      }
    } while (1);
  }

  if (SIM800.available())   {                                       // Если модем, что-то отправил...
    _response = waitResponse();                                     // Получаем ответ от модема для анализа
    _response.trim();                                               // Убираем лишние пробелы в начале и конце
    Serial.println(_response);                                      // Если нужно выводим в монитор порта
    if (_response.indexOf("+CMTI:")>-1) {                           // Пришло сообщение об отправке SMS
      lastUpdate = millis() -  updatePeriod;                        // Теперь нет необходимости обрабатываеть SMS здесь, достаточно просто
                                                                    // сбросить счетчик автопроверки и в следующем цикле все будет обработано
    }
  }
  if (Serial.available())  {                                        // Ожидаем команды по Serial... (возможность через серийный порт общаться с модемом для отладки)
    SIM800.write(Serial.read());                                    // ...и отправляем полученную команду модему
  };

//Сработка 1

  if (digitalRead(2)==HIGH && flag2==1 && flag1==0) {
        flag1++;
        digitalWrite(6, LOW);                                       // Выключаем зеленый светодиод
        digitalWrite(7, HIGH);                                      // Включаем красный светодиод
        digitalWrite(10, LOW);                                      // Включаем сигнализацию
        
        SIM800.println("AT+CMGS=\"" + n1 + "\"");                   // ...и отправляем полученную команду модему
        delay(500);                                                 // Ждем 0,5 секунд
        SIM800.println(sms1+ "\r\n" + ((char)26));                  // текст смс на номер 1 и После текста отправляем перенос строки и Ctrl+Z
        delay(5000);                                                // Ждем 5 секунд

       // SIM800.println("AT+CMGS=\"" + n2 + "\"");                   // ...и отправляем полученную команду модему
       // delay(500);                                                 // Ждем 0,5 секунд
       // SIM800.println(sms1+ "\r\n" + ((char)26));                  // текст смс на номер 2 и После текста отправляем перенос строки и Ctrl+Z
       // delay(5000);                                                // Ждем 5 секунд
      
}
 //Сработка 2

  if (digitalRead(3)==HIGH && flag2==1 && flag6==0) {
        flag6++;
        digitalWrite(6, LOW);                                       // Выключаем зеленый светодиод
        digitalWrite(7, HIGH);                                       // Включаем красный светодиод
        digitalWrite(10, LOW);                                      // Включаем сигнализацию
        
        SIM800.println("AT+CMGS=\"" + n1 + "\"");                   // ...и отправляем полученную команду модему
        delay(500);                                                 // Ждем 0,5 секунд
        SIM800.println(sms1+ "\r\n" + ((char)26));                  // текст смс на номер 1 и После текста отправляем перенос строки и Ctrl+Z
        delay(5000);                                                // Ждем 5 секунд

       // SIM800.println("AT+CMGS=\"" + n2 + "\"");                   // ...и отправляем полученную команду модему
       // delay(500);                                                 // Ждем 0,5 секунд
       // SIM800.println(sms1+ "\r\n" + ((char)26));                  // текст смс на номер 2 и После текста отправляем перенос строки и Ctrl+Z
       // delay(5000);                                                // Ждем 5 секунд
      
}   
//Контроль питания отсутствие
   
  if (digitalRead(5)==LOW && flag3==0) {
    flag3++;
   
    SIM800.println("AT+CMGS=\"" + n1 + "\"");                       // ...и отправляем полученную команду модему
    delay(500);                                                     // Ждем 0,5 секунд
    SIM800.println(sms2+ "\r\n" + ((char)26));                      // текст смс и После текста отправляем перенос строки и Ctrl+Z
    delay(5000);                                                    // Ждем 5 секунд

   
}

//Контроль питания востановлено
   
  if (digitalRead(5)==HIGH && flag3==1) {
    flag3=0;
    SIM800.println("AT+CMGS=\"" + n1 + "\"");                       // ...и отправляем полученную команду модему
    delay(500);                                                     // Ждем 0,5 секунд
    SIM800.println(sms3+ "\r\n" + ((char)26));                      // текст смс и После текста отправляем перенос строки и Ctrl+Z
    delay(5000);                                                    // Ждем 5 секунд

   
}

}

void parseSMS(String msg) {                                        // Парсим SMS
  String msgheader  = "";
  String msgbody    = "";
  

  msg = msg.substring(msg.indexOf("+CMGR: "));
  msgheader = msg.substring(0, msg.indexOf("\r"));                // Выдергиваем телефон

  msgbody = msg.substring(msgheader.length() + 2);
  msgbody = msgbody.substring(0, msgbody.lastIndexOf("OK"));      // Выдергиваем текст SMS
  msgbody.trim();

  int firstIndex = msgheader.indexOf("\",\"") + 3;
  int secondIndex = msgheader.indexOf("\",\"", firstIndex);
  msgphone = msgheader.substring(firstIndex, secondIndex);

  Serial.println("Phone: " + msgphone);                           // Выводим номер телефона на компьютер в монитор порта
  Serial.println("Message: " + msgbody);                          // Выводим текст SMS  на компьютер в монитор порта

  if (msgphone.length() > 6 && phones.indexOf(msgphone) > -1) {   // Если телефон в белом списке, то...
    setLedState(msgbody, msgphone);                               // ...выполняем команду
  }
  else {
    Serial.println("Unknown phonenumber");
    SIM800.println("AT+CMGS=\"" + n1 + "\"");                     // ...и отправляем полученную команду модему, отправляет 1 номеру Unknown phonenumber, можно добавить, чтоб номер еще отправлял левый
    delay(1000); // Ждем 1 секунд
    SIM800.println(msgphone + " Unknown phonenumber" + "\r\n" + ((char)26));    // текст смс и После текста отправляем перенос строки и Ctrl+Z
    }
}

void setLedState (String result, String phone) {
  bool correct = false;                                          // Для оптимизации кода, переменная корректности команды
  String msgToSend = "";
  String my_ohr = "";                                            // Переменная для хранения ответа охраны
  String my_power = "";                                          // Переменная для хранения ответа питания
  String my_Relay1 = "";                                          // Переменная для хранения ответа Реле
  String my_Relay2 = "";                                         // Переменная для хранения ответа Розетки
  String my_status = "";                                         // Переменная для хранения ответа статуса
  
  //Постановка на охрану
  
  if (result == "On" && digitalRead(6)==LOW && flag1==0 && flag2==0) {
          digitalWrite(6, HIGH);                                 // Включаем зеленый светодиод
          digitalWrite(7, LOW);                                  // выключаем красный светодиод
          flag2++;
          delay(2000);                                           // Ждем 2 секундs
          msgToSend = sms0;                                      // Статус исполнения
      
   correct = true;                                               // Флаг корректности команды
 
}
   //Снятие с охраны
   
  if (result == "Off" && flag2==1) {
    flag1=0;
    flag2=0;
    digitalWrite(6, LOW);                                        // выключаем зеленый светодиод
    digitalWrite(7, LOW);                                        // выключаем красный светодиод
    delay(1000);                                                 // Ждем 1 секунд
    msgToSend = sms4;                                            // Статус исполнения

 correct = true;                                                 // Флаг корректности команды
 
}

//Включение РЕЛЕ 1
   
  if (result == "Relay1 ON" && flag4==0) {
    flag4=1;
    digitalWrite(11, LOW);                                       // включаем РЕЛЕ
    delay(1000);                                                 // Ждем 1 секунд
    msgToSend = sms5;                                            // Статус исполнения

 correct = true;                                                 // Флаг корректности команды
 
}

//Выключение РЕЛЕ 1
   
  if (result == "Relay1 OFF" && flag4==1) {
    flag4=0;
    digitalWrite(11, HIGH);                                      // выключаем РЕЛЕ
    delay(1000);                                                 // Ждем 1 секунд
    msgToSend = sms6;                                            // Статус исполнения

 correct = true;                                                 // Флаг корректности команды
 
}

//Включение Розетки
   
  if (result == "Relay2 ON" && flag5==0) {
    flag5=1;
    digitalWrite(10, LOW);                                     // включаем РЕЛЕ
    delay(1000);                                               // Ждем 1 секунд
    msgToSend = sms7;                                          // Статус исполнения

 correct = true;                                               // Флаг корректности команды
 
}

//Выключение Розетки
   
  if (result == "Relay2 OFF" && flag5==1) {
    flag5=0;
    digitalWrite(10, HIGH);                                    // выключаем РЕЛЕ
    delay(1000);                                               // Ждем 1 секунд
    msgToSend = sms8;                                          // Статус исполнения

 correct = true;                                               // Флаг корректности команды
 
}

//Статус
   
  if (result == "Status") {
    if (flag2==1 && digitalRead(6)==HIGH){
    my_ohr = "Pod Ohranoi";                                                    //Статус на охране
    }
    if (flag2==0 && flag1==0 && digitalRead(6)==LOW && digitalRead(7)==LOW) {
    my_ohr = "Snyto";                                                          //Статус снят с охраны
    }
    if (flag2==1 && flag1==1 && digitalRead(6)==LOW && digitalRead(7)==HIGH) {
    my_ohr = "Srabotka";                                                       // Статус сработки
    }
    if (flag3==0) {
    my_power = "+12Volt Ready";                                                // Статус наличия питания 12 вольт
    }
    if (flag3==1) {
    my_power = "+12Volt Warning";                                              // Статус отсутствия питания 12 вольт
    }
    if (flag4==1 && digitalRead(10)==HIGH) {
    my_Relay1 = "Relay1 ON";                                                     // Статус включеного РЕЛЕ
    }
    if (flag4==0 && digitalRead(10)==LOW) {
    my_Relay1 = "Relay1 OFF";                                                    // Статус отключеного РЕЛЕ
    }
    if (flag5==1 && digitalRead(11)==HIGH) {
    my_Relay2 = "Relay2 ON";                                                     // Статус включеного РЕЛЕ
    }
    if (flag5==0 && digitalRead(11)==LOW) {
    my_Relay2 = "Relay2 OFF";                                                    // Статус отключеного РЕЛЕ
    }
        
   msgToSend = (my_ohr + "\r\n" + my_power + "\r\n" + my_Relay1 + "\r\n" + my_Relay2);               // Статус исполнения

 correct = true;                                                                // Флаг корректности команды
   
}
  
  if (!correct) {
  msgToSend = "Incorrect command: " + result;                                   // Статус исполнения
  }

                                                                                //Тут идет проверка номера, если команды отправляет 1 номер, то все в норме, если 2 или 3 и так далее из белого списка, 
                                                                                //то ответ дублируется 1 номеру + номер того, кто производит запросы
  if (msgphone == "+7777777777"){
  SIM800.println("AT+CMGS=\"" + msgphone + "\"");                               // ...и отправляем полученную команду модему
  delay(500);                                                                   // Ждем 0,5 секунд
  SIM800.println(msgToSend + "\r\n" + ((char)26));                              // текст смс и После текста отправляем перенос строки и Ctrl+Z
  Serial.println("1 uslovie" + msgphone + msgToSend + "\r\n" + ((char)26));
  }

  
  else
  {
  SIM800.println("AT+CMGS=\"" + msgphone + "\"");                              // ...и отправляем полученную команду модему
  delay(500);                                                                  // Ждем 0,5 секунд
  SIM800.println(msgToSend+ "\r\n" + ((char)26));                              // текст смс и После текста отправляем перенос строки и Ctrl+Z
  delay(5000);                                                                 // Ждем 5 секунд
 
  SIM800.println("AT+CMGS=\"" + n1 + "\"");                                    // ...и отправляем полученную команду модему
  delay(500);                                                                  // Ждем 0,5 секунд
  SIM800.println(msgphone + " " + msgToSend + "\r\n" + ((char)26));            // текст смс и После текста отправляем перенос строки и Ctrl+Z
  delay(1000);                                                                 // Ждем 1 секунд
  Serial.println("2 uslovie" + msgphone + msgToSend + "\r\n" + ((char)26));
  }

}

Сразу скажу скетч не я сам писал. Нашел здесь на форуме, но он подошел под мои задачи. Я его малость переделал под свои нужды. И все бы было хорошо, если бы не 2 странных глюка:

1. Не приходит контрольная СМС о статусе системы. Это строки 93-105. Я уже пробовал и час ставить, вообще никак не отрабатывается этот кусок.

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

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

restiv
Offline
Зарегистрирован: 03.01.2016

Не знаю как отредактировать свой пост, но хочу сразу предупредить, чтобы не обращали внимание на пин RST на GSM модуле, на самом деле он не задействован в схеме и не соединен с землей.

mykaida
mykaida аватар
Offline
Зарегистрирован: 12.07.2018

А к СОЗДАТЕЛЮ программы не обращались?

Никто, кроме него не знает всех нюансов ЕГО творения.

restiv
Offline
Зарегистрирован: 03.01.2016

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

restiv
Offline
Зарегистрирован: 03.01.2016

Доработал схему. Установил мосфет P75N02LDG. Привязал его в свободному пину ардуины и раз в сутки перегружаю модуль. Разобрался с глюками в скетче. Может кому пригодится: 

1. Не приходит контрольная СМС о статусе системы. Это строки 93-105. Я уже пробовал и час ставить, вообще никак не отрабатывается этот кусок.

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

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

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

Тестирую дальше.