SIM800 и MQTT

ser_ega
Offline
Зарегистрирован: 07.04.2022

Всем привет!

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

https://github.com/martinhol221/SIM800L_MQTT

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

Объем буфера менял в файле SoftwareSerial.h результат не меняется... (при том что )  количество символов далеко меньше значения буфера....

перечитал тему http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-nim-svyazano изменил функцию обработки ответов SIM800 заменив STRING на CHAR, но уже сейчас понимаю что не в этом проблема, потому что результат тот же и во-вторых потому что обрезает команды от команды SIM800.println а не ответы.

Теперь заметил на сообщение при компиляции

Скетч использует 17194 байт (53%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 1621 байт динамической памяти.
 
так вот если закоментирую пару строк она становится такой 
 
Скетч использует 17120 байт (53%) памяти устройства. Всего доступно 32256 байт.
Глобальные переменные используют 1585 байт динамической памяти
 
как видно разница в 36 байт динамической памяти и уже все работает.
Подскажите как решить этот вопрос, что я не так делаю ил может незнаю какой то нюанс?
 Использую Arduino Nano на atmege 328 
 
Вот мой код
 
#include "EEPROM.h"          //библиотека для для записи в энергонезависимую память
#include <SoftwareSerial.h>  //библиотека для создания второго программного UART для связи с GSM модулем
#include <OneWire.h>
#include <DallasTemperature.h>

#define MAX_SIZE_RESP_BUF 100

#define ONE_WIRE_BUS 6

// создаем экземпляр класса OneWire, чтобы с его помощью
// общаться с однопроводным устройством
// (т.е. в нашем случае – с температурным датчиком):
OneWire oneWire(ONE_WIRE_BUS);

// передаем объект oneWire объекту sensors:
DallasTemperature sensors(&oneWire);

float temperature = 0; // Глобальная переменная для хранения значение температуры с датчика DS18B20
long lastUpdateTime = 0; // Переменная для хранения времени последнего считывания с датчика
const int TEMP_UPDATE_TIME = 1000; // Определяем периодичность проверок

/*  ----------------------------------------- НАСТРОЙКИ MQTT брокера---------------------------------------------------------   */
const char MQTT_user[10] = "emqx";      // api.cloudmqtt.com > Details > User  
const char MQTT_pass[15] = "public";      // api.cloudmqtt.com > Details > Password
const char MQTT_type[15] = "MQIsdp";        // тип протокола НЕ ТРОГАТЬ !
const char MQTT_CID[15] = "siga";        // уникальное имя устройства в сети MQTT
String MQTT_SERVER = "broker.emqx.io";   // api.cloudmqtt.com > Details > Server  сервер MQTT брокера
String PORT = "1883";                      // api.cloudmqtt.com > Details > Port    порт MQTT брокера НЕ SSL !

SoftwareSerial SIM800(A5, A4); //программные RX, TX для связи с модулем SIM800L
#define key_led   7       //Пин 5 для подключения светодиода для индикации о постановке на охрану
#define led_2     A3       //светодиод для индикации сигнализации
#define a1        9      // D4 линия для подключения датчика ДВИЖЕНИЯ
#define a2        10      //D3 линия А5 для подключения датчика
#define speaker   8       //контакт для подключения сирены
#define set_220   A0       //контакт для определения наличия питания в сети
#define relay     3      //контакт для подключения первого твердотельного реле или релейного модуля
#define relay2    2      //контакт для подключения второго твердотельного реле или релейного модуля

String phon = "+3xxxxxxx"; //1 номер на который будет выполняться звонок если сработает сигнализация
String phones = "+3xxxxxxx"; //1 или несколько номеров через запятую, с которых будет разрешено управления по СМС
String balance = "*111#";//1 номер для проверки баланса Sim карты GSM сигнализации
String SMS_phone = "+3xxxxxxxxxx";//1 номер на который будут приходить SMS отчеты

String APN = "internet";    // тчка доступа выхода в интернет вашего сотового оператора
String USER = "";               // имя выхода в интернет вашего сотового оператора
String PASS = "";               // пароль доступа выхода в интернет вашего сотового оператора
bool   n_send = true;               // отправка данных на народмон по умолчанию включена (true), отключена (false)
bool   sms_report = true;           // отправка SMS отчета по умолчанию овключена (true), отключена (false)
bool   ring_st = true;            
String pin = "";                   // строковая переменная набираемого пинкода 
int interval = 2;                  // интервал отправки данных на народмон сразу после загрузки 
bool SMS_send = false;             // флаг разовой отправки СМС
bool ring = false;                 // флаг момента снятия трубки
int Step_voice = 0;                // Этап голосового меню при вх. звонке
bool Voice_fl=true;                 // Разрешение проигрывание 
bool broker = false;                        // статус подклюлючения к брокеру
bool rel_st = false;
bool rel_st2 = false;

long spiker_time = 5;   //20 секунд время работы сирены, после отключения датчиков
long ring_time   = 20;   //20 секунд пауза между звонками при срабатывании сигнализации
int batery_limit = 95;   //значение заряда батареи в процентах, при котором отправится СМС о разряженной батареи (оптимально от 30% до 60%)
//int ring_x       = 3;    //пауза 3 минуты между сериями звонков, при постоянно сработанном концевике (от 1 до 32000 минут)
bool ring_out = false;  // Состояние исходящего звонка при сигнализации
int ring_kol = 0;       //Порядковый номер вызова при СРАБАТЫВАНИИ
bool Sig_alarm=false;    // СРАБАТЫВАНИЕ охраны
bool send_mes_power=false;  //ФЛАГ откправки сообщение при отключении 220В
String SMS_tema = "";
String bal_st = "";
String st_temp = "";
bool state_power = false;   //Состояние питания 220В
bool sig_st = false;      //Переключатель сигнализации
bool stat_a1 = false, st_a1 = false, stat_a2 = false, st_a2 = false, sensorVal = false;     //Состояние датчиков 

int val, send_mesag_state_Batery = 0, send_mesag_Balanse = 0, led_2_OFF, led_2_ON, readflag = 0;
int  ring_fl2 = 0, blinker = 1;

int k = 0, low_power_kol = 0, t = 0, msgphone = 0, state_Batery = 100;
int error_CF, error_C;

// Переменные для работы с EEPROM
int flag_EEPROM, start_FLAG = 2, address_FLAG = 0,  address_SMS = 2, address_SIG = 4, address_RING = 6, address_REL = 8, address_REL2 = 9;

// Переменные для хранения точек отсчета, для таймеров
unsigned long timing_alarm;                     //Отсчет времени работы сирены;
unsigned long timing_ring;                     //Отсчет времени ИСХОДЯЩЕГО ВЫЗОВА;
unsigned long timing_blink_OFF, timing_blink;   //Отсчет работы БЛИНКОВ
unsigned long timing10, timing11, timing15, timing16, timing17, timing, timer_power, timer_start;

//String _response = "";                                   // Переменная для хранения ответа модуля
long lastUpdate = millis();                              // Время последнего обновления
long updatePeriod = 60000;                               // Проверять каждую минуту

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 MQTT_CONNECT () {
  SIM800.println("AT+CIPSEND"), 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(0xC2),SIM800.write((byte)0),SIM800.write(0x3C); // просто так нужно
  SIM800.write((byte)0), SIM800.write(strlen(MQTT_CID)),  SIM800.write(MQTT_CID);  // MQTT  идентификатор устройства
  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 ("C5/status", "connect");                                            // пакет публикации
  MQTT_SUB ("C5/comand");                                                          // пакет подписки на присылаемые команды
  SIM800.write(0x1A),  broker = true;    }  

void  MQTT_FloatPub (const char topic[15], float val, int x) {char st[10]; dtostrf(val,0, x, st), MQTT_PUB (topic, st);}

void SIM800_reset() {
  SIM800.println("AT+CFUN=1,1");
  delay(2000); 
  
}

void resp_modem () {    //------------------ НАЛИЗИРУЕМ БУФЕР ВИРТУАЛЬНОГО ПОРТА МОДЕМА------------------------------
  char buf[MAX_SIZE_RESP_BUF];
  byte pos_buf;
  bool recievedFlag = false;

   
    while (SIM800.available()) {
      byte readByte = SIM800.read();
      if (readByte > 0) {
        buf[pos_buf] = readByte;
        Serial.print(buf[pos_buf]);
        //Serial.print(readByte);
        ++pos_buf;
        if (pos_buf >= MAX_SIZE_RESP_BUF) pos_buf = 0;
        
      }
      
       if (strstr (buf,"C5/comandrelay1") != NULL )   {delay(50); if (SIM800.read() == 48) rel_st=0; else rel_st=1;  EEPROM.put(address_REL, rel_st); memset(buf, 0, pos_buf);pos_buf = 0;}      //  включение реле
       if (strstr (buf,"C5/comandrelay2") != NULL )   {delay(50); if (SIM800.read() == 48) rel_st2=0; else rel_st2=1;  EEPROM.put(address_REL2, rel_st2); memset(buf, 0, pos_buf);pos_buf = 0;}
//       if (strstr (buf,"C5/comandsms") != NULL )   {delay(50); if (SIM800.read() == 48) sms_report=0; else sms_report=1;  EEPROM.put(address_SMS, sms_report); memset(buf, 0, pos_buf);pos_buf = 0;}
//       if (strstr (buf,"C5/comandring") != NULL )   {delay(50); if (SIM800.read() == 48) ring_st=0; else ring_st=1;  EEPROM.put(address_RING, ring_st); memset(buf, 0, pos_buf);pos_buf = 0;}
//       if (strstr (buf,"C5/comandsig") != NULL )   {delay(50); if (SIM800.read() == 48) sig_st=0; else sig_st=1;  EEPROM.put(address_SIG, sig_st); memset(buf, 0, pos_buf);pos_buf = 0;}
//       if (strstr (buf,"C5/comandbalans") != NULL )   {delay(50);  memset(buf, 0, pos_buf);pos_buf = 0;SIM800.println("AT+CUSD=1,\"*111#\"");}
       
      if (readByte == '\n' && pos_buf > 1 && buf[pos_buf - 2] == '\r') {
          //Serial.println(buf);
          Serial.print(pos_buf);
          //работаю с полученной строкой
      
//  if (recievedFlag)
if (strstr (buf,"ATD") != NULL) {
//  if (strstr (buf,"ATD" + phon + ";") != NULL) {
    timing_ring=millis();
    Serial.println(">>OUT CALL");
  } else if (strstr (buf,"+CLIP:") > -1  && strstr (buf,"+CMGR:") == NULL ) {
    ring = true,SIM800.println("ATA"), delay(500), Step_voice=1; // ВХОДЯЩИЙ ЗВОНОК
    Serial.println("<<IN CALL");

    }  else if (strstr (buf,"+CREC: ") != NULL)        { //Завернено ПРОИГРЫВАНИЕ файла
      Step_voice++;
      Voice_fl=true;
      Serial.print("<<REC");Serial.print(String(Step_voice));
            
  }  else if (strstr (buf,"+DTMF: ") != NULL)        {

    if (pin.indexOf("*") > -1 ) pin = "";
    
  } else if (strstr (buf,"+CUSD:") != NULL)        {//Если пришел ответ о состоянии баланса

      Serial.print("SIM: "); Serial.print(bal_st);Serial.println(" grn.");

  } else if (strstr (buf,"+CBC:") != NULL) {              //Если пришел ответ о состоянии батареи

     Serial.print("BAT = "); Serial.print(String(state_Batery));Serial.println("%");
     SIM800.println("AT+SAPBR=2,1");
  } else if (strstr (buf,"+CMTI: \"SM\",") != NULL) {

  } else if (strstr (buf,"BUSY") != NULL) {    // Отбой  звонка ALARM
      ring_out=false;  
      timing10 = millis();
      ring_kol++;                           //Увеличиваем счетчик т.к. звонок УЛЫШАН и ОТБИТ
    }
    else if (strstr (buf,"SMS Ready")  != NULL || strstr (buf,"NO CARRIER")  != NULL || strstr (buf,"NO ANSWER") != NULL) {      //ЗАВЕРШЕНИЕ ЗВОНКА
         ring_out=false;
         timing10 = millis();
         if (ring_kol==0) 
            {ring = false;
             SIM800.println("AT+CLIP=1;+DDET=1"); // Активируем АОН и декодер DTMF
            }
    /*  -------------------------------------- проверяем соеденеиние с ИНТЕРНЕТ ------------------------------------------------------------------- */
    }
else if (strstr (buf,"+SAPBR: 1,3") != NULL)                          {delay (200), SIM800.println("AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"");} 
else if (strstr (buf,"AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"") != NULL)    {delay (200), SIM800.println("AT+SAPBR=3,1, \"APN\",\"internet\""); }
else if (strstr (buf,"AT+SAPBR=3,1, \"APN\",\"internet\"") != NULL)   {delay (200), SIM800.println("AT+SAPBR=1,1"), interval = 2 ;} // устанавливаем соеденение   
else if (strstr (buf,"+SAPBR: 1,1") != NULL)        {SIM800.print("AT+CIPSTART=\"TCP\",\""), SIM800.print(MQTT_SERVER), SIM800.println("\",\""+PORT+"\"");}
else if (strstr (buf,"CONNECT FAIL") != NULL)       {SIM800.println("AT+CFUN=1,1"), error_CF++, delay (1000), interval = 3 ;}  // костыль 1
else if (strstr (buf,"CLOSED") != NULL)             {SIM800.println("AT+CFUN=1,1"), error_C++,  delay (1000), interval = 3 ;}  // костыль 2
else if (strstr (buf,"+CME ERROR:") != NULL)        {error_CF++; if (error_CF > 5) {error_CF = 0, SIM800.println("AT+CFUN=1,1");}}   // костыль 4 
else if (strstr (buf,"CONNECT OK") != NULL)          {MQTT_CONNECT(); interval = 1 ;}

else if (strstr (buf,"ALR") != NULL)              {SIM800.println("AT+CIPSEND"), delay (200); // если не "влезает" "ALREADY CONNECT"
                                                  MQTT_FloatPub ("C5/ds0",     temperature ,2);
                                                  MQTT_FloatPub ("C5/Ubat",     state_Batery ,0);    
                                                  //MQTT_FloatPub ("C5/ball",  bal_st ,0);
                                                  MQTT_PUB("C5/power", digitalRead(A0) ? "1" : "0");                                             
                                                  MQTT_PUB("C5/relay", rel_st ? "relay11" : "relay10");
                                                  MQTT_PUB("C5/relay2", rel_st2 ? "relay21" : "relay20");
                                                  MQTT_PUB("C5/ring", ring_st ? "ring1" : "ring0");
//  вот эти заветные                 MQTT_PUB("C5/sign",  sig_st ? "sig1" : "sig0");
//      две строки                        MQTT_PUB("C5/sms", sms_report ? "sms1" : "sms0");
                                                  MQTT_PUB("C5/motion", digitalRead(a1) ? "1" : "0");
                                                  MQTT_PUB("C5/door", digitalRead(a2) ? "1" : "0");
                                                  MQTT_FloatPub ("C5/uptime",   millis()/3600000,0); 
                                                  SIM800.write(0x1A);}
                                                  
////else if (at.indexOf("C5/comandbalans",4) > -1 )     {SIM800.println("AT+CUSD=1,\"*111#\""); }     // запрос баланса
////else if (at.indexOf("C5/comandrssi") > -1 )       {SIM800.println("AT+CSQ"); }                  // запрос уровня сигнала
////else if (at.indexOf("C5/comandlocation") > -1 )   {SIM800.println("AT+CIPGSMLOC=1,1"); }        // запрос локации
//else if (strstr (buf,"C5/comandrelay1") != NULL )   {Serial.println(buf[19]); EEPROM.put(address_REL, rel_st);}      //  включение реле
//else if (strstr (buf,"C5/comandrelay2",4) != NULL ) {rel_st2 = at.substring(at.indexOf("")+19, at.indexOf("")+20).toInt(); EEPROM.put(address_REL2, rel_st2);}      //  включение реле
//else if (strstr (buf,"C5/comandsms",4) != NULL )   {sms_report = at.substring(at.indexOf("")+16, at.indexOf("")+17).toInt(); EEPROM.put(address_SMS, sms_report);}      //  включение реле
//else if (strstr (buf,"C5/comandring",4) != NULL )   {ring_st = at.substring(at.indexOf("")+17, at.indexOf("")+18).toInt(); EEPROM.put(address_RING, ring_st);}      //  включение реле
//else if (strstr (buf,"C5/comandsig",4) != NULL )   {sig_st = at.substring(at.indexOf("")+16, at.indexOf("")+17).toInt(); EEPROM.put(address_SIG, sig_st);}      //  включение реле
            
          memset(buf, 0, pos_buf);
          pos_buf = 0;
        }
    }// While SIM800                                                  
  

       if (pin.indexOf("1") > -1 ){ pin= ""; sig_st = 0;Voice("Sig1_OFF_st"); EEPROM.put(address_SIG, sig_st);  
} else if (pin.indexOf("2") > -1 ){ pin= ""; sig_st = 1;Voice("Sig1_ON_st"); EEPROM.put(address_SIG, sig_st);  
} else if (pin.indexOf("4") > -1 ){ pin= ""; rel_st = 0;Voice("Rel1_OFF_st"); EEPROM.put(address_REL, rel_st);    
} else if (pin.indexOf("5") > -1 ){ pin= ""; rel_st = 1;Voice("Rel1_ON_st"); EEPROM.put(address_REL, rel_st);    
} else if (pin.indexOf("7") > -1 ){ pin= ""; rel_st2 = 0; Voice("Rel2_OFF_st");EEPROM.put(address_REL2, rel_st2);    
} else if (pin.indexOf("8") > -1 ){ pin= "";  rel_st2 = 1; Voice("Rel2_ON_st");EEPROM.put(address_REL2, rel_st2);    
} else if (pin.indexOf("0") > -1 ){ pin= ""; delay(1500);SIM800.println("ATH0"); delay(200); ring=false; SMS_send = true; SMS_tema = "<< STATUS SYSTEM >>";}

digitalWrite(relay, rel_st);
digitalWrite(relay2, rel_st2);

              
  recievedFlag = false;  
}

void Voice(String Track) {
  SIM800.print("AT+CREC=4,\"C:\\User\\"), SIM800.print(Track), SIM800.println(".amr\",0,95");
  //SIM800.println("AT+CREC=4,\"C:\\User\\Sig1_ON_st.amr\",0,100");
}


void setup() {  //>>>>>>>>>>>>>>>>> SETUP <<<<<<<<<<<<<<<<<<<

  //набор функций для записи настроек в энергонезависимую память при первом запуске
  EEPROM.get(address_FLAG, flag_EEPROM);
  if (flag_EEPROM < start_FLAG) {
    EEPROM.put(address_FLAG, start_FLAG);
    EEPROM.put(address_SMS, sms_report);
    EEPROM.put(address_SIG, sig_st);
    EEPROM.put(address_RING, ring_st);
    EEPROM.put(address_REL, rel_st);
    EEPROM.put(address_REL2, rel_st2);
  }
  EEPROM.get(address_SMS, sms_report);
  EEPROM.get(address_SIG, sig_st);
  EEPROM.get(address_RING, ring_st);
  EEPROM.get(address_REL, rel_st);
  EEPROM.get(address_REL2, rel_st2);

  Serial.begin(115200);                           // Скорость обмена данными с компьютером
  SIM800.begin(9600);                           // Скорость обмена данными с модемом


  sensors.begin(); //Измерение температуры

  SIM800.println("AT");  

  SIM800_reset();
 lastUpdate = millis();                        // Обнуляем таймер

  pinMode(set_220, INPUT);
  pinMode(a1, INPUT);
  pinMode(a2, INPUT_PULLUP);
  //pinMode(speaker, OUTPUT);
  pinMode(led_2, OUTPUT);
  pinMode(relay, OUTPUT); digitalWrite(relay, rel_st);
  pinMode(relay2, OUTPUT); digitalWrite(relay2, rel_st2);
  pinMode(key_led, OUTPUT); digitalWrite(key_led, LOW);
  timer_start = millis();
}

void detection(){                                                 // условия проверяемые каждые 10 сек 
  
     //Измерение температуры
  sensors.requestTemperatures();

    // Формируем значение
    temperature = sensors.getTempCByIndex(0);
    st_temp = "Temp: " + String(temperature) + " C";

  if (SMS_send == true && sms_report == true) {
    SMS_send = false;          // если фаг SMS_send равен 1 высылаем отчет по СМС
    SIM800.println("AT+CMGS=\"" + SMS_phone + "\""); delay(100);
    SIM800.println(SMS_tema);// delay(300);
    SIM800.print("Power: "), SIM800.println(state_power ? "GOOD" : "BAD"); //delay(300);
//    SIM800.println("Battery: " + String(state_Batery) + "%"); delay(300);
    //SIM800.print("Temp: ");SIM800.print(String(temperature));SIM800.println(" C"); delay(300);
//    SIM800.println("Balance: " + bal_st+" grn."); delay(300);
    //SIM800.println(signaling); //delay(300);
//    SIM800.print("MOTION: "), SIM800.println(st_a1 ? "ALARM" : "GOOD"); //delay(300);
//    SIM800.println(st_a2 ? "*DOOR: ALARM" : "DOOR: GOOD"); delay(300);
//    SIM800.println("Alarm ring: " + String(ring_st)); //delay(300);
//    SIM800.println("SMS report: " + String(sms_report)); //delay(300);
    SIM800.println("REL1: " + String(rel_st)); //delay(300);
    SIM800.println("REL2: " + String(rel_st2));//delay(300);
    //SIM800.println("Low power: " + String(low_power_kol));
    SIM800.print("\n Uptime: "),     SIM800.print(millis() / 3600000),        SIM800.print("H.");
    //SIM800.print("\n https://www.google.com/maps/place/"), SIM800.print(LAT), SIM800.print(","), SIM800.print(LNG);
    SIM800.print((char)26);
  }
  
  if (n_send == true) interval--;
  if (interval <1) interval = 6, SIM800.println("AT+CBC"),delay (200);    // подключаемся к GPRS

Serial.println(interval);


  //МОНИТОРИНГ ПИТАНИЯ
sensorVal = digitalRead(set_220);   // для получения состояния сети 220
if (sensorVal == HIGH && state_power == false)
    {
     state_power = true;
     timer_power = millis();
     //Serial.println("PITANIE 220V - GOOD!");
    }


  //****  МОНИТОРИНГ ПИТАНИЯ

}

void loop() { //>>>>>>>>>>>>>>>>>> LOOP <<<<<<<<<<<<<<<<<<

  if (ring == true) {  // Голосовые сообщение при ВХОДЯЩЕМ ЗВОНКЕ
    delay(500);
  Serial.println("VOICE");
  if (Step_voice==1 && Voice_fl==true)
  {
   Voice_fl=false;
   if (sig_st) { Voice("Sig1_ON_st"); 
      } else {Voice("Sig1_OFF_st");}
  }
  if (Step_voice==2 && Voice_fl==true)
  {         
   Voice_fl=false;
      if (rel_st == 1) {Voice("Rel1_ON_st");
      }
      else {Voice("Rel1_OFF_st"); }
  }
  if (Step_voice==3 && Voice_fl==true)
  {
   Voice_fl=false;
      if (rel_st2 == 1) {Voice("Rel2_ON_st");
      } else {Voice("Rel2_OFF_st");}
  }    

  if (Step_voice==4 && Voice_fl==true)  Voice_fl=false, Voice("sms_otch");

    }

if (SIM800.available())  resp_modem();                            // если что-то пришло от SIM800 в Ардуино отправляем для разбора
if (Serial.available())  resp_serial();                           // если что-то пришло от Ардуино отправляем в SIM800
if (ring == false && ring_out ==false)
    if (millis()> timer_start + 10000)
       {                                // ***выполняем функцию detection () каждые 10 сек если нет ЗВОНКА
        timer_start = millis(); 
        detection();
       }       // ***выполняем функцию detection () каждые 10 сек 

    //опрос датчиков
    stat_a1 = digitalRead(a1);
    stat_a2 = digitalRead(a2);
    
    if (stat_a1 == LOW && Sig_alarm == false) {
      st_a1 = false;
      //Serial.println("CLOSED");
      digitalWrite(key_led, LOW);
    }
    if (stat_a1 == HIGH) {
      st_a1 = true;
      //Serial.println("OPEN");
      digitalWrite(key_led, HIGH);
    }

    
    if (stat_a2 == LOW && Sig_alarm == false) {
      st_a2 = false;
    }
    if (stat_a2 == HIGH) {
      st_a2 = true;
    }

    if (stat_a1 == LOW && stat_a2 == LOW)
    {
      blinker = 1;
      
      if (millis() - timing_alarm > spiker_time * 1000)
      {
        //analogWrite(speaker, 0);
        noTone(speaker);
      }
      
    } else {
      blinker = 0;
    }

    if ((stat_a1 == HIGH || stat_a2 == HIGH)&& Sig_alarm == false) //ЕСЛИ СРАБОТАЛ ДАТЧИК
    {
      led_2_ON = 200; led_2_OFF = 100;       //Частое мигание светодиода
      Sig_alarm=true;                        //Флаг срабатывания сирены
      timing_alarm = millis();               //Запуск таймера
      
      if (sig_st)
      { 
        tone(speaker, 1500);
        //analogWrite(speaker, 250);
      }
    }

    //*** опрос датчиков

  //блинк для индикации сигнализации
  if (sig_st && blinker) {
    led_2_ON = 1000;
    led_2_OFF = 1000;
  }
  if (sig_st && blinker) {
    led_2_ON = 3000;
    led_2_OFF = 1000;
 }

  if (millis() - timing_blink > led_2_ON){ timing_blink = millis(); timing_blink_OFF = millis(); digitalWrite(led_2, HIGH); }
  if (millis() - timing_blink_OFF > led_2_OFF) { digitalWrite(led_2, LOW); }
  //*** блинк для индикации сигнализации


  if (!sig_st)      //Сигнализация выключена
  {
    digitalWrite(key_led, LOW);
    //send_mesag = 0; 
    ring_kol = 0; ring_out = false;
    Sig_alarm = false;
    //signaling = "Signal: OFF";
    //analogWrite(speaker, 0);
    //tone(speaker, 0);
  }                     //****  Сигнализация выключена

    if (sig_st)                  //Сигнализация включена
    {
    if (ring == false)
    if (ring_out == false)
        {
              
          if (Sig_alarm == true && ring_kol ==0)
          {
           Serial.println("ALARM!");
           Serial.print("IN1="+String(stat_a1));Serial.println(" - IN2="+String(stat_a2));
           if (ring_st == 1)       // ДОЗВОН разрешен и это первый звонок
            {
              ring_kol ++;
              SMS_send=true;  // ОТПРАВКА СМС ПРИ ВЗЛОМЕ
              SMS_tema = "<< ALARM >>";
              Serial.println("<< Ring " + String(ring_kol) + " >>");
              SIM800.print("ATD");SIM800.print(phon);SIM800.println(";");
              ring_out=true; timing_ring=millis();
              //delay(10000);
            } 
          }
         
        }
   //signaling = "Signal: ON"; 
    }

  // звонки при срабатывании датчиков
  if (ring_kol > 0                                  //Если начался отсчет ЗВОНКОВ 
      && millis() - timing10 > ring_time * 1000     // ПАУЗА между звонками БОЛЬШЕ ring_time
      && ring_st == 1                               // ДОЗВОН разрешен
      && ring_out == false)                         // Предыдущий ЗВОНОК завершен.
      {                           
    Serial.println("<< Ring " + String(ring_kol) + " >>");
    ring_out=true;timing_ring=millis();
    SIM800.print("ATD");SIM800.print(phon);SIM800.println(";");
    delay(200);
    //delay(5000);
  }

  // Прекращаем звонить
  if (ring_kol > 3) {
    //Serial.println(">>STOP CALL");
    ring_kol = 0;
    //send_mesag = 0;
    ring_out = false;
    Sig_alarm = false;
  }
//--------------------------------------------------------------------------------------

}

 
brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

Скорее всего не хватает оперативной памяти. Библиотеки MQTT жрут очень много памяти.

Для начала попробуйте все стринги грузить из флеша - используйте макрос F().

Например SIM800.println("AT+CFUN=1,1"); замените на SIM800.println(F("AT+CFUN=1,1"));

Такой же прием используйте для функций strstr, замените их на strstr_p - почитайте что ни-будь об этом. 

Например: if (strstr (buf,"ATD") != NULL) { замените на if (strstr_p (buf,F("ATD")) != NULL) {

Без всего этого вы не справитесь, либо берите процессор с бОльшим объемом памяти (ОЗУ). 

 

ser_ega
Offline
Зарегистрирован: 07.04.2022

brokly пишет:

Скорее всего не хватает оперативной памяти. Библиотеки MQTT жрут очень много памяти.

Для начала попробуйте все стринги грузить из флеша - используйте макрос F().

Да уж действительно, получилось освободить несколько байт, но это это временно, и в какой то момент написания снова будет тоже...

Спасибо, за столь оперативный и конструктивный ответ.

Может направите на статейку?

brokly
brokly аватар
Offline
Зарегистрирован: 08.02.2014

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

У AVR очень много функций имеют прогмемные аналоги обычно они называются так же оно имеют в конце _p, эти функции позволяют использовать строковые переменные из программной памяти, освобождая ОЗУ, которого вам не хватает, потому что библиотека MQTT выделяет себе буфера, по меркам микропроцессоров, огромного размера. Уберите все строковые переменные в программную память. Или используйте мегу. Можете поковырять библиотеку MQTT, перенастроить ее на более короткие буфера, но мне кажется не разберетесь....

К сожалению не все описано в книжках, многое, например про MQTT - в стандартах, их тоже нужно изучать. Невозможно все рассказать в формате "совета". Основной посыл выделил жирным.

ser_ega
Offline
Зарегистрирован: 07.04.2022

Спасибо попробую...

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Перетащить все на Мегу, и памяти больше и аппаратный UART есть.

Я делал на Меге с шилдом на SIM800 устройство (прототип) с подключением к домашнему MQTT брокеру. Работает стабильно где нормально GPRS работает. Сейчас на даче стоит, нормально работает пока зима и мало народу вокруг. Есть пререподключения, но все время на связи, данные поступают. У меня использовались <TinyGsmClient.h> и <PubSubClient.h>

Я в свое время от GPRS отказался на даче, летом, в выходные, было даже IP адрес не получить, хотя сигнал нормальный был.
А с LTE сразу ситуация исправилась, и проблемы со связью пропали.
Сейчас конечно сократилось кол-во GPRS устройств, все смартфоны уже 3G LTE, но как говорят "осадочек остался". 

 

ser_ega
Offline
Зарегистрирован: 07.04.2022

вообщем все что хотел видеть в логике своего девайса сделал, спасибо вашей подсказке освободил половину ОЗУ, но один момент не работает... а именно, на MQTT не все топики передаются, а только первые 5 шт., вот даже не обращал раньше на это внимания

SIM800.println(F("AT+CIPSEND"));delay(100);
MQTT_FloatPub ("LA/T",     temperature ,1);
MQTT_FloatPub ("LA/U",     state_Batery ,0);   
MQTT_PUB("LA/P", digitalRead(A0) ? "1" : "0");                                             
MQTT_PUB("LA/r1", rel_st ? "r11" : "r10");
MQTT_PUB("LA/r2", rel_st2 ? "r21" : "r20");
MQTT_PUB("LA/ring", ring_st ? "ring1" : "ring0");
MQTT_PUB("LA/sign",  sig_st ? "sig1" : "sig0");
MQTT_PUB("LA/sms", sms_report ? "sms1" : "sms0");
MQTT_PUB("LA/mot", digitalRead(a1) ? "1" : "0");
MQTT_PUB("LA/dr", digitalRead(a2) ? "1" : "0");
MQTT_FloatPub ("LA/upt",   millis()/3600000,0); 
SIM800.write(0x1A);

 

ser_ega
Offline
Зарегистрирован: 07.04.2022

brokly пишет:

Уберите все строковые переменные в программную память

Если комментирую первые 5, приходят следующие 5. Или это та же тема с ОЗУ

SergeiL
SergeiL аватар
Offline
Зарегистрирован: 05.11.2018

Передавайте за два раза, между ними пауза на отправку.

ser_ega
Offline
Зарегистрирован: 07.04.2022

SergeiL пишет:

Передавайте за два раза, между ними пауза на отправку.

Была мысль, но в чем причина? Arduino или сам сервер?

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

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