Arduino Nano+Mqtt+sim800
- Войдите на сайт для отправки комментариев
Ср, 17/06/2020 - 17:52
Добрый день!
По примерам из сети собрал небольшую платку на ардуино нано + сим 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);} // перезагрузка модема
Сразу говорю что я не программист=) не ругайте сильно=)
http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukommentarii
максимально не использовать delay
максимально избавиться от вывода какой либо информации в монитор порта при работе с модемом
http://arduino.ru/forum/programmirovanie/snova-mqtt-1#comment-411540
Вставить код по правилам форума?
Спасибо большое. Завтра попробую сделать
вставить код?
Вообще хотел попробовать убрать задержки и вывод текста=)
Не нашёл как можно отредактировать сообщение (вставить код по правилам)
Не нашёл как можно отредактировать сообщение (вставить код по правилам)
первое сообщение ветки отредактировать нельзя.
Вставьте код просто новым сообщением
Убрал вывод в монитор и задержки. Не помогло, все равно есть сбои.
Увидел одну особенность. У меня сим800 и ардуино соеденино проводами. (Rx, tx 5v gnd идет от платы с ардуино к сим800. На модули сим800 есть антена. Вот если эта антена попадает на эти провода, то в порт монитора пишутся какие то квадраты. Может из за этого происходила ошибка?
Только пайка спасёт мир