Arduino Nano+Mqtt+sim800

sma-etu
Offline
Зарегистрирован: 17.06.2020

Добрый день!

По примерам из сети собрал небольшую платку на ардуино нано + сим 800+датчик температуры. 

Брокер cloudmqtt.com, приложение для андройда mqtt dash.

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

Так работает какое то время (минут 20-40), потом просто всё вылетает, в монитор порта начинает лесть всякая ерунда.

Ни кто не сталкивался с подобной ситуацией? в чем может быть проблема?

#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <avr/wdt.h>
 
Adafruit_BME280 bme; // I2C
 
#include <SoftwareSerial.h>
//В папке с Arduino IDE в файле SoftwareSerial.h строку #define _SS_MAX_RX_BUFF 64 заменяем на  #define _SS_MAX_RX_BUFF 255. 
//#include <DallasTemperature.h>      // https://github.com/milesburton/Arduino-Temperature-Control-Library
#define LCD_ADDR 0x27
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(LCD_ADDR, 20, 4);
//  ----------------------------------------- НАЗНАЧАЕМ ВЫВОДЫ для платок до 1.7.6 (c Arduino Pro Mini) ------------------------------ 
 
SoftwareSerial SIM800(7, 8);                // для старых плат начиная с версии RX,TX
String _response = "";
 
#define ONE_WIRE_BUS 4                      // пин датчика DS18B20, https://github.com/PaulStoffregen/OneWire
#define FIRST_P_Pin  8                      // на реле первого положения замка зажигания с 8-го пина ардуино
#define SECOND_P     9                      // на реле зажигания, через транзистор с 9-го пина ардуино
#define STARTER_Pin  12                     // на реле стартера, через транзистор с 12-го пина ардуино
#define Lock_Pin     10                     // реле на кнопку "заблокировать дверь"
#define Unlock_Pin   11                     // реле на кнопку "разаблокировать дверь"
#define LED_Pin      13                     // на светодиод (моргалку) 6-й транзистор
#define BAT_Pin      A0                     // на батарею, через делитель напряжения 39кОм / 11 кОм
#define Feedback_Pin A1                     // на провод от замка зажигания для обратной связи по проводу ON
#define STOP_Pin     A2                     // на концевик педали тормоза для отключения режима прогрева
#define PSO_Pin      A3                     // на прочие датчики через делитель 39 kOhm / 11 kΩ
#define K5           A5                     // на плате не реализован, снимать сигнал с ардуинки
#define IMMO         A4                     // на плате не реализован, снимать сигнал с ардуинк
#define RESET_Pin    5                      // аппаратная перезагрузка модема, по сути не задействован
 
//  -----------------------------Инициализация датчика температуры и давления  BME280 --------------------- 
 
 
 
//=========================================================================================================\\
 
 
 
 
//  ----------------------------------------- НАЗНАЧАЕМ ВЫВОДЫ для платок от 5.3.0  (c Atmega328 на самой плате)--------------------- 
/*
SoftwareSerial SIM800(4, 5);                // для новых плат начиная с 5.3.0 пины RX,TX 
#define ONE_WIRE_BUS A5                     // пин датчика DS18B20, библиотека тут https://github.com/PaulStoffregen/OneWire
#define FIRST_P_Pin  10                     // на реле K1 на плате ПОТРЕБИТЕЛИ
#define SECOND_P     12                     // на реле К3 на плате ЗАЖИГАНИЕ
#define STARTER_Pin  11                     // на реле К2 на плате СТАРТЕР
#define IMMO         9                      // на реле K4 на плате под иммобилайзер
#define K5           8                      // на реле K5  внешнее под различные нужды, програмно не реализован
#define Lock_Pin     6                      // на реле K6 внешнее на кнопку "заблокировать дверь"
#define Unlock_Pin   7                      // на реле K7 внешнее на кнопку "разаблокировать дверь"
#define LED_Pin      13                     // на светодиод на плате
#define STOP_Pin     A0                     // вход IN3 на концевик педали тормоза для отключения режима прогрева
#define PSO_Pin      A1                     // вход IN4  на прочие датчики через делитель 39 kOhm / 11 kΩ
#define PSO_F        A2                     // обратная связь по реле K1, проверка на ключ в замке
#define RESET_Pin    A3                     // аппаратная перезагрузка модема, по сути не задействован
#define BAT_Pin      A7                     // внутри платы соединен с +12, через делитель напряжения 39кОм / 11 кОм
#define Feedback_Pin A6                     // обратная связь по реле K3, проверка на включенное зажигание
*/
 
//OneWire oneWire(ONE_WIRE_BUS); 
//DallasTemperature sensors(&oneWire);
/*  ----------------------------------------- НАСТРОЙКИ MQTT брокера---------------------------------------------------------   */
const char MQTT_user[10] = "doxfdnqm";      // api.cloudmqtt.com > Details > User  
const char MQTT_pass[15] = "41dYbBRh2Hz1";  // api.cloudmqtt.com > Details > Password
const char MQTT_type[15] = "MQIsdp";        // тип протокола НЕ ТРОГАТЬ !
const char MQTT_CID[15] = "SMIRNOV";        // уникальное имя устройства в сети MQTT
String MQTT_SERVER = "tailor.cloudmqtt.com";   // api.cloudmqtt.com > Details > Server  сервер MQTT брокера
String PORT = "10743";                      // api.cloudmqtt.com > Details > Port    порт MQTT брокера НЕ SSL !
/*  ----------------------------------------- ИНДИВИДУАЛЬНЫЕ НАСТРОЙКИ !!!---------------------------------------------------------   */
String call_phone=  "+79210994020";        // телефон входящего вызова  для управления DTMF
String call_phone2= "+79210994020";        // телефон для автосброса могут работать не корректно
String call_phone3= "+79210994020";        // телефон для автосброса 
String call_phone4= "+79210994020";        // телефон для автосброса 
String APN = "internet.mts.ru";             // тчка доступа выхода в интернет вашего сотового оператора
 
/*  ----------------------------------------- ДАЛЕЕ НЕ ТРОГАЕМ ---------------------------------------------------------------   */
 
 
float TempDS[11];                           // массив хранения температуры c рахных датчиков 
                              
float m = 68.01;                            // делитель для перевода АЦП в вольты для резистров 39/11kOm
unsigned long Time1, Time2, Time3=0, Time4 = 0;
int Timer, count, error_CF, error_C, reset_counter;
int interval = 3;                           // интервал тправки данных на сервер после загрузки ардуино
 
 
bool broker = false;                        // статус подклюлючения к брокеру
bool Security = false;                      // состояние охраны после подачи питания
 
void setup() {
  //// Режим сторжевого сброса , таймаут ~8с
//Serial.println("watchdog enabled start");    
//wdt_enable(WDTO_8S);  
//Serial.println("watchdog enabled end");     
 
  
//================BME280==========================\\
unsigned status;
// default settings
  bme.begin(0x76);
 
  // bme.begin();  
//================================================\\
  
 // pinMode(RESET_Pin, OUTPUT);  
  lcd.init();
  lcd.backlight();
  lcd.print("Kontr teplici ");
  delay (1000);
  
 
  pinMode(FIRST_P_Pin, OUTPUT);          
  pinMode(SECOND_P,    OUTPUT);           
  pinMode(STARTER_Pin, OUTPUT);          
  pinMode(Lock_Pin,    OUTPUT);           
  pinMode(Unlock_Pin,  OUTPUT);          
  pinMode(LED_Pin,     OUTPUT);            
  pinMode(IMMO,        OUTPUT);  
  pinMode(K5,          OUTPUT);                
  
  pinMode(3, INPUT_PULLUP);                 //  для плат до 1.7.2 с оптопарами
  pinMode(2, INPUT_PULLUP);                 //  для плат до 1.7.2 с оптопарами
 // pinMode(3, INPUT);                      //  для плат от 5.3.0 с делителем на резистрах
 // pinMode(2, INPUT);                      //  для плат от 5.3.0 с делителем на резистрах
 
  delay(100); 
  Serial.begin(9600);                       //скорость порта
//  Serial.setTimeout(50);
  
  SIM800.begin(9600);                       //скорость связи с модемом
 // SIM800.setTimeout(500);                 // тайм аут ожидания ответа
  
  Serial.println("MQTT |13/11/2018"); 
 
  delay (1000);
  SIM800_reset();
 
   
 // attachInterrupt(0, callback, FALLING);  // включаем прерывание при переходе 1 -> 0 на D2, или 0 -> 1 на ножке оптопары
 // attachInterrupt(1, callback, FALLING);  // включаем прерывание при переходе 1 -> 0 на D3, или 0 -> 1 на ножке оптопары
              }
 
String sendATCommand(String cmd, bool waiting) {
  String _resp = "";                            // Переменная для хранения результата
     Serial.println("sendATCommand_Start");
  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("sendATCommand_End_if");
   // }
  //  Serial.println("sendATCommand_otvet1");
    Serial.println(_resp);                      // Дублируем ответ в монитор порта
   // Serial.println("sendATCommand_otvet2");
  }
  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...");               // ... оповещаем об этом и...
            delay (5000);
            sendATCommand("AT+CFUN=1,1", true); 
            delay (5000);  
            lcd.setCursor(18, 3);
            lcd.print("ER"); 
            delay (5000); 
            interval = 6 ;
  }
  return _resp;                                 // ... возвращаем результат. Пусто, если проблема
}
 
 
 
void loop() 
{
//_response=0;
//_response= SIM800.available();
//Serial.println(_response);
 
if (SIM800.available())  resp_modem();                                    // если что-то пришло от SIM800 в Ардуино отправляем для разбора
if (Serial.available())  resp_serial();                                 // если что-то пришло от Ардуино отправляем в SIM800
if (millis()> Time2 + 60000) {Time2 = millis(); 
    if (Timer > 0 ) Timer-- ;}
                                               
if (millis()> Time1 + 10000) Time1 = millis(), detection();               // выполняем функцию detection () каждые 10 сек 
 
if ((millis()> Time3 + 50000)&&(interval == 0)) Time3 = millis(), sendPingPacket();               // выполняем функцию detection () каждые 50 сек 
 
if (millis()> Time4 + 100000)
           { 
            Time4 = millis();
            delay (5000);
            sendATCommand("AT+CFUN=1,1", true); 
            delay (5000);  
            lcd.setCursor(18, 3);
            lcd.print("ER"); 
            delay (5000); 
            interval = 6 ;
            }
}
 
 
 
 
 
 
 
 
 
 
void detection(){                                                 // условия проверяемые каждые 10 сек  
 
   
    lcd.setCursor(12, 2);
    lcd.print(bme.readTemperature());
    lcd.setCursor(16, 2);  
    lcd.println("*");
     lcd.setCursor(17, 2);    
    lcd.println("C");   
    
     TempDS[0] = bme.readTemperature();           // читаем температуру
     TempDS[1] = Time1;           // читаем температуру
     TempDS[2] = 5;           // читаем температуру
     
      if (interval > 1) 
          {
            lcd.setCursor(0, 3); 
            lcd.print("GPRS CONNECT"); 
            lcd.setCursor(14, 3); 
            lcd.print(interval);
         
            };
 
 
    
    
    if (interval == 2) 
    {
 
   
    ///==============================Настройка контекста и открытие соединения==========================\\\\\\\\\\\\\\\\\\\\
       delay (1000);
    sendATCommand("ATE0", true);               // отключаем возврат команд от модема
    sendATCommand("AT+CLIP=1", true);          // включаем АОН
    sendATCommand("ATS0=0", true);             // вручную поднимать трубку при входящем звонке  
    sendATCommand("AT+CMGF=0", true);          //PDU режим приема и отправки SMS  
    sendATCommand("AT+CMGDA=\"DEL READ\"", true);  
      
    sendATCommand("AT+SAPBR=2,1", true); 
    sendATCommand("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"", true); 
    sendATCommand("AT+SAPBR=3,1, \"APN\",\""+APN+"\"", true); 
    sendATCommand("AT+SAPBR=1,1", true);
 
    
  
    sendATCommand("AT+CIPSTART=\"TCP\",\""+MQTT_SERVER+"\",\""+PORT+"\"", true),lcd.setCursor(0, 3); lcd.print("GPRS CONNECT"); 
    };  
    
    if (interval>0){interval--;};    
                
}  
 
 
 
 
void resp_serial (){     // ---------------- ТРАНСЛИРУЕМ КОМАНДЫ из ПОРТА В МОДЕМ ----------------------------------
     String at = "";   
     while (Serial.available()) at = Serial.readString();
  //int k = 0;
   //while (Serial.available()) k = Serial.read(),at += char(k),delay(1);
     SIM800.println(at), at = "";  
      Serial.println("v modem");  Serial.println(at);  }   
 
 
void  MQTT_FloatPub (const char topic[15], float val, int x) {char st[10]; dtostrf(val,0, x, st), MQTT_PUB (topic, st);}
 
void sendOtvetPacket() {
  // fixed header
  sendATCommand("AT+CIPSEND", true), delay (100);
  //==================ping=========================\\
 // SIM800.write((byte)0xC0); // Ping что бы всегда был коннект  
 // SIM800.write((byte)0x00); // Remaining Length
  //==================send data vmesto ping=======================\\
  
    MQTT_FloatPub ("C5/ds0",      TempDS[0],2);             // посылаю данные раз в 20 секунд, что бы был коннект, вместо Ping
    MQTT_FloatPub ("C5/ds1",      TempDS[1],2);             // посылаю данные раз в 20 секунд, что бы был коннект, вместо Ping
    SIM800.write((byte)0x1A); // Remaining Length
    
  Serial.println("Ping...");
}
 
void sendPingPacket() {
  // fixed header
   Serial.println("Start Ping");
  sendATCommand("AT+CIPSEND", true), delay (100);
  //==================ping=========================\\
 // SIM800.write((byte)0xC0); // Ping что бы всегда был коннект  
 // SIM800.write((byte)0x00); // Remaining Length
  //==================send data vmesto ping=======================\\
  
    MQTT_FloatPub ("C5/ds0",      TempDS[0],2);             // посылаю данные раз в 20 секунд, что бы был коннект, вместо Ping
    MQTT_FloatPub ("C5/ds1",      TempDS[1],2);             // посылаю данные раз в 20 секунд, что бы был коннект, вместо Ping
    SIM800.write((byte)0x1A); // Remaining Length
    Time4 = millis();
  Serial.println("End Ping");
}
 
void MQTT_CONNECT () {
      lcd.setCursor(0, 3); lcd.print("GPRS ON      ");  
      lcd.setCursor(14, 3); lcd.print(" ");
      lcd.setCursor(15, 3); lcd.print(" ");  
      lcd.setCursor(16, 3); lcd.print(" ");      
  sendATCommand("AT+CIPSEND", true), delay (100);
     
  SIM800.write(0x10);                                                              // маркер пакета на установку соединения
  SIM800.write(strlen(MQTT_type)+strlen(MQTT_CID)+strlen(MQTT_user)+strlen(MQTT_pass)+12);
  
  SIM800.write((byte)0);
  SIM800.write(strlen(MQTT_type));
  SIM800.write(MQTT_type);   // тип протокола
  
  SIM800.write(0x03);
  SIM800.write(0xC0);
  SIM800.write((byte)0);
  SIM800.write(0x3C); // Keep Alive LSB (10) - 60 sec
  
  SIM800.write((byte)0), SIM800.write(strlen(MQTT_CID)),  SIM800.write(MQTT_CID);  // MQTT  идентификатор устройстваAT+SAPBR
  SIM800.write((byte)0), SIM800.write(strlen(MQTT_user)), SIM800.write(MQTT_user); // MQTT логин
  SIM800.write((byte)0), SIM800.write(strlen(MQTT_pass)), SIM800.write(MQTT_pass); // MQTT пароль
 
  MQTT_PUB ("sma/status", "ON");                                                     // пакет публикации  
  MQTT_SUB ("sma/comand");                                                          // пакет подписки на присылаемые команды  
 
  SIM800.write(0x1A),  broker = true;    }                                         // маркер завершения пакета
 
void  MQTT_PUB (const char MQTT_topic[15], const char MQTT_messege[15]) {          // пакет на публикацию
 
  SIM800.write(0x30), SIM800.write(strlen(MQTT_topic)+strlen(MQTT_messege)+2);
  SIM800.write((byte)0), SIM800.write(strlen(MQTT_topic)), SIM800.write(MQTT_topic); // топик
  SIM800.write(MQTT_messege);   }                                                  // сообщение
 
void  MQTT_SUB (const char MQTT_topic[15]) {                                       // пакет подписки на топик
  
  SIM800.write(0x82), SIM800.write(strlen(MQTT_topic)+5);                          // сумма пакета 
  SIM800.write((byte)0), SIM800.write(0x01), SIM800.write((byte)0);                // просто так нужно
  SIM800.write(strlen(MQTT_topic)), SIM800.write(MQTT_topic);                      // топик
  SIM800.write((byte)0);  }                          
 
void resp_modem (){     //------------------ АНЛИЗИРУЕМ БУФЕР ВИРТУАЛЬНОГО ПОРТА МОДЕМА------------------------------
     String at = "";
     //while (SIM800.available()) at = SIM800.readString();  // набиваем в переменную at
  int k = 0;
   while (SIM800.available()) k = SIM800.read(),at += char(k),delay(1);           
   Serial.println("1111111111111");
   Serial.println(at);  
// Serial.println (at.indexOf("CONNECT OK"));
 
 Serial.println("9999999999999");
if (at.indexOf("+CLIP:") > -1)  {sendATCommand("AT+CFUN=1,1", true), error_C++,   lcd.setCursor(18, 3); lcd.print(error_C); delay (10000), interval = 1 ;}  // костыль 2
else if (at.indexOf("SMS Ready") > -1 || at.indexOf("NO CARRIER") > -1 ) {sendATCommand("AT+CLIP=1;+DDET=1", true);} // Активируем АОН и декодер DTMF
/*  -------------------------------------- проверяем соеденеиние с ИНТЕРНЕТ, конектимся к серверу------------------------------------------------------- */
//else if (at.indexOf("+SAPBR: 1,3") > -1)                                  {SIM800.println("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\""),     lcd.setCursor(1, 3); lcd.print(at); delay(200);} 
//else if (at.indexOf("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"\r\r\nOK") > -1)    {SIM800.println("AT+SAPBR=3,1, \"APN\",\""+APN+"\""),  lcd.setCursor(1, 3); lcd.print(at); delay (500); }
//else if (at.indexOf("AT+SAPBR=3,1, \"APN\",\""+APN+"\"\r\r\nOK") > -1 )   {SIM800.println("AT+SAPBR=1,1"),  lcd.setCursor(1, 3); lcd.print("GPRS CONNECT"); interval = 2 ;} // устанавливаем соеденение   
//else if (at.indexOf("+SAPBR: 1,1") > -1 )        {delay (200),  SIM800.println("AT+CIPSTART=\"TCP\",\""+MQTT_SERVER+"\",\""+PORT+"\""),  lcd.setCursor(1, 3); lcd.print(at); delay (1000);}
else if (at.indexOf("CONNECT FAIL") > -1 )       {sendATCommand("AT+CFUN=1,1", true), error_CF++, lcd.setCursor(16, 3); lcd.print(error_CF); delay (1000), interval = 3 ;}  // костыль 1
else if (at.indexOf("CLOSED") > -1 )             {sendATCommand("AT+CIPSHUT", true), error_C++,   lcd.setCursor(18, 3); lcd.print(error_C); delay (1000), interval = 1 ;}  // костыль 2
else if (at.indexOf("+CME ERROR:") > -1 )        {Serial.println("interval = 4");error_CF++;  interval = 4;  if (error_CF > 5) {error_CF = 0, sendATCommand("AT+CFUN=1,1", true); }  lcd.setCursor(16, 3); lcd.print(error_CF);}   // костыль 4 
else if (at.indexOf("CONNECT OK") > -1){MQTT_CONNECT(); }
  
  
 
 
else if (at.indexOf("sma/comand1",4) > -1 )      {  
                 sendATCommand("AT+CIPSEND", true), delay (100);
                 MQTT_FloatPub ("sma/security", 1 ,2);             // посылаю данные раз в 20 секунд, что бы был коннект, вместо Ping         
                 SIM800.write((byte)0x1A); // Remaining Length
                 lcd.setCursor(0, 1); lcd.print("POLIV OFF "); 
    }     // команда постановки на охрану и включения прерывания по датчику вибрации     
else if (at.indexOf("sma/comand0",4) > -1 )      { 
                 sendATCommand("AT+CIPSEND", true), delay (100);
                 MQTT_FloatPub ("sma/security", 0,2);             // посылаю данные раз в 20 секунд, что бы был коннект, вместо Ping         
                 SIM800.write((byte)0x1A); // Remaining Length
                 lcd.setCursor(0, 1); lcd.print("POLIV ON "); 
  }                               
                                                  
 
 at = "";
                              
 } 
 
 
void SIM800_reset() {sendATCommand("AT+CFUN=1,1", true);}                        // перезагрузка модема 
 
 
 
 
Сразу говорю что я не программист=) не ругайте сильно=)

 

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukommentarii

максимально не использовать delay

максимально избавиться от вывода какой либо информации в монитор порта при работе с модемом

http://arduino.ru/forum/programmirovanie/snova-mqtt-1#comment-411540

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Вставить код по правилам форума?

sma-etu
Offline
Зарегистрирован: 17.06.2020

Спасибо большое. Завтра попробую сделать

b707
Offline
Зарегистрирован: 26.05.2017

sma-etu пишет:
Завтра попробую сделать

вставить код?

sma-etu
Offline
Зарегистрирован: 17.06.2020

Вообще хотел попробовать убрать задержки и вывод текста=)

Не нашёл как можно отредактировать сообщение (вставить код по правилам)

b707
Offline
Зарегистрирован: 26.05.2017

sma-etu пишет:

Не нашёл как можно отредактировать сообщение (вставить код по правилам)

первое сообщение ветки отредактировать нельзя.

Вставьте код просто новым сообщением

sma-etu
Offline
Зарегистрирован: 17.06.2020

Убрал вывод в монитор и задержки. Не помогло, все равно есть сбои.
Увидел одну особенность. У меня сим800 и ардуино соеденино проводами. (Rx, tx 5v gnd идет от платы с ардуино к сим800. На модули сим800 есть антена. Вот если эта антена попадает на эти провода, то в порт монитора пишутся какие то квадраты. Может из за этого происходила ошибка?

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Только пайка спасёт мир