После отправки 0xC0 0x00 0x1A из порта модема получаю 0xFF 0xC0 0x00 0x1A. Т.е. на сколько я понимаю наружу ничего не уходит.
Что значит из "порта модема получаю" - это откуда?
Сложно судить, вы бы скетч весь выложили, посмотрим. А ещё проще - тупо для испытания - напишите простенький скетч с последовательностью АТ команд что выше было - они то гарантированно наружу шлют данные. И будет понятно где косяк.
И вы так и не выложили что отвечает модем и лог брокера.
Update : я так понимаю вам модем в ответ дублирует посланную команду - отключите нафиг чтоб не мешало разбираться.
По поводу пинга - каждый коннект к брокер сотовый оператор считает за новое подключение, соответственно если у вас лимитный интернет и коннктится каждые N секунд - трафик весь быстро закончится. Пинг пакеты на то и придуманы в mqtt чтоб коннктится раз например в сутки, и постоянно проверять связь через M секунд.
с чего вы взяли что ответ от брокера стабильно через 100 миллисекунд придёт, а например не через секунду.
Делэй поставил уже от безисходности, кстати ставил setTimeout на порт 10000 - эффект нет.. И вообще модем должен что то внятное пинуть в порт после отправки пакета, я его жду. При отправке паблиша или подписки сразу получаю "SEND OK, а тут нифига. Видимо я всё же как то не правильно формирую пакет.
Вижу два варианта :
1 сменить брокера - возможно он что то шлёт не так
2 взять наконец то нормальный пример с последовательность АТ команд и делать по аналогии
ЗЫ. Чудес не бывает.
Update :
3. Пересмотреть всю логику работы с модемом - переходить на конечные автоматы или их подобие, т е каждая отправлена команда подразумевает ожидание некоего ответа и или какие то действия и в зависимости от условия - переходить на другие действия.
нет команд настройки режима обмена CIPQSEND CIPMODE
нет команды закрытия сессии CIPSHUT
рекомендую все таки сообщать модему сколько будет отправлено байт в команде CIPSEND, а не слать в конце байт 26, это во первых надежнее, во вторых если у вас в передаче будет этот байт - все сломается
Вобщем опять работает, отвечает как положено 0xD0 0x00. От чего завист и какого чёрта надо серверу - закономерности без бутылки не нашёл. Просто раз несколько переконнектился и заработало.
А че их искать - cipshut добавили? Похоже что нет, естественно он будет несколько раз пытаться запустить новую сессию не закрыв старую, в итоге по таймауту все сбрасывается и опять работает.
ЗЫ. Вот поэтому у нас и ракеты падают и заказчики скетч не могут запустить и т.д. - потому что разработчик сказал "и так сойдёт, ведь законнектилось в итоге" (
Тьфу...блин, разбирайтесь сами, я в теме, у меня мой код по вышеперечисленным книжкам работает исправно, а вы вместо того чтоб прислушаться и хоть чуть попытаться изменить свой скетч только и делайте что троллите.
закончил небольшой проект, работа SIM800L + MQTT подключение к двум брокерам через два сокета, список команд модема ниже, вдруг кому пригодится.
- инициализация
AT
OK
AT+CIPSHUT
SHUT OK
AT+DDET=0
OK
ATE0
OK
AT+CLIP=0
OK
ATS0=0
OK
ATV1
OK
AT+CMEE=2
OK
AT+CMGF=1
OK
AT+CSCLK=0
OK
AT+CIPMODE=0
OK
AT+CIPMUX=1
OK
AT+CIPHEAD=0
OK
AT+CIPSRIP=0
OK
AT+CSTT="internet"
OK
AT+CIICR
OK
AT+CIPSTATUS
OK
STATE: IP GPRSACT
AT+CIFSR
t▒b▒IRU*R▒('LK▒▒,",▒9%J▒▒
C: 2,,"","","","INITIAL"
C: 3,,"","","","INITIAL"
C: 4,,"","","","INITIAL"
C: 5,,"","","","INITIAL"
100.70.64.195
OK
STATE: IP STATUS
Ready
- подключение к брокерам CIPSTART=X, закрытие сокета для его потом повторного подключения CIPCLOSE=X, или переподключение между брокерами для работы в попеременном режиме
Последовательность команд SIM800L работы с MQTT брокером, устройство работает 24/7, в случае проблем переподключается между серверами.
// начало работы
Start!
// начало модуля первоначальной настройкой модема
// ждем ответ на команды в течении 5 секунд, в случае отсутствия - перезагрузка модема
ATZ // сбросим настройки модема в default
OK
ATE0 // отключение ЭХО, т е модем в обратку не дублирует команды
OK
ATV1 // развернуты подробный ответ от модема
OK
AT+CMEE=2 // вывод подробных описаний ошибок
OK
AT+CIPSHUT // закрыть все интернет сессии
SHUT OK // этот ответ лучше ждать подольше, до 10 секунд
AT+CLIP=0 // отключение АОН
OK
ATS0=0 // модем не берет трубку при входящем звонке
OK
AT+CMGF=1 // обычный режим вывода SMS
OK
AT+CSCLK=0 // отключение работы энергосберегающего режима через пин DTR
OK
AT+CIPHEAD=0 // не добавлять заголовок при приеме данных
OK
AT+CIPRXGET=0 // автоматический вывод принятых данных
OK
AT+CIPSRIP=0 // не показывать данные отправителя при приеме данных
OK
AT+CSPN? // получить имя оператора из SIM карты
+CSPN: "M2M Express",0 // парсим ответ, в зависимости от того, чья карта стоит, будем использовать разные APN
OK
// инициализация основная закончилась
// переходим в режим регистрации модема у оператора
AT+CREG? // каждые 5 секунд запрашиваем статус
+CREG: 0,2
OK
SMS Ready
// ответ ждем в течении 2х минут, если за это время не зарегестрировались - перезагрузка модема
AT+CREG?
+CREG: 0,3
OK
AT+CREG?
+CREG: 0,3
OK
AT+CREG?
+CREG: 0,3
OK
AT+CREG?
+CREG: 0,0
OK
AT+CREG?
+CREG: 0,0
OK
AT+CREG?
+CREG: 0,0
OK
AT+CREG?
+CREG: 0,5 // успешно зарегестрировались
OK
AT+COPS? // запрашиваем имя оператора
+COPS: 1,0,"MegaFon" // парсим ответ - заносим имя оператора в переменную - потом отдадим на сервер для статистики
OK
AT+CSQ? // запрашиваем уровень связи
+CSQ: 12,0 // парсим ответ, потом отдадим серверу для статистики
OK
AT+CIPMODE=0 // командный режим передачи данных
OK
AT+CMGDA="DEL ALL" // удаление всех SMS на SIM карте
OK
// закончилась полная инициализация модема
// начало модуля соединения с mqtt сервером
// ответы на команды, просто отвечающие ОК, без глобальных изменений так же ждем 5 секунд, в случе отсутствия - проблема - перезагружаем модем
AT+CIPSTATUS // запрашиваем статус сессии
OK
STATE: IP INITIAL
AT + CSTT = "internet.emt.ee" // прописываем APN в зависимости от установленной SIM карты
OK
AT+CIPSTATUS // запрашиваем статус
OK
STATE: IP START
AT+CIICR // активируем контекст, по даташиту команда выполняется до 62 секунд, оптимально 35 секунд ждать ответ
OK
AT+CIPSTATUS // запрашиваем статус
OK
STATE: IP GPRSACT
AT+CIFSR // получаем адрес
0.137.119.101
OK
STATE: IP STATUS
AT+CIPSTART="TCP","m23.cloudmqtt.com",***** // коннектимся к серверу
OK
AT+CIPSTATUS // запрашиваем статус
OK
STATE: TCP CONNECTING
AT+CIPSTATUS
OK
STATE: TCP CONNECTING
//
// в течении 10 секунд ждем подключения к серверу, иначе или меняем сервер на резервный или опять поднимаем заново интернет сессию
// общее время ожидания к mqtt серверу ждем в течении 2 минут, иначе перезагрузка модема
//
AT+CIPSTATUS
OK
STATE: TCP CONNECTING
AT+CIPSTATUS
OK
STATE: TCP CONNECTING
AT+CIPSTATUS
CONNECT OK
OK
STATE: CONNECT OK // успешное подключение
// начинаем работать с брокером
AT+CIPSEND
>x10 3x0 x4 MQTTx4 xC0 x0 xFD x0 xF Qw37Tu89u78-91px0 x8 ****** xC ******* // connect packet
SEND OK
AT+CIPSEND
>x82 x1C x0 xA x0 x17 smd/Qw37Tu89u78-91p/cmdx1 x2 x1 // подписываемся на нужные топики
SEND OK
AT+CIPSEND
>05x0 xB log/connectx0 x0 Qw37Tu89u78-91p - connected;MegaFon;12 // отправляем на сервер данные о подключении
23
0
x90 x3
x1
SEND OK // после каждой отправки ждем данное подтверждение в течении 8 секунд, в случае отсутствия - переподключаемся к серверу
AT+CIPSEND // каждае 240 секунд (время удержания соединения, меньшее, чем указано в connect packet)
>xC0 x0 // шлем PING REQ , потом ждем 14 секунд PING RESP
SEND OK
xD0 /*пришел PING RESP, если не дождались - реконнект к серверу*/ AT+CIPSEND
>xC0 x0
SEND OK
xD0 AT+CIPSTATUS
OK
STATE: CONNECT OK
AT+CIPCLOSE // принудительно разорвали связь или увидели ответ CLOSED
CLOSE OK
AT+CIPSTATUS // запускаем заново модуль соединения к серверу
OK
STATE: TCP CLOSED // который в зависимости от статуса
AT+CIPSHUT // согласно даташита шлет нужную команду
SHUT OK
AT+CIPSTATUS
OK
STATE: IP INITIAL
AT + CSTT = "internet.emt.ee"
OK
AT+CIPSTATUS
OK
STATE: IP START
AT+CIICR
OK
AT+CIPSTATUS
OK
STATE: IP GPRSACT
AT+CIFSR
0.137.201.64S
OK
STATE: IP STATUS
AT+CIPSTART="TCP","m20.cloudmqtt.com",***** // коннектимся к резервному серверу
OK
AT+CIPSTATUS
OK
STATE: TCP CONNECTING
// .......... ждем коннекта
AT+CIPSTATUS
OK
STATE: TCP CONNECTING
AT+CIPSTATUS
CONNECT OK
OK
STATE: CONNECT OK
AT+CIPSEND
>x10 3x0 x4 MQTTx4 xC0 x0 xFD x0 xF Qw37Tu89u78-91px0 x8 ****** xC *******
SEND OK
AT+CIPSEND
>x82 x1C x0 xA x0 x17 smd/Qw37Tu89u78-91p/cmdx1 x2
SEND OK
AT+CIPSEND
>x82 xC x0 xA x0 x7 log/srvx1 x90 x3
x1
SEND OK
AT+CIPSEND
>05x0 xB log/connectx0 x0 Qw37Tu89u78-91p - connected;MegaFon;12
23
7
x90 x3
x1
SEND OK
AT+CIPSTATUS
OK
STATE: CONNECT OK
AT+CIPCLOSE // опять принудительно разрываем связь
CLOSE OK
AT+CIPSTATUS
OK
STATE: TCP CLOSED
AT+CIPSHUT
SHUT OK
AT+CIPSTATUS
OK
STATE: IP INITIAL
AT + CSTT = "internet.emt.ee"
OK
AT+CIPSTATUS
OK
STATE: IP START
AT+CIICR
OK
AT+CIPSTATUS
OK
STATE: IP GPRSACT
AT+CIFSR
0.149.212.52S
OK
STATE: IP STATUS
AT+CIPSTART="TCP","m23.cloudmqtt.com",****** // теперь уже соединяемся с основным сервером
OK
AT+CIPSTATUS
OK
STATE: TCP CONNECTING
// ...... ждем соединения
AT+CIPSTATUS
OK
STATE: TCP CONNECTING
AT+CIPSTATUS
CONNECT OK
OK
STATE: CONNECT OK
AT+CIPSEND
>x10 3x0 x4 MQTTx4 xC0 x0 xFD x0 xF Qw37Tu89u78-91px0 x8 ******* xC ********
SEND OK
AT+CIPSEND
>x82 x1C x0 xA x0 x17 smd/Qw37Tu89u78-91p/cmdx1 x2 x1
SEND OK
AT+CIPSEND
>05x0 xB log/connectx0 x0 Qw37Tu89u78-91p - connected;MegaFon;12
23
0
x90 x3
x1
SEND OK
0x1D x17 smd/Qw37Tu89u78-91p/cmdcmd1AT+CIPSEND // пришла команда в подписанный топик, выполнили ее
>0"x0 x18 smd/Qw37Tu89u78-91p/respx0 x0 resp12 // отправили подтверждающий ответ
SEND OK
AT+CIPSEND
>xC0 x0 // бесконечно крутимся в цикле PING REQ
SEND OK
xD0 // PING RESP
-
часть кода, обработка интернет сессии по даташиту
-
void processStatus(byte inBt) { // основной анализ статусов, логика строго по даташиту
static unsigned long timerConnecting; // таймер для замера времени коннекта к брокеру
if (findRespFromBuf((char *) "IP INITIAL\r\n", inBt)) { // если начальный статус // 0
needCloseConnect = false; // разрывать связь не надо
// прописываем APN
gprsATcmdByIdx(0, false);
gprsATcmd((char *)getAPNname(opsCard), false);
gprsATcmd((char *)"\"\r", true);
currentGprsModem = waitOKcmd; // ждем ОК
} else if (findRespFromBuf((char *) "IP START\r\n", inBt)) { // следующий статус // 1
gprsATcmdByIdx(1, true); // активируем контекст
currentGprsModem = waitCIICRcmd; // ждем ОК
} else if (findRespFromBuf((char *) "IP GPRSACT\r\n", inBt)) { // следующий статус // 3
if (needCloseConnect) { // если нужно свзь разорвать
gprsATcmdByIdx(2, true); // отключаем контекст
currentGprsModem = waitOKcmd; // ждем ОК
} else { // если подключаем связь
gprsATcmdByIdx(3, true); // получаем адрес
currentGprsModem = waitRNcmd; // ждем вывода
}
} else if (findRespFromBuf((char *) "IP STATUS\r\n", inBt)) { // дальше // 4
if (needCloseConnect) { // если рвем связь
gprsATcmdByIdx(2, true); // отключаем контекст
} else { // продолжаем подключение
gprsATcmdByIdx(4, false); // коннектимся к серверу
if (mainMQTTserver) { // выбор сервера и отправка соотвествующего имени в зависимости от режима
#ifdef DEBUG_MODE
gprsATcmd((char *)"m20.cloudmqtt.com", false); gprsATcmd((char *)"\",", false); gprsATcmd((char *)"*****", false);
#else
char strServer[maxSizeBrokerID];
strcpy(strServer, (char *)mqttServer2); gprsATcmd((char *)strServer, false); gprsATcmd((char *)"\",", false);
strcpy(strServer, (char *)mqttPort2); gprsATcmd((char *)strServer, false);
#endif
} else { // основной сервер
#ifdef DEBUG_MODE
gprsATcmd((char *)"m23.cloudmqtt.com", false); gprsATcmd((char *)"\",", false); gprsATcmd((char *)"*****", false);
#else
char strServer[maxSizeBrokerID];
strcpy(strServer, (char *)mqttServer1); gprsATcmd((char *)strServer, false); gprsATcmd((char *)"\",", false);
strcpy(strServer, (char *)mqttPort1); gprsATcmd((char *)strServer, false);
#endif
}
gprsATcmd((char *)"\r", true); // шлем окончание команды
timerConnecting = currentMillis; // обнуляем таймер ожидания коннекта
}
currentGprsModem = waitOKcmd; // ждем ок
} else if (findRespFromBuf((char *) "CONNECT OK\r\n", inBt)) { // приконнектилось // 6
if (needCloseConnect) { // если нужен разрыв
gprsATcmdByIdx(5, true); // закрываем контекст
currentGprsModem = waitOKcmd; // ждем ОК
} else { // если подключаемся
currentGprsModem = serverConnected; // успешно выходим
}
} else if (findRespFromBuf((char *) "TCP CONNECTING\r\n", inBt)) { // в процессе подключения // 5
if (needCloseConnect) { // если нужно разорвать связь
gprsATcmdByIdx(2, true); // гасим
currentGprsModem = waitOKcmd; // ждем ОК
} else { // ждем подключения
if ((currentMillis - timerConnecting) >= gprsPeriodConnecting) { // если время вышло
if (mainMQTTserver) mainMQTTserver = 0; else mainMQTTserver = 1; // меняем сервер
++totalReconnectMQTT; // увеличиваем счетчик смены брокеров
gprsATcmdByIdx(2, true); // гасим контекст
currentGprsModem = waitOKcmd; // ждем ОК
} else { // если продолжыется подключение
currentGprsModem = sendCipStatus; // запрашиваем статус
}
}
} else if (findRespFromBuf((char *) "IP CONFIG\r\n", inBt)) { // шаг // 2
currentGprsModem = sendCipStatus; // запрос статуса
} else if (findRespFromBuf((char *) "TCP CLOSING\r\n", inBt)) { // шаг // 7
currentGprsModem = sendCipStatus; // запрос статуса
} else if (findRespFromBuf((char *) "TCP CLOSED\r\n", inBt)) { // отключились от сервера // 8
gprsATcmdByIdx(2, true); // гасим сессию
currentGprsModem = waitOKcmd; // ждем ОК
} else if (findRespFromBuf((char *) "DPD DEACT\r\n", inBt)) { // отключилась сессия // 9
currentGprsModem = sendCipStatus; // запрос статуса
} else if (findRespFromBuf((char *) "CONNECT FAIL\r\n", inBt)) { // ошибка соединения
gprsATcmdByIdx(2, true); // гасим сессию
currentGprsModem = waitOKcmd; // ждем ОК
}
}
-
к сожалению, какая бы не была хорошая схема, в среднем один из 20и модемов SIM800L зависает наглухо один раз в 50....70 дней, на команды отвечает, а по факту данные не передает. Поэтому рекомендую в схему добавить эл.ключ/реле, в случае принудительной перезагрузки третий раз за 15 минут, тупо отрубать питание. И конечно для стабильной работы строго использовать Hardware UART atmega328p.
просто с правильным SoftwareSerial видимо никто не экспериментировал...
А что, в природе такое бывает?
IMHO, SoftwareSerial - костыль, который, возможно, может быть в некоторых экзотических случаях использован для отладки, но который обязательно должен быть удален из финального кода.
аппаратная реализация сериала конечно лучше программной...
я знаю как минимум пяток реализаций программного, недостатки того, что из коробки...
захватывает все прерывания PCINT и нет поддержки параметров число бит данных, контроль, стоп биты
первый решился бы разработкой библиотеки менеджера прерываний, второй решен в одной из библиотек, но
только для ограниченного набора частот кварца
смотрю профессиональные девайсы, а там используется SIM300... более стабилен в работе?
а что в вашем понятии профессиональные девайсы? мой последний проект/заказ c SIM800L развернут на нескольких тысяч устройств, в планах 200000+ , но считать его профессиональным я например не могу.
и да, соглашусь с мнением выше, использовать software serial из коробки можно только для вывода какого нибудь не критичного лога. Если у вас он стабильно работает, могу только поздравить.
но считать его профессиональным я например не могу.
Интересно, почему ?
потому что я не профессиональный программист/электронщик и не имею соответствующего сертификата как у какого нибудь КБ с кучей специалистов разной направленности :)
но да, устройства работают хорошо и стабильно, поэтому конечно вопрос спорный что считать проф.устройством.
использовать software serial из коробки можно только для вывода какого нибудь не критичного лога.
Даже для этого нельзя, если софт интенсивно прерывания юзает. software serial его положит. Список его авторов я уже дето выкладывал. Этих уродов регулярно упоминаю в проклятиях. Надо быть последним фашистским человеконенавистником чтоб такое нахерячить. И да - тех кого устраивает как оно работает - дальше хелоуворда не пробовали. Он просто не может стабильно работать не убив все вокруг.
Температура, влажность, давление на BME280+ESP8266(WeMos D1 mini), отправляемые на MQTT сервер.
Код сборная солянка, страшненький, написан наспех на коленке, но работает стабильно.
При включении подключается в течении 2 минут к WiFi точке доступа, в случае облома запускает сервер куда вбиваются данные WiFi и MQTT. Далее получает данные, отправлет и засыпает на 25 минут.
Потребление через понижайку от аккумулятора 18650 ~1.5мА в спящем режиме
#include <ESP8266WebServer.h>
#include <ESP8266WiFi.h>
#include <EEPROM.h>
#include <Wire.h>
#include <Adafruit_BME280.h>
#include <Adafruit_Sensor.h>
#define SEALEVELPRESS_HPA (1013.25)
Adafruit_BME280 bme;
char srvssid[] = "ESterm06";
char srvpass[] = "ESterm06";
ESP8266WebServer server(80);
/* Just a little test message. Go to http://192.168.4.1 in a web browser
connected to this access point to see it.
*/
byte wifiset = 0; byte mqttset = 0;
#define eep_max_len_param 0x40
#define eep_max_count_params 7
#define eep_pos_wifi_p1 0x10
#define eep_pos_wifi_p2 0x30
#define eep_pos_mqtt_p1 0x60
#define eep_pos_mqtt_p2 0x80
#define eep_pos_mqtt_p3 0xA0
#define eep_pos_mqtt_p4 0xC0
#define eep_pos_mqtt_p5 0xE0
char eep_str[eep_max_len_param];
#define period_enable_http_server 300000UL // 5min
unsigned long timer_enable_http_server = 0;
#define size_response_buf 0x40
char mqtt_response_buf[size_response_buf];
byte pos_response_mqtt = 0;
#define errTemp 1111
word currTemp = errTemp;
word currHum = errTemp;
word currPres = errTemp;
byte deviceMode = 10; // main mode work device
// 0 connect wifi
// 1 wait connect wifi
// 2 repeat connect wifi
// 3 connect to mqtt server
// 7 load data mqtt
// 8 wifi access point + http server - several minuts after start
// 9 wait get/post answer
// 10 get temp/hum/press
// 11 sleep device
char ssid[eep_max_len_param];
char password[eep_max_len_param];
#define period_test_wifi_connect 500UL
unsigned long timer_test_wifi_connect = 0;
#define period_timeout_wifi_connect 30000UL // 30sec
unsigned long timer_timeout_wifi_connect = 0;
#define period_repeat_wifi_connect 30000UL // 30sec and MQTT repeat
unsigned long timer_repeat_wifi_connect = 0;
WiFiClient client;
char mqtt_server[eep_max_len_param];
int mqtt_port;
char mqtt_user[eep_max_len_param];
char mqtt_pass[eep_max_len_param];
char mqtt_device[eep_max_len_param];
char mqtt_realhard[] = "Pogreb01-CatVil";
char mqtt_topic_temp[] = "/pog";
char mqtt_topic_hum[] = "/hum";
char mqtt_topic_pres[] = "/pre";
unsigned long currentMillis;
#define LEDON digitalWrite(LED_BUILTIN,LOW)
#define LEDOFF digitalWrite(LED_BUILTIN,HIGH)
void ledFlash(byte countFlash) {
for (byte i = 0; i < countFlash; ++i) {
LEDON; delay(100); LEDOFF; delay(100);
}
delay(400);
}
void setup() {
// put your setup code here, to run once:
pinMode(LED_BUILTIN, OUTPUT);
LEDOFF; EEPROMinit();
Serial.begin(115200); Serial.println("Reset Serial");
ledFlash(1); loadDataWiFiEEPROM(); loadDataMqttEEPROM();
}
void processMainWork() {
switch (deviceMode) {
case 0: { // connect wifi
WiFi.disconnect(true);
Serial.print("Connect to WiFi AP "); Serial.println(ssid);
WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); ++deviceMode; timer_timeout_wifi_connect = currentMillis; timer_test_wifi_connect = currentMillis; break;
}
case 1: { // wait connect wifi
if ((currentMillis - timer_test_wifi_connect) >= period_test_wifi_connect) {
timer_test_wifi_connect = currentMillis;
if (WiFi.status() == WL_CONNECTED) {
Serial.println("WiFi connected"); deviceMode = 3; // connect ok
ledFlash(3);
} else {
Serial.print(".");
if ((currentMillis - timer_timeout_wifi_connect) >= period_timeout_wifi_connect) {
Serial.println("WiFi timeout connection"); timer_repeat_wifi_connect = currentMillis; deviceMode = 8; WiFi.disconnect(); // problem connect
}
}
} break;
}
case 3: { // connect to mqtt server
if (client.connect(mqtt_server, mqtt_port)) {
Serial.println("MQTT connected"); deviceMode = 5; // connect ok
} else {
Serial.println("Error MQTT connect"); timer_repeat_wifi_connect = currentMillis; deviceMode = 4; // problem connect
} break;
}
case 4: { // repeat connect mqtt
if ((currentMillis - timer_repeat_wifi_connect) >= period_repeat_wifi_connect) {
if (WiFi.status() == WL_CONNECTED) {
deviceMode = 3;
} else {
deviceMode = 0;
}
} break;
}
case 5: { // send conneck packet and subscribe
sendConnectPacket(); Serial.println(""); deviceMode = 6; timer_repeat_wifi_connect = currentMillis; break;
}
case 6: { // wait response - pause 3 sec
if ((currentMillis - timer_repeat_wifi_connect) >= 3000UL) {
deviceMode = 7;
} else {
if (client.available()) {
while (client.available()) {
byte inByte = client.read();
if ((inByte < 0x20) || (inByte >= 0x7F)) {
Serial.print(" 0x"); Serial.print(inByte, HEX); Serial.print(" ");
} else {
Serial.write(inByte);
}
}
} // end avail
} // -
break;
}
case 7: { // send data
Serial.println(" Need send current temp! ");
sendPubTemp(); Serial.println("");
Serial.println(" Need send current hum! ");
sendPubHum(); Serial.println("");
Serial.println(" Need send current pres! ");
sendPubPres(); Serial.println("");
deviceMode = 11; // sleep
break;
}
case 8: { // start wifi and http server
WiFi.disconnect(true);
Serial.print("Configuring access point...");
WiFi.softAP(srvssid, srvpass);
IPAddress myIP = WiFi.softAPIP();
Serial.print("AP IP address: ");
Serial.println(myIP);
server.on("/", handleRoot);
server.on("/setup", HTTP_GET, handleSetupGet);
server.on("/setup", HTTP_POST, handleSetupPost);
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP server started");
deviceMode = 9;
timer_enable_http_server = currentMillis;
break;
}
case 9: {
server.handleClient();
if (server.hasArg("action")) {
if (!wifiset) {
if (((server.arg("action").indexOf("savewifi")) >= 0) && (server.hasArg("ssid")) && (server.hasArg("pass"))) {
wifiset = 1;
Serial.println("There are new WiFi data");
// save data to eeprom
byte l = server.arg("ssid").length() + 1;
server.arg("ssid").toCharArray(eep_str, l); eep_str[l] = 0;
byte i = 0; while (eep_str[i] > 0) {
EEPROM.write(eep_pos_wifi_p1 + i, eep_str[i]); ++i;
} EEPROM.write(eep_pos_wifi_p1 + i, 0);
l = server.arg("pass").length() + 1;
server.arg("pass").toCharArray(eep_str, l); eep_str[l] = 0;
i = 0; while (eep_str[i] > 0) {
EEPROM.write(eep_pos_wifi_p2 + i, eep_str[i]); ++i;
} EEPROM.write(eep_pos_wifi_p2 + i, 0);
EEPROM.commit();
EEPROM.end();
EEPROMinit();
loadDataWiFiEEPROM();
}
}
if (!mqttset) {
if (((server.arg("action").indexOf("mqttset")) >= 0) && (server.hasArg("host")) && (server.hasArg("port")) && (server.hasArg("user")) && (server.hasArg("pass")) && (server.hasArg("devname"))) {
mqttset = 1;
Serial.println("There are new MQTT data");
// save data to eeprom
byte l = server.arg("host").length() + 1;
server.arg("host").toCharArray(eep_str, l); eep_str[l] = 0;
byte i = 0; while (eep_str[i] > 0) {
EEPROM.write(eep_pos_mqtt_p1 + i, eep_str[i]); ++i;
} EEPROM.write(eep_pos_mqtt_p1 + i, 0);
l = server.arg("port").length() + 1;
server.arg("port").toCharArray(eep_str, l); eep_str[l] = 0;
i = 0; while (eep_str[i] > 0) {
EEPROM.write(eep_pos_mqtt_p2 + i, eep_str[i]); ++i;
} EEPROM.write(eep_pos_mqtt_p2 + i, 0);
l = server.arg("user").length() + 1;
server.arg("user").toCharArray(eep_str, l); eep_str[l] = 0;
i = 0; while (eep_str[i] > 0) {
EEPROM.write(eep_pos_mqtt_p3 + i, eep_str[i]); ++i;
} EEPROM.write(eep_pos_mqtt_p3 + i, 0);
l = server.arg("pass").length() + 1;
server.arg("pass").toCharArray(eep_str, l); eep_str[l] = 0;
i = 0; while (eep_str[i] > 0) {
EEPROM.write(eep_pos_mqtt_p4 + i, eep_str[i]); ++i;
} EEPROM.write(eep_pos_mqtt_p4 + i, 0);
l = server.arg("devname").length() + 1;
server.arg("devname").toCharArray(eep_str, l); eep_str[l] = 0;
i = 0; while (eep_str[i] > 0) {
EEPROM.write(eep_pos_mqtt_p5 + i, eep_str[i]); ++i;
} EEPROM.write(eep_pos_mqtt_p5 + i, 0);
EEPROM.commit();
EEPROM.end();
EEPROMinit();
loadDataMqttEEPROM();
}
}
}
if ((currentMillis - timer_enable_http_server) >= period_enable_http_server) {
Serial.println("Stop HTTP server");
server.stop();
WiFi.disconnect(true);
deviceMode = 11; // sleep
}
break;
}
case 10: { // get temp hum press
if (!bme.begin(0x76)) {
Serial.println("BME280 problem!");
} else {
currTemp = ((word)(bme.readTemperature() * 10)) + 2000;
currHum = bme.readHumidity();
currPres = (word)(bme.readPressure() / 133.322368421);
ledFlash(2);
}
deviceMode = 0; // connect to wifi
break;
}
case 11: { // wait 5 sec and sleep
timer_repeat_wifi_connect = currentMillis;
++deviceMode;
break;
}
default: { // wait 5 sec
if ((currentMillis - timer_repeat_wifi_connect) >= 5000UL) {
// 12 sleep device
Serial.println(" sleep device ");
WiFi.disconnect(true);
ESP.deepSleep(1500e6); // sleep 25min
} else {
if (client.available()) {
while (client.available()) {
byte inByte = client.read();
if ((inByte < 0x20) || (inByte >= 0x7F)) {
Serial.print(" 0x"); Serial.print(inByte, HEX); Serial.print(" ");
} else {
Serial.write(inByte);
}
}
} // end avail
} // -
}
}
}
void loop() {
// put your main code here, to run repeatedly:
currentMillis = millis();
// main work
processMainWork();
// end loop
}
void sendConnectPacket() {
byte sizeDevice = strlen(mqtt_realhard); byte sizeUser = strlen(mqtt_user); byte sizePass = strlen(mqtt_pass);
// fixed header
sendByteToMQTTclient((byte)0x10); // MQTT Control Packet type 0001 connect, reserved 0000
sendByteToMQTTclient((byte)(16 + sizeDevice + sizeUser + sizePass)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload.
// Variable header
sendByteToMQTTclient((byte)0x00); // Length MSB (0)
sendByteToMQTTclient((byte)0x04); // Length LSB (4)
sendByteToMQTTclient((byte)'M'); sendByteToMQTTclient((byte)'Q'); sendByteToMQTTclient((byte)'T'); sendByteToMQTTclient((byte)'T'); // protocol name
sendByteToMQTTclient((byte)0x04); // Protocol Level byte
sendByteToMQTTclient((byte)0xC0); // Connect Flag bits, login and pass enable + retain +will flag
sendByteToMQTTclient((byte)0x00); // Keep Alive MSB (0)
sendByteToMQTTclient((byte)0x28); // Keep Alive LSB (10) - 40 sec
// payload
sendByteToMQTTclient((byte)0x00); // Length MSB (0)
sendByteToMQTTclient((byte)sizeDevice); // Length LSB (4) - device
for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_realhard[i]));
sendByteToMQTTclient((byte)0x00); // Length MSB (0)
sendByteToMQTTclient((byte)sizeUser); // Length LSB (4) - user
for (byte i = 0; i < sizeUser; ++i) sendByteToMQTTclient((byte)(mqtt_user[i]));
sendByteToMQTTclient((byte)0x00); // Length MSB (0)
sendByteToMQTTclient((byte)sizePass); // Length LSB (4) - pass
for (byte i = 0; i < sizePass; ++i) sendByteToMQTTclient((byte)(mqtt_pass[i]));
}
void sendByteToMQTTclient(byte inByte) {
client.write((byte)(inByte));
if ((inByte < 0x20) || (inByte >= 0x7F)) {
Serial.print(" 0x"); Serial.print(inByte, HEX); Serial.print(" ");
} else {
Serial.write(inByte);
}
}
void sendPubTemp() {
char textTemp[] = "-100.0 °C"; byte textPos = 0; word absTemp = currTemp;
if (currTemp == errTemp) {
textTemp[textPos] = 'n'; ++textPos; textTemp[textPos] = 'o'; ++textPos;
} else {
if (absTemp >= 2000) {
textTemp[textPos] = '+'; absTemp -= 2000;
} else {
textTemp[textPos] = '-';
} ++textPos;
//word bt = absTemp * 0.023; absTemp = absTemp + bt; // correct to true temp
if (absTemp >= 1000) {
textTemp[textPos] = (absTemp / 1000) + '0'; absTemp = absTemp % 1000; ++textPos; textTemp[textPos] = (absTemp / 100) + '0'; absTemp = absTemp % 100; ++textPos; textTemp[textPos] = (absTemp / 10) + '0'; ++textPos;
} else if (absTemp >= 100) {
textTemp[textPos] = (absTemp / 100) + '0'; absTemp = absTemp % 100; ++textPos; textTemp[textPos] = (absTemp / 10) + '0'; ++textPos;
} else if (absTemp >= 10) {
textTemp[textPos] = (absTemp / 10) + '0'; ++textPos;
}
textTemp[textPos] = '.'; ++textPos; textTemp[textPos] = (absTemp % 10) + '0'; ++textPos;
}
textTemp[textPos] = ' '; ++textPos; textTemp[textPos] = '`'; ++textPos; textTemp[textPos] = 'C'; ++textPos; textTemp[textPos] = 0;
byte sizeDevice = strlen(mqtt_device); byte sizeTopic = strlen(mqtt_topic_temp); byte sizeData = strlen(textTemp);
// fixed header
sendByteToMQTTclient((byte)0x31); // MQTT Control Packet type 0011, DUP QoS Retain 0001 flags
sendByteToMQTTclient((byte)(4 + sizeDevice + sizeTopic + sizeData)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload.
// Variable header
sendByteToMQTTclient((byte)0x00); // Length MSB (0)
sendByteToMQTTclient((byte)(sizeDevice + sizeTopic)); // Length LSB (4)
for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i]));
for (byte i = 0; i < sizeTopic; ++i) sendByteToMQTTclient((byte)(mqtt_topic_temp[i]));
sendByteToMQTTclient((byte)0x00); // Packet Identifier MSB (0)
sendByteToMQTTclient((byte)0x00); // Packet Identifier LSB (10)
// payload
for (byte i = 0; i < sizeData; ++i) sendByteToMQTTclient((byte)(textTemp[i]));
}
void sendPubHum() {
char textTemp[] = "-100.0 °C"; byte textPos = 0; word absTemp = currHum;
if (currHum == errTemp) {
textTemp[textPos] = 'n'; ++textPos; textTemp[textPos] = 'o'; ++textPos;
} else {
if (absTemp >= 1000) {
textTemp[textPos] = (absTemp / 1000) + '0'; absTemp = absTemp % 1000; ++textPos; textTemp[textPos] = (absTemp / 100) + '0'; absTemp = absTemp % 100; ++textPos; textTemp[textPos] = (absTemp / 10) + '0'; ++textPos;
} else if (absTemp >= 100) {
textTemp[textPos] = (absTemp / 100) + '0'; absTemp = absTemp % 100; ++textPos; textTemp[textPos] = (absTemp / 10) + '0'; ++textPos;
} else if (absTemp >= 10) {
textTemp[textPos] = (absTemp / 10) + '0'; ++textPos;
}
textTemp[textPos] = (absTemp % 10) + '0'; ++textPos;
}
textTemp[textPos] = ' '; ++textPos; textTemp[textPos] = '%'; ++textPos; textTemp[textPos] = 0;
byte sizeDevice = strlen(mqtt_device); byte sizeTopic = strlen(mqtt_topic_hum); byte sizeData = strlen(textTemp);
// fixed header
sendByteToMQTTclient((byte)0x31); // MQTT Control Packet type 0011, DUP QoS Retain 0001 flags
sendByteToMQTTclient((byte)(4 + sizeDevice + sizeTopic + sizeData)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload.
// Variable header
sendByteToMQTTclient((byte)0x00); // Length MSB (0)
sendByteToMQTTclient((byte)(sizeDevice + sizeTopic)); // Length LSB (4)
for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i]));
for (byte i = 0; i < sizeTopic; ++i) sendByteToMQTTclient((byte)(mqtt_topic_hum[i]));
sendByteToMQTTclient((byte)0x00); // Packet Identifier MSB (0)
sendByteToMQTTclient((byte)0x00); // Packet Identifier LSB (10)
// payload
for (byte i = 0; i < sizeData; ++i) sendByteToMQTTclient((byte)(textTemp[i]));
}
void sendPubPres() {
char textTemp[] = "-100.0 °C"; byte textPos = 0; word absTemp = currPres;
if (currPres == errTemp) {
textTemp[textPos] = 'n'; ++textPos; textTemp[textPos] = 'o'; ++textPos;
} else {
if (absTemp >= 1000) {
textTemp[textPos] = (absTemp / 1000) + '0'; absTemp = absTemp % 1000; ++textPos; textTemp[textPos] = (absTemp / 100) + '0'; absTemp = absTemp % 100; ++textPos; textTemp[textPos] = (absTemp / 10) + '0'; ++textPos;
} else if (absTemp >= 100) {
textTemp[textPos] = (absTemp / 100) + '0'; absTemp = absTemp % 100; ++textPos; textTemp[textPos] = (absTemp / 10) + '0'; ++textPos;
} else if (absTemp >= 10) {
textTemp[textPos] = (absTemp / 10) + '0'; ++textPos;
}
textTemp[textPos] = (absTemp % 10) + '0'; ++textPos;
}
textTemp[textPos] = ' '; ++textPos; textTemp[textPos] = 'm'; ++textPos; textTemp[textPos] = 'm'; ++textPos; textTemp[textPos] = 0;
byte sizeDevice = strlen(mqtt_device); byte sizeTopic = strlen(mqtt_topic_pres); byte sizeData = strlen(textTemp);
// fixed header
sendByteToMQTTclient((byte)0x31); // MQTT Control Packet type 0011, DUP QoS Retain 0001 flags
sendByteToMQTTclient((byte)(4 + sizeDevice + sizeTopic + sizeData)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload.
// Variable header
sendByteToMQTTclient((byte)0x00); // Length MSB (0)
sendByteToMQTTclient((byte)(sizeDevice + sizeTopic)); // Length LSB (4)
for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i]));
for (byte i = 0; i < sizeTopic; ++i) sendByteToMQTTclient((byte)(mqtt_topic_pres[i]));
sendByteToMQTTclient((byte)0x00); // Packet Identifier MSB (0)
sendByteToMQTTclient((byte)0x00); // Packet Identifier LSB (10)
// payload
for (byte i = 0; i < sizeData; ++i) sendByteToMQTTclient((byte)(textTemp[i]));
}
byte getByteFromTwoChar(byte byte1, byte byte0) {
byte resultB;
if (byte1 >= 0x41) resultB = (byte1 - 0x37) * 16; else resultB = (byte1 - 0x30) * 16;
if (byte0 >= 0x41) resultB = resultB + (byte0 - 0x37); else resultB = resultB + (byte0 - 0x30);
return resultB;
}
void handleNotFound() {
String message = "File Not Found\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
server.send(404, "text/plain", message);
}
void handleRoot() {
wifiset = 0; mqttset = 0;
server.send(200, "text/html", "<h1>You are connected</h1>");
}
void handleSetupGet() {
String message = "<html lang='ru'>\
<head>\
<meta charset='utf - 8'>\
<title>ESP temperature Server</title>\
</head>\
<body>\
<h1>WiFi Acces Point data</h1>\
<form action='?' method='post'>\
<div>\
<label for='ssid'>WiFi SSID: <input type='text' name='ssid' id='ssid' value='";
message += ssid;
message += "'></label>\
</div>\
<div>\
<label for='pass'>WiFi Password: <input type='password' name='pass' id='pass' value='";
message += password;
message += "'></label>\
</div>\
<p></p>\
<input type='hidden' name='action' value='savewifi'>\
<input type='submit' value='Save'>\
</div>\
</form>\
<form action='?' method='post'>\
<div>\
<label for='host'>Host: <input type='text' name='host' id='host' value='";
message += mqtt_server;
message += "'></label>\
</div>\
<div>\
<label for='port'>Port: <input type='text' name='port' id='port' value='";
message += mqtt_port;
message += "'></label>\
</div>\
<p></p>\
<div>\
<label for='user'>User: <input type='text' name='user' id='user' value='";
message += mqtt_user;
message += "'></label>\
</div>\
<div>\
<label for='pass'>Password: <input type='password' name='pass' id='pass' value='";
message += mqtt_pass;
message += "'></label>\
</div>\
<p></p>\
<div>\
<label for='devname'>Topic name: <input type='text' name='devname' id='devname' value='";
message += mqtt_device;
message += "'></label>\
</div>\
<p></p>\
<input type='hidden' name='action' value='mqttset'>\
<input type='submit' value='Set'>\
</form>\
<p></p>\
<a href='../'>Return to main page</a>\
</body>\
</html>";
server.send(200, "text/html", message);
}
void handleSetupPost() {
server.send(200, "text/html", "<html lang='ru'>\
<head>\
<meta charset='utf - 8'>\
<title>ESP temperature Server</title>\
</head>\
<body>\
<h1>OK</h1>\
<p></p>\
<a href='../'>Return to main page</a>\
</body>\
</html>");
}
char* LastPos(char *str1, char *str2) { // find substring in string
int L1 = strlen(str1);
int L2 = strlen(str2);
for (int i = L1 - L2; i >= 0; i--)
{
int j = 0;
for (; j < L2; j++)
if ((str1[i + j] != str2[j]))
break;
if (j == L2)
return str1 + i;
}
return 0;
}
int strPos(char *str11, char *str22) { // find position in string(1) substring(2)
char*p = LastPos(str11, str22);
int n = p - str11;
return n;
}
void loadDataWiFiEEPROM() {
byte i = 0; while (((eep_str[i] = EEPROM.read(eep_pos_wifi_p1 + i)) > 0) && (i < eep_max_len_param)) ++i; eep_str[i] = 0;
strcpy(ssid, eep_str);
i = 0; while (((eep_str[i] = EEPROM.read(eep_pos_wifi_p2 + i)) > 0) && (i < eep_max_len_param)) ++i; eep_str[i] = 0;
strcpy(password, eep_str);
}
void EEPROMinit() {
EEPROM.begin(eep_max_len_param * eep_max_count_params);
}
void loadDataMqttEEPROM() {
byte i = 0; while (((eep_str[i] = EEPROM.read(eep_pos_mqtt_p1 + i)) > 0) && (i < eep_max_len_param)) ++i; eep_str[i] = 0;
strcpy(mqtt_server, eep_str);
i = 0; while (((eep_str[i] = EEPROM.read(eep_pos_mqtt_p2 + i)) > 0) && (i < eep_max_len_param)) ++i; eep_str[i] = 0;
mqtt_port = atoi(eep_str);
i = 0; while (((eep_str[i] = EEPROM.read(eep_pos_mqtt_p3 + i)) > 0) && (i < eep_max_len_param)) ++i; eep_str[i] = 0;
strcpy(mqtt_user, eep_str);
i = 0; while (((eep_str[i] = EEPROM.read(eep_pos_mqtt_p4 + i)) > 0) && (i < eep_max_len_param)) ++i; eep_str[i] = 0;
strcpy(mqtt_pass, eep_str);
i = 0; while (((eep_str[i] = EEPROM.read(eep_pos_mqtt_p5 + i)) > 0) && (i < eep_max_len_param)) ++i; eep_str[i] = 0;
strcpy(mqtt_device, eep_str);
}
Добрый день. Подскажите пожалуйста в чем может быть проблема? Сделал sim800+arduino, брокер был cloudmqtt.com. Все работало стабильно.Решил перенести на другой брокер,www.dioty.co. Возникли трудности. Опубликовать в паблик могу, все передается на брокер, но как только пытаюсь подписаться на топик, сразу закрывает соединение
использовать software serial из коробки можно только для вывода какого нибудь не критичного лога.
Даже для этого нельзя, если софт интенсивно прерывания юзает. software serial его положит. Он просто не может стабильно работать не убив все вокруг.
Есть еще CustomSoftwareSerial, SomeSerial, я их использую
А какая, собственно, разница?
Любая программная реализация последовательного порта будет конфликтовать с прерываниями. Вопрос лишь в том, что раньше отвалится - сам COM-порт или все остальное оборудование, требующее прерываний.
PS. Лично я программный COM-порт не использую. Где-то при отладке - еще может быть, а в готовом изделии - никогда.
Любая программная реализация последовательного порта будет конфликтовать с прерываниями. Вопрос лишь в том, что раньше отвалится - сам COM-порт или все остальное оборудование, требующее прерываний.
PS. Лично я программный COM-порт не использую. Где-то при отладке - еще может быть, а в готовом изделии - никогда.
использует PCINT однако, только захватывает все прерывания, править библиотеку приходится освобождая ненужные, DetSimen написал библиотеку для радиолюбителей использующую софтовый сериал, всё работает при правильном подходе )))
использует PCINT однако, только захватывает все прерывания, править библиотеку приходится освобождая ненужные,
Ну переписали мы таким образом библиотеку. Ну пошли у нас прерывания со стороны. И вот тут каждое устройство стало тянуть одеяло на себя. И кто-то из них в этом перетягивании однозначно проиграет. Чудес не бывает: либо с софтсериал полезут ошибки, либо другое устройство будет работать ненормально со всеми вытекающими.
Цитата:
DetSimen написал библиотеку для радиолюбителей использующую софтовый сериал, всё работает при правильном подходе )))
Вот именно - при правильном! А отключить часть пинов от pcint и думать, что все проблемы уже решены - подход явно неправильный.
И кому это? если мне, то не интересно - я все это читал.
В логах брокера что нибудь вразумительное есть? Модем корректно отвечает на все команды? отправка успешна у модема?
После отправки 0xC0 0x00 0x1A из порта модема получаю 0xFF 0xC0 0x00 0x1A. Т.е. на сколько я понимаю наружу ничего не уходит.
После отправки 0xC0 0x00 0x1A из порта модема получаю 0xFF 0xC0 0x00 0x1A. Т.е. на сколько я понимаю наружу ничего не уходит.
Что значит из "порта модема получаю" - это откуда?
Сложно судить, вы бы скетч весь выложили, посмотрим. А ещё проще - тупо для испытания - напишите простенький скетч с последовательностью АТ команд что выше было - они то гарантированно наружу шлют данные. И будет понятно где косяк.
И вы так и не выложили что отвечает модем и лог брокера.
Update : я так понимаю вам модем в ответ дублирует посланную команду - отключите нафиг чтоб не мешало разбираться.
void brokerPing() { gsm.println("AT+CIPSEND"); if (!gsm.find(">")) return; . gsm.write(0xC0); gsm.write(byte(0x00)); gsm.write(0x1A); delay(100); Serial.print("ping resp: "); while(gsm.available()) Serial.print(" "), Serial.print(gsm.read(), HEX); }После вызова функции в терминале вижу:
К брокеру ессенно в это время подключен, паблиши улетают как положено.
А что касаемо лога, а что лог... в нём не пишется ничего из обена, там просто коннект, дисконнект и всего то...
Я чё думаю: может не морочится с пингом. пустой паблиш туда кадать какой нибудь до таймута да и всё, по сути эффект будет тот же.
Вот смотрю я на код, а с чего вы взяли что ответ от брокера стабильно через 100 миллисекунд придёт, а например не через секунду.
Может быть я не прав, но уже писал - такая архитектура скетча с delay и не дожидаться ответов от модемов и без их анализа - неработоспособна!
По поводу пинга - каждый коннект к брокер сотовый оператор считает за новое подключение, соответственно если у вас лимитный интернет и коннктится каждые N секунд - трафик весь быстро закончится. Пинг пакеты на то и придуманы в mqtt чтоб коннктится раз например в сутки, и постоянно проверять связь через M секунд.
Делэй поставил уже от безисходности, кстати ставил setTimeout на порт 10000 - эффект нет.. И вообще модем должен что то внятное пинуть в порт после отправки пакета, я его жду. При отправке паблиша или подписки сразу получаю "SEND OK, а тут нифига. Видимо я всё же как то не правильно формирую пакет.
Вижу два варианта :
1 сменить брокера - возможно он что то шлёт не так
2 взять наконец то нормальный пример с последовательность АТ команд и делать по аналогии
ЗЫ. Чудес не бывает.
Update :
3. Пересмотреть всю логику работы с модемом - переходить на конечные автоматы или их подобие, т е каждая отправлена команда подразумевает ожидание некоего ответа и или какие то действия и в зависимости от условия - переходить на другие действия.
И ещё команда cipsend имеет несколько режимов работы, я отправляю с указанием количества отправояемых байт, а вы как настроили свой модем?)
Пока скетч не выложите - сложно далее что либо обсуждать.
Весь скетч
#include <SoftwareSerial.h> const char* apn = "internet.tele2.ru"; // apn<,user,pass> const char* broker = "m23.cloudmqtt.com,17155"; // addr,port const char* proto = "MQIsdp"; const char* cid = "BlackBox"; const char* willt = "notify"; const char* willm = "BlackBox is died!"; const char* user = "e4tggrtgerge"; const char* pass = "ergergerge3334343f34f"; SoftwareSerial gsm(9, 10); unsigned long t1min = 0; char* at = ""; char* buff = ""; /*AT+CFUN=1,1 OK AT+CREG? cycle +CREG: 0,1 AT+CSTT=internet.tele2.ru OK AT+CIICR OK AT+CIFSR 10.142.119.220 AT+CDNSCFG=8.8.8.8 OK AT+CIPSTATUS OK STATE: IP STATUS AT+CIPSTART=TCP,m23.cloudmqtt.com,17015 OK CONNECT */ bool gprsConnect () { gsm.println("AT+CFUN=1,1"); if ( !gsm.find("OK") ) return false; delay(3000); for (byte i = 0;; i++) { gsm.println("AT+CREG?"); delay(1000); if ( gsm.find("+CREG: 0,1") ) break; if (i > 10) return false; } gsm.println("+CIPMUX=0"); if ( !gsm.find("OK") ) return false; gsm.print ("AT+CSTT="); gsm.println(apn); if ( !gsm.find("OK") ) return false; gsm.println("AT+CIICR"); gsm.setTimeout(10000); if ( !gsm.find("OK") ) return false; gsm.setTimeout(1000); gsm.println("AT+CIFSR"); gsm.readString(); gsm.println("AT+CDNSCFG=8.8.8.8"); if ( !gsm.find("OK") ) return false; gsm.println("AT+CIPSTATUS"); return gsm.find("STATE: IP STATUS"); } bool brokerConnect () { gsm.print("AT+CIPSTART=TCP,"); gsm.println(broker); delay(2000); if (!gsm.find("CONNECT OK")) return false; //gsm.println("AT+CIPHEAD=1"); if (!gsm.find("OK")) return false; gsm.println("AT+CIPSEND"); if ( !gsm.find(">") ) return false; gsm.write(0x10); gsm.write(12 + 2+strlen(cid) + 2+strlen(willt) + 2+strlen(willm) + 2+strlen(user) + 2+strlen(pass)); gsm.write((byte)0x00); gsm.write(0x06); gsm.write("MQIsdp"); gsm.write(0x03); // proto, ver gsm.write(0xC6); gsm.write((byte)0x00); gsm.write(0x3C); // flags, ka timout gsm.write((byte)0x00); gsm.write(strlen(cid)); gsm.write(cid); gsm.write((byte)0x00); gsm.write(strlen(willt)); gsm.write(willt); gsm.write((byte)0x00); gsm.write(strlen(willm)); gsm.write(willm); gsm.write((byte)0x00); gsm.write(strlen(user)); gsm.write(user); gsm.write((byte)0x00); gsm.write(strlen(pass)); gsm.write(pass); brokerPub("notify", "BlackBox is alive..."); brokerSub("cmd/#"); gsm.write(0x1A); //return (gsm.read() == "+IPD,1\0"); //return (gsm.read() == (byte)0); return gsm.find("SEND OK"); } void brokerPub (const char* topic, const char* msg) { gsm.write(0x30); gsm.write((2+strlen(topic) + strlen(msg))); gsm.write((byte)0x00), gsm.write(strlen(topic)), gsm.write(topic); gsm.write(msg); } void brokerSub (const char* topic) { gsm.write(0x82); gsm.write(strlen(topic) + 5); gsm.write((byte)0x00); gsm.write(0x01) ; gsm.write((byte)0x00); gsm.write(strlen(topic)); gsm.write(topic); gsm.write((byte)0x00); } bool brokerPing() {////////////////////////////////////00000230: ff c0 00 1a 0d 0a 53 45 | 4e 44 20 4f 4b 0d 0a d0 ÿÀ....SEND OK gsm.println("AT+CIPSEND"); if (!gsm.find(">")) return false;//////00000240: 00 . gsm.write(0xC0); gsm.write(byte(0x00)); gsm.write(0x1A); delay(1000); Serial.print("ping ret :"); while(gsm.available()) Serial.print(" "), Serial.print(gsm.read(), HEX); Serial.println(); return true; //gsm.find("SEND OK"); } bool googlePing() { gsm.println("AT+CIPPING=8.8.8.8,1"); return gsm.find("+CIPPING:"); } void setup() { Serial.begin(9600); delay(500); gsm.begin(9600); delay(500); while (true) { Serial.print("gprs connect... "); if ( gprsConnect() ) break; Serial.println("error!"); } Serial.println("OK"); while (true) { Serial.print("broker connect... "); if ( brokerConnect() ) break; Serial.println("error!"); } Serial.println("OK"); delay(5000); pinMode(13, OUTPUT); } void loop() { if ((millis() - t1min) > 30*1000) t1min = millis(), brokerPing(); //while(Serial.available()) gsm.write(Serial.read()); //while(gsm.available()) Serial.write(gsm.read()); at = ""; if ( gsm.available() ) at = gsm.readString().c_str(); // gsm.println("AT+CIPSEND"); // brokerPub("notify", Serial.readString().c_str()); // gsm.write(0x1A); if ( strstr(at, "cmd/start1") != 0 ) digitalWrite(13, HIGH);//////00000340: ff c0 00 1a 30 0c 00 09 | 63 6d 64 2f 73 74 61 72 ÿÀ..0...cmd/star if ( strstr(at, "cmd/start0") != 0 ) digitalWrite(13, LOW); //////00000350: 74 30 0d 0a t0.. if ( strstr(at, "cmd/stopTimer") != 0 ) { Serial.print("stopTimer="); for ( byte i = 0;;i++ ) { if ( (byte)strstr(at, "stopTimer")[8+i] > 0x30 ) { buff[i] = '\0'; break; } buff[i] = strstr(at, "stopTimer")[8+i]; } Serial.println(buff); } if ( strstr(at, "cmd/stopTemp") != 0 ) { Serial.print("stopTemp="); for ( byte i = 0;;i++ ) { if ( (byte)strstr(at, "stopTemp")[7+i] > 0x30 ) { buff[i] = '\0'; break; } buff[i] = strstr(at, "stopTemp")[7+i]; } Serial.println(buff); } }нет команд настройки режима обмена CIPQSEND CIPMODE
нет команды закрытия сессии CIPSHUT
рекомендую все таки сообщать модему сколько будет отправлено байт в команде CIPSEND, а не слать в конце байт 26, это во первых надежнее, во вторых если у вас в передаче будет этот байт - все сломается
Читать до просветления:
http://forum.cxem.net/index.php?/topic/195209-%D0%BD%D0%B0%D1%81%D1%82%D...
http://arduino.ru/forum/programmirovanie/snova-mqtt-1#comment-411540
Вот старенький пример, комментариев нет, функционал - ранняя версия, только отправка и то с одним неприятным косяком.
#include <avr/wdt.h> #include <avr\pgmspace.h> #include "s800str.h" #define USE_UART_LOG 1 // 1 if use HW Serial as Log #include <SoftwareSerial.h> SoftwareSerial gsm(GSM_TX, GSM_RX); // установка контактовGSM_TX->RX и GSM_RX->TX для программного порта byte modem_step = 100; // current work mode mode in table of command // static steps: // 100 - delay 15 sec for registration modem in net // 101 - not wait response, wait incomming call or other commands // 102 - show info on display by press key and/or sleep modem unsigned long current_millis; // main timer #define period_fixed_wait 30000UL // max time wait response unsigned long timer_reg_modem = 0; // timer registration modem in net and timer response char resp_buf[maxSizeResponse]; // response buf from modem byte pos_buf = 0; // current pos response buf #define max_resp_count_on_one_type_cmd 5 // max 5 response text by one command and one type byte fl_true_Rresp[max_resp_count_on_one_type_cmd]; char text_Rresp[max_resp_count_on_one_type_cmd][maxSizeResponse]; byte fl_true_Oresp[max_resp_count_on_one_type_cmd]; char text_Oresp[max_resp_count_on_one_type_cmd][maxSizeResponse]; byte startFlag = 1; byte rresp, oresp; byte ussdStep = 0; #define max_size_operator_name 10 char operator_name[max_size_operator_name]; char mqtt_user[] = "********"; // Логи от сервер char mqtt_pass[] = "***********"; // Пароль от сервера char mqtt_device[] = "AndycatTest41"; char mqtt_topic_gps_longitude[] = "/gps_l"; // долгота char mqtt_topic_gps_breadth[] = "/gps_b"; // широта #define max_size_gps_string 0x20 char data_gps_longitude[max_size_gps_string]; // долгота char data_gps_breadth[max_size_gps_string]; // широта byte mqtt_mode = 0; // 0 - connect mqtt server // 1 - send data // 2 - disconnect from server #define period_send_connect_mqtt 600000UL // connect/disconnect mqtt server unsigned long timer_send_connect_mqtt = 580000UL; #define period_send_gps_data 2000UL // send data unsigned long timer_send_gps_data = 0; uint8_t mcusr_mirror __attribute__ ((section (".noinit"))); void get_mcusr(void) \ __attribute__((naked)) \ __attribute__((used)) \ __attribute__((section(".init3"))); void get_mcusr(void) { mcusr_mirror = MCUSR; MCUSR = 0; wdt_disable(); } void setup() { MCUSR = 0; wdt_disable(); #if (USE_UART_LOG == 1) Serial.begin(115200); Serial.println("Power ON or WDT reset"); #endif gsm.begin(9600); pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); pinMode(reset_sim800_pin, INPUT); digitalWrite(reset_sim800_pin, LOW); pinMode(dtr_sim800_pin, OUTPUT); digitalWrite(dtr_sim800_pin, LOW); // normal mode modem pinMode(ledRed_pin, OUTPUT); pinMode(ledGre_pin, OUTPUT); LEDREDOFF; LEDGREOFF; operator_name[0] = 0; wdt_enable(WDTO_8S); } void loop() { wdt_reset(); //delay(9000); // test WDT current_millis = millis(); if (((current_millis - timer_send_connect_mqtt) >= period_send_connect_mqtt) && (modem_step == 101) && (!startFlag)) { switch (mqtt_mode) { case 0: { timer_send_connect_mqtt = current_millis; modem_step = 32; sendATcmd(); break; } case 1: { mqtt_mode = 2; modem_step = 42; sendATcmd(); break; } case 2: { modem_step = 45; sendATcmd(); break; } default: {} } } if (((current_millis - timer_send_gps_data) >= period_send_gps_data) && (modem_step == 101) && (!startFlag) && (mqtt_mode == 1)) { timer_send_gps_data = current_millis; // gps data TO text data_gps_longitude[0] = random(0, 10) + '0'; data_gps_longitude[1] = 0; data_gps_breadth[0] = '9'; data_gps_breadth[1] = random(0, 10) + '0'; data_gps_breadth[2] = 0; // send data modem_step = 42; sendATcmd(); } if (modem_step == 100) { LEDGREOFF; if ((current_millis - timer_reg_modem) >= 15000UL) { // wait 15 sec registration modem modem_step = 0; sendATcmd(); } } else if (modem_step == 101) { LEDGREOFF; if (startFlag) { LEDREDOFF; startFlag = 0; #if (USE_UART_LOG == 1) Serial.println("Ready"); #endif digitalWrite(LED_BUILTIN, HIGH); } // nothing do loadDataFromModem(); } else if (modem_step < 100) { LEDGREON; if ((rresp == 0) && (oresp == 0)) { // go to next cmd modem_step = s800getNextStepCmdByNum(modem_step); if (modem_step < 100) sendATcmd(); } else { if ((current_millis - timer_reg_modem) >= period_fixed_wait) { if (rresp > 0) { resetModem(); } else if (oresp > 0) { // go to next cmd modem_step = s800getNextStepCmdByNum(modem_step); if (modem_step < 100) sendATcmd(); } } else { // main work loadDataFromModem(); } } } } byte doCmdForModem(byte inByte) { byte flGood, flResp; if (modem_step < 100) { if (rresp > 0) { flGood = 0; flResp = 0; for (byte i = 0; i < rresp; ++i) { if (fl_true_Rresp[i] == 0) { if (findRespFromBuf(text_Rresp[i])) { fl_true_Rresp[i] = 1; if ((rresp == 1) || (i == (rresp - 1))) flGood = 1; flResp = 1; } break; } } if (flGood) { // manual processing response for good cmd switch (modem_step) { case 43: { // connected to mqtt server if (mqtt_mode == 0)mqtt_mode = 1; break; } case 44: { // re connect to mqtt server mqtt_mode = 0; break; } default: {} } // go to next cmd modem_step = s800getNextStepCmdByNum(modem_step); if (modem_step < 100) sendATcmd(); return 1; } if (flResp) { clearRespBuf(); return 1; } } // manual processing response switch (modem_step) { case 24: { // operator name if (inByte == '+') { ussdStep = 1; operator_name[0] = 0; } else if ((ussdStep == 1) && (inByte == '"')) { ussdStep = 2; } else if (ussdStep == 2) { if (inByte == '"') { ussdStep = 3; } else { byte sl = strlen(operator_name); if (sl < (max_size_operator_name - 1)) { operator_name[sl] = inByte; operator_name[sl + 1] = 0; } } } break; } default: {} } } else { // mode 101 // find ring or other cmd } return 0; } byte findRespFromBuf(char* textResp) { if (resp_buf[pos_buf] > 0) { byte idxBuf; if (pos_buf == 0) idxBuf = maxSizeResponse - 1; else idxBuf = pos_buf - 1; byte lenResp = strlen(textResp); byte idxResp = lenResp - 1; byte cntResp = 0; for (byte i = 0; i < maxSizeResponse; ++i) { if (resp_buf[idxBuf] == 0) break; if (resp_buf[idxBuf] == textResp[idxResp]) { --idxResp; if ((++cntResp) == lenResp) return 1; } else { cntResp = 0; idxResp = lenResp - 1; } if ((--idxBuf) == 0) idxBuf = maxSizeResponse - 1; } } else if (pos_buf > 0) { if (strPos(resp_buf, textResp) >= 0) { return 1; } } return 0; } void sendATcmd() { char cmdAT[maxSizeATcommand]; s800getTextCmdByNum(modem_step, cmdAT); switch (modem_step) { // manual processing AT cmd case 42: { gsm.print(cmdAT); #if (USE_UART_LOG == 1) Serial.print(cmdAT); #endif byte fullSize = getSizeMqttPacket(); gsm.print(fullSize, DEC); gsm.print("\r\n"); #if (USE_UART_LOG == 1) Serial.println(fullSize, DEC); #endif break; } case 43: { sendMqttPacket(); #if (USE_UART_LOG == 1) Serial.println(""); #endif break; } default: { gsm.print(cmdAT); #if (USE_UART_LOG == 1) Serial.print(cmdAT); #endif } } timer_reg_modem = current_millis; rresp = s800getCountRrespCmdByNum(modem_step); oresp = s800getCountOrespCmdByNum(modem_step); for (byte i = 0; i < max_resp_count_on_one_type_cmd; ++i) { fl_true_Rresp[i] = 0; // max 5 response text by one command and one type fl_true_Oresp[i] = 0; } if (rresp) { for (byte i = 0; i < rresp; ++i) { s800getRespByNum(0, modem_step, i, text_Rresp[i]); } } if (oresp) { for (byte i = 0; i < oresp; ++i) { s800getRespByNum(1, modem_step, i, text_Oresp[i]); } } clearRespBuf(); } void clearRespBuf() { memset(resp_buf, 0, maxSizeResponse); pos_buf = 0; } void loadDataFromModem() { if (gsm.available()) { while (gsm.available()) { byte readByte = gsm.read(); if (readByte > 0) { #if (USE_UART_LOG == 1) if ((modem_step != 3) && (modem_step != 28) && (modem_step != 21)) Serial.write(readByte); #endif resp_buf[pos_buf] = readByte; ++pos_buf; if (pos_buf >= maxSizeResponse) pos_buf = 0; wdt_reset(); if (doCmdForModem(readByte) == 1) break; } } } } void resetModem() { LEDREDON; // reset modem pinMode(reset_sim800_pin, OUTPUT); digitalWrite(reset_sim800_pin, LOW); delay(115); pinMode(reset_sim800_pin, INPUT); digitalWrite(reset_sim800_pin, LOW); // new init modem and start new main loop timer_reg_modem = current_millis; modem_step = 100; startFlag = 1; operator_name[0] = 0; mqtt_mode = 0; timer_send_connect_mqtt = 580000UL; } byte sendConnectPacket(byte getSize) { byte sizeDevice = strlen(mqtt_device); byte sizeUser = strlen(mqtt_user); byte sizePass = strlen(mqtt_pass); byte fullSize = 16 + sizeDevice + sizeUser + sizePass; if (getSize) return (fullSize + 2); // fixed header sendByteToMQTTclient((byte)0x10); // MQTT Control Packet type 0001 connect, reserved 0000 sendByteToMQTTclient((byte)(fullSize)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload. // Variable header sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)0x04); // Length LSB (4) sendByteToMQTTclient((byte)'M'); sendByteToMQTTclient((byte)'Q'); sendByteToMQTTclient((byte)'T'); sendByteToMQTTclient((byte)'T'); // protocol name sendByteToMQTTclient((byte)0x04); // Protocol Level byte sendByteToMQTTclient((byte)0xC0); // Connect Flag bits, login and pass enable sendByteToMQTTclient((byte)0x00); // Keep Alive MSB (0) sendByteToMQTTclient((byte)0x28); // Keep Alive LSB (10) - 40 sec // payload sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)sizeDevice); // Length LSB (4) - device for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i])); sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)sizeUser); // Length LSB (4) - user for (byte i = 0; i < sizeUser; ++i) sendByteToMQTTclient((byte)(mqtt_user[i])); sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)sizePass); // Length LSB (4) - pass for (byte i = 0; i < sizePass; ++i) sendByteToMQTTclient((byte)(mqtt_pass[i])); } void sendByteToMQTTclient(byte inByte) { gsm.write((byte)(inByte)); #if (USE_UART_LOG == 1) if ((inByte < 0x20) || (inByte >= 0x7F)) { Serial.print(" 0x"); Serial.print(inByte, HEX); Serial.print(" "); } else { Serial.write(inByte); } #endif } byte sendGPSlData(byte getSize) { byte sizeDevice = strlen(mqtt_device); byte sizeTopic = strlen(mqtt_topic_gps_longitude); byte sizeData = strlen(data_gps_longitude); byte fullSize = 4 + sizeDevice + sizeTopic + sizeData; if (getSize) return (fullSize + 2); // fixed header sendByteToMQTTclient((byte)0x31); // MQTT Control Packet type 0011, DUP QoS Retain 0000 flags sendByteToMQTTclient((byte)(fullSize)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload. // Variable header sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)(sizeDevice + sizeTopic)); // Length LSB (4) for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i])); for (byte i = 0; i < sizeTopic; ++i) sendByteToMQTTclient((byte)(mqtt_topic_gps_longitude[i])); sendByteToMQTTclient((byte)0x00); // Packet Identifier MSB (0) sendByteToMQTTclient((byte)0x00); // Packet Identifier LSB (10) // payload for (byte i = 0; i < sizeData; ++i) sendByteToMQTTclient((byte)(data_gps_longitude[i])); } byte sendGPSbData(byte getSize) { byte sizeDevice = strlen(mqtt_device); byte sizeTopic = strlen(mqtt_topic_gps_breadth); byte sizeData = strlen(data_gps_breadth); byte fullSize = 4 + sizeDevice + sizeTopic + sizeData; if (getSize) return (fullSize + 2); // fixed header sendByteToMQTTclient((byte)0x31); // MQTT Control Packet type 0011, DUP QoS Retain 0000 flags sendByteToMQTTclient((byte)(fullSize)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload. // Variable header sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)(sizeDevice + sizeTopic)); // Length LSB (4) for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i])); for (byte i = 0; i < sizeTopic; ++i) sendByteToMQTTclient((byte)(mqtt_topic_gps_breadth[i])); sendByteToMQTTclient((byte)0x00); // Packet Identifier MSB (0) sendByteToMQTTclient((byte)0x00); // Packet Identifier LSB (10) // payload for (byte i = 0; i < sizeData; ++i) sendByteToMQTTclient((byte)(data_gps_breadth[i])); } void sendDisConnectPacket() { // fixed header sendByteToMQTTclient((byte)0xE0); // MQTT Control Packet type 1110 connect, reserved 0000 sendByteToMQTTclient((byte)0x00); // Remaining Length } byte getSizeMqttPacket() { switch (mqtt_mode) { case 0 : { return sendConnectPacket(1); } case 1 : { byte fullSize = sendGPSlData(1); fullSize += sendGPSbData(1); return fullSize; } case 2 : { return 2; } default: {} } } void sendMqttPacket() { switch (mqtt_mode) { case 0 : { sendConnectPacket(0); break; } case 1 : { sendGPSlData(0); sendGPSbData(0); break; } case 2 : { sendDisConnectPacket(); break; } default: {} } } //--s800str.h-- #include <avr\pgmspace.h> #define maxSizeATcommand 60 #define maxSizeResponse 24 const char at0cmdAT[] PROGMEM = "AT\r\n"; const char at1cmdHTTPACTION[] PROGMEM = "AT+HTTPACTION=0\r\n"; const char at1rsp1[] PROGMEM = "+HTTPACTION:"; const char at1rsp2[] PROGMEM = ","; const char at2cmdSAPBR11[] PROGMEM = "AT+SAPBR=1,1\r\n"; const char at2rsp1[] PROGMEM = "operation not allowed\r\n"; const char at3cmdREADSMS[] PROGMEM = "AT+CMGL=4\r\n"; // "AT+CMGL=\"ALL\"\r\n"; const char at4cmdDDET[] PROGMEM = "AT+DDET=1\r\n"; const char at5cmdATE0[] PROGMEM = "ATE0\r\n"; const char at6cmdCLIP1[] PROGMEM = "AT+CLIP=1\r\n"; const char at7cmdATS0[] PROGMEM = "ATS0=0\r\n"; const char at8cmdATV1[] PROGMEM = "ATV1\r\n"; const char at9cmdATCMEE2[] PROGMEM = "AT+CMEE=2\r\n"; const char at10cmdATCMGF1[] PROGMEM = "AT+CMGF=0\r\n"; const char at11cmdATCREG[] PROGMEM = "AT+CREG?\r\n"; const char at11rsp1[] PROGMEM = "+CREG:"; const char at11rsp2[] PROGMEM = ",1\r\n"; const char at12cmdDELSMS[] PROGMEM = "AT+CMGDA=6\r\n"; // "AT+CMGDA=\"DEL ALL\"\r\n"; const char at13cmdSAPBR311[] PROGMEM = "AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"\r\n"; const char at14cmdSAPBR312[] PROGMEM = "AT+SAPBR=3,1,\"APN\",\"internet\"\r\n"; const char at15cmdSAPBR313[] PROGMEM = "AT+SAPBR=3,1,\"USER\",\"\"\r\n"; const char at16cmdSAPBR314[] PROGMEM = "AT+SAPBR=3,1,\"PWD\",\"\"\r\n"; const char at17cmdSAPBR21[] PROGMEM = "AT+SAPBR=2,1\r\n"; const char at17rsp1[] PROGMEM = "+SAPBR:"; const char at17rsp2[] PROGMEM = ",1,\""; const char at18cmdHTTPINIT[] PROGMEM = "AT+HTTPINIT\r\n"; const char at19cmdHTTPCID[] PROGMEM = "AT+HTTPPARA=\"CID\",1\r\n"; const char at20cmdHTTPURL[] PROGMEM = "AT+HTTPPARA=\"URL\",\"arduino.ru\"\r\n"; const char at21cmdHTTPREAD[] PROGMEM = "AT+HTTPREAD\r\n"; const char at22cmdHTTPTERM[] PROGMEM = "AT+HTTPTERM\r\n"; const char at23cmdCSCLK1[] PROGMEM = "AT+CSCLK=1\r\n"; // =1 if use DTR pin modem const char at24cmdGETOPS[] PROGMEM = "AT+COPS?\r\n"; // get operator const char at25cmdCSQ[] PROGMEM = "AT+CSQ\r\n"; // get net const char at26cmdCMGS[] PROGMEM = "AT+CMGS="; // begin send sms const char at26rsp1[] PROGMEM = ">"; // begin send sms const char at27cmdCMGS[] PROGMEM = "none"; // text sms const char at27rsp1[] PROGMEM = "+CMGS:"; // text sms const char at28cmdBALMEG[] PROGMEM = "AT+CUSD=1,\"*100#\"\r\n"; // get balance megafon const char at28rsp1[] PROGMEM = "+CUSD:"; const char at28rsp2[] PROGMEM = ", 72\r\n"; // init new gprs packet const char at29cmdCGATT[] PROGMEM = "AT+CGATT?\r\n"; const char at29rsp1[] PROGMEM = "+CGATT: 1\r\n"; const char at30cmdCIPMODE[] PROGMEM = "AT+CIPMODE=0\r\n"; const char at31cmdCIPMUX[] PROGMEM = "AT+CIPMUX=0\r\n"; // set context and open connect const char at32cmdCIPSTATUS[] PROGMEM = "AT+CIPSTATUS\r\n"; const char at32rsp1[] PROGMEM = "IP INITIAL\r\n"; const char at33cmdCSTT[] PROGMEM = "AT+CSTT=\"internet\"\r\n"; const char at32rsp2[] PROGMEM = "IP START\r\n"; /*34*/ const char at35cmdCIICR[] PROGMEM = "AT+CIICR\r\n"; const char at32rsp3[] PROGMEM = "IP GPRSACT\r\n"; /*36*/ const char at37cmdCIFSR[] PROGMEM = "AT+CIFSR\r\n"; const char at32rsp4[] PROGMEM = "IP STATUS\r\n"; /*38*/ const char at39cmdCIPSTART[] PROGMEM = "AT+CIPSTART=\"TCP\",\"m23.cloudmqtt.com\",15069\r\n"; const char at39rsp1[] PROGMEM = "CONNECT OK\r\n"; const char at32rsp5[] PROGMEM = "STATE: CONNECT OK\r\n"; /*40*/ // send data to server const char at41cmdCIPQSEND[] PROGMEM = "AT+CIPQSEND=1\r\n"; const char at42cmdCIPSEND[] PROGMEM = "AT+CIPSEND="; const char at42rsp1[] PROGMEM = ">"; const char at43cmdNull[] PROGMEM = "\r\n"; const char at43rsp1[] PROGMEM = "DATA ACCEPT:"; const char at43rsp2[] PROGMEM = "CLOSED\r\n"; const char at44cmdCIPQSEND0[] PROGMEM = "AT+CIPQSEND=0\r\n"; const char at45cmdCIPCLOSE[] PROGMEM = "AT+CIPCLOSE\r\n"; const char at45rsp1[] PROGMEM = "CLOSE OK\r\n"; const char at46cmdCIPSHUT[] PROGMEM = "AT+CIPSHUT\r\n"; const char at46rsp1[] PROGMEM = "SHUT OK\r\n"; // typical response const char rspOK[] PROGMEM = "OK\r\n"; const char rspEndLine[] PROGMEM = "\r\n"; const char * const at_list_cmd[] PROGMEM = { // text command at0cmdAT, at1cmdHTTPACTION, at2cmdSAPBR11, at3cmdREADSMS, at4cmdDDET, at5cmdATE0, at6cmdCLIP1, at7cmdATS0, at8cmdATV1, at9cmdATCMEE2, at10cmdATCMGF1, at11cmdATCREG, at12cmdDELSMS, at13cmdSAPBR311, at14cmdSAPBR312, at15cmdSAPBR313, at16cmdSAPBR314, at17cmdSAPBR21, at18cmdHTTPINIT, at19cmdHTTPCID, at20cmdHTTPURL, at21cmdHTTPREAD, at22cmdHTTPTERM, at23cmdCSCLK1, at24cmdGETOPS, at25cmdCSQ, at26cmdCMGS, at27cmdCMGS, at28cmdBALMEG, at29cmdCGATT, at30cmdCIPMODE, at31cmdCIPMUX, at32cmdCIPSTATUS, at33cmdCSTT, at32cmdCIPSTATUS /*34*/, at35cmdCIICR, at32cmdCIPSTATUS /*36*/, at37cmdCIFSR, at32cmdCIPSTATUS /*38*/, at39cmdCIPSTART, at32cmdCIPSTATUS /*40*/, at41cmdCIPQSEND, at42cmdCIPSEND, at43cmdNull, at44cmdCIPQSEND0, at45cmdCIPCLOSE, at46cmdCIPSHUT }; const PROGMEM uint8_t at_rresp_cmd[] = { // 0-count right response 1, 4, 0, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 1, 2, 2, 1, 1, 1 }; const PROGMEM uint8_t at_oresp_cmd[] = { // 1-count other response - need manual action by response 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; const PROGMEM uint8_t at_move_cmd[] = { // step after action cmd 4, 21, 17, 12, 5, 6, 7, 8, 9, 10, 11, 13, 101, 14, 15, 16, 23, 18, 19, 20, 1, 22, 101, 24, 29, 101, 27, 101, 101, 30, 31, 101, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 101, 101, 46, 44 }; const char * const at_list_rresp[] PROGMEM = { rspOK, // at0 rspOK, at1rsp1, at1rsp2, rspEndLine, // at1 rspOK, // at3 rspOK, // at4 rspOK, // at5 rspOK, // at6 rspOK, // at7 rspOK, // at8 rspOK, // at9 rspOK, // at10 at11rsp1, at11rsp2, rspOK, // at11 rspOK, // at12 rspOK, // at13 rspOK, // at14 rspOK, // at15 rspOK, // at16 at17rsp1, at17rsp2, rspOK, // at17 rspOK, // at18 rspOK, // at19 rspOK, // at20 rspOK, // at21 rspOK, // at22 rspOK, // at23 rspOK, // at24 rspOK, // at25 at26rsp1, // at26 at27rsp1, rspOK, // at27 rspOK, at28rsp1, at28rsp2, // at28 at29rsp1, rspOK, // at29 rspOK, // at30 rspOK, // at31 rspOK, at32rsp1, // at32 rspOK, // at33 rspOK, at32rsp2, // at34 rspOK, // at35 rspOK, at32rsp3, // at36 rspEndLine, // at37 rspOK, at32rsp4, // at38 rspOK, at39rsp1, // at39 rspOK, at32rsp5, // at40 rspOK, // at41 rspEndLine, at42rsp1, // at42 at43rsp1, rspEndLine, // at43 rspOK, // at44 at45rsp1, // at45 at46rsp1 // at46 }; const char * const at_list_oresp[] PROGMEM = { rspOK, at2rsp1 // at2 }; void s800getTextCmdByNum(byte numCmd, char* textCmd); byte s800getCountRrespCmdByNum(byte numCmd); byte s800getCountOrespCmdByNum(byte numCmd); void s800getRespByNum(byte typeResp, byte numCmd, byte numResp, char* textCmd); byte s800getNextStepCmdByNum(byte numCmd); #define GSM_RX 3 // пин RX на модуле подключаем к указаному пину на Ардуино TX #define GSM_TX 2 // пин TX на модуле подключаем к указаному пину на Ардуино RX #define WORK_LEVEL_LED 0 // 1 if HIGH level ON led, else 0 #define reset_sim800_pin 4 // pin for reset modem #define dtr_sim800_pin 10 // pin DTR for sleep mode #define ledRed_pin 7 // pin RED led #define ledGre_pin 8 // pin GREEN led #if (WORK_LEVEL_LED == 0) #define LEDREDON digitalWrite(ledRed_pin,LOW) #define LEDGREON digitalWrite(ledGre_pin,LOW) #define LEDREDOFF digitalWrite(ledRed_pin,HIGH) #define LEDGREOFF digitalWrite(ledGre_pin,HIGH) #else #define LEDREDON digitalWrite(ledRed_pin,HIGH) #define LEDGREON digitalWrite(ledGre_pin,HIGH) #define LEDREDOFF digitalWrite(ledRed_pin,LOW) #define LEDGREOFF digitalWrite(ledGre_pin,LOW) #endif char* LastPos(char *str1, char *str2); int strPos(char *str11, char *str22); //--s800str.cpp-- #include "Arduino.h" #include "s800str.h" void s800getTextCmdByNum(byte numCmd, char* textCmd) { const char * addrStroki = pgm_read_word_near((int)(at_list_cmd + numCmd)); strcpy_P(textCmd, addrStroki); } byte s800getCountRrespCmdByNum(byte numCmd) { return pgm_read_byte_near(at_rresp_cmd + numCmd); } byte s800getCountOrespCmdByNum(byte numCmd) { return pgm_read_byte_near(at_oresp_cmd + numCmd); } byte s800getNextStepCmdByNum(byte numCmd) { return pgm_read_byte_near(at_move_cmd + numCmd); } void s800getRespByNum(byte typeResp, byte numCmd, byte numResp, char* textCmd) { byte startPos = 0; if (numCmd > 0) for (byte i = 1; i <= numCmd; ++i) { switch (typeResp) { case 0: { startPos += pgm_read_byte_near(at_rresp_cmd + i - 1); break; } case 1: { startPos += pgm_read_byte_near(at_oresp_cmd + i - 1); break; } default : {} } } switch (typeResp) { case 0: { const char * addrStroki = pgm_read_word_near((int)(at_list_rresp + startPos + numResp)); strcpy_P(textCmd, addrStroki); break; } case 1: { const char * addrStroki = pgm_read_word_near((int)(at_list_oresp + startPos + numResp)); strcpy_P(textCmd, addrStroki); break; } default : {} } } char* LastPos(char *str1, char *str2) { // find substring in string int L1 = strlen(str1); int L2 = strlen(str2); for (int i = L1 - L2; i >= 0; i--) { int j = 0; for (; j < L2; j++) if ((str1[i + j] != str2[j])) break; if (j == L2) return str1 + i; } return 0; } int strPos(char *str11, char *str22) { // find position in string(1) substring(2) char*p = LastPos(str11, str22); int n = p - str11; return n; }Вобщем опять работает, отвечает как положено 0xD0 0x00. От чего завист и какого чёрта надо серверу - закономерности без бутылки не нашёл. Просто раз несколько переконнектился и заработало.
.
А че их искать - cipshut добавили? Похоже что нет, естественно он будет несколько раз пытаться запустить новую сессию не закрыв старую, в итоге по таймауту все сбрасывается и опять работает.
ЗЫ. Вот поэтому у нас и ракеты падают и заказчики скетч не могут запустить и т.д. - потому что разработчик сказал "и так сойдёт, ведь законнектилось в итоге" (
А причём здесь вообще cipshut ?? Сервер соединение рвёт при отправке пинга. Вы вообще здесь, в теме?
Тьфу...блин, разбирайтесь сами, я в теме, у меня мой код по вышеперечисленным книжкам работает исправно, а вы вместо того чтоб прислушаться и хоть чуть попытаться изменить свой скетч только и делайте что троллите.
код для этого примера
http://arduino.ru/forum/programmirovanie/snova-mqtt-1#comment-411540
#include <avr/wdt.h> #include <avr\pgmspace.h> #include "s800str.h" #define USE_UART_LOG 1 // 1 if use HW Serial as Log #include <SoftwareSerial.h> SoftwareSerial gsm(GSM_TX, GSM_RX); // установка контактовGSM_TX->RX и GSM_RX->TX для программного порта byte modem_step = 100; // current work mode mode in table of command // static steps: // 100 - delay 15 sec for registration modem in net // 101 - not wait response, wait incomming call or other commands // 102 - show info on display by press key and/or sleep modem unsigned long current_millis; // main timer #define period_fixed_wait 10000UL // max time wait response unsigned long timer_reg_modem = 0; // timer registration modem in net and timer response char resp_buf[maxSizeResponse]; // response buf from modem byte pos_buf = 0; // current pos response buf #define max_resp_count_on_one_type_cmd 5 // max 5 response text by one command and one type byte fl_true_Rresp[max_resp_count_on_one_type_cmd]; char text_Rresp[max_resp_count_on_one_type_cmd][maxSizeResponse]; byte fl_true_Oresp[max_resp_count_on_one_type_cmd]; char text_Oresp[max_resp_count_on_one_type_cmd][maxSizeResponse]; byte startFlag = 1; byte rresp, oresp; byte ussdStep = 0; #define max_size_operator_name 10 char operator_name[max_size_operator_name]; char mqtt_user[] = "*******"; // Логи от сервер char mqtt_pass[] = "***********"; // Пароль от сервера char mqtt_device[] = "AT41"; char mqtt_topic_gps_longitude[] = "/gps_l"; // долгота char mqtt_topic_gps_breadth[] = "/gps_b"; // широта char mqtt_topic_key[] = "/key"; char mqtt_topic_vin[] = "/vin"; char mqtt_topic_temp[] = "/temp"; char mqtt_topic_uptime[] = "/uptime"; #define max_size_gps_string 0x20 char data_gps_longitude[max_size_gps_string]; // долгота char data_gps_breadth[max_size_gps_string]; // широта char find_str1[max_size_gps_string]; char find_str2[max_size_gps_string]; byte found_key1_status; byte mqtt_mode = 0; #define period_send_gps_data 60000UL // minimum 10sec = 10000UL for slow mqtt server unsigned long timer_send_gps_data = 0; byte time_live_connect_packet = period_send_gps_data / 1000; unsigned long timer_uptime = 0; word modemVin = 999; float Vdel = 0.096; // R2/(R1+R2) 0.99кОм / (9.88кОм + 0.99кОм) #define period_read_vin 61791UL // read vin modem unsigned long timer_read_vin = 0; // get modem power level #include <OneWire.h> #define ds_pin A0 // pin DS18B20 OneWire ds18b20(ds_pin); #define errTemp 1111 // it is error value word currTemp = errTemp; #define period_get_temp 137298UL unsigned long timer_get_temp = 0; byte reqTemp = 0; uint8_t mcusr_mirror __attribute__ ((section (".noinit"))); void get_mcusr(void) \ __attribute__((naked)) \ __attribute__((used)) \ __attribute__((section(".init3"))); void get_mcusr(void) { mcusr_mirror = MCUSR; MCUSR = 0; wdt_disable(); } void setup() { MCUSR = 0; wdt_disable(); #if (USE_UART_LOG == 1) Serial.begin(115200); Serial.println("Power ON or WDT reset"); #endif gsm.begin(9600); pinMode(LED_BUILTIN, OUTPUT); digitalWrite(LED_BUILTIN, LOW); pinMode(reset_sim800_pin, INPUT); digitalWrite(reset_sim800_pin, LOW); pinMode(dtr_sim800_pin, OUTPUT); digitalWrite(dtr_sim800_pin, LOW); // normal mode modem randomSeed(analogRead(A2)); analogReference(INTERNAL); getVinModem(); pinMode(ledRed_pin, OUTPUT); pinMode(ledGre_pin, OUTPUT); pinMode(ledBlu_pin, OUTPUT); found_key1_status = 0; LEDREDOFF; LEDGREOFF; LEDBLUOFF; operator_name[0] = 0; wdt_enable(WDTO_8S); } void loop() { wdt_reset(); //delay(9000); // test WDT current_millis = millis(); if (((current_millis - timer_send_gps_data) >= period_send_gps_data) && (modem_step == 101) && (!startFlag)) { if (mqtt_mode) { modem_step = 44; sendATcmd(); } else { timer_send_gps_data = current_millis; strcpy(find_str1, mqtt_topic_key); strcat(find_str1, "5"); strcpy(find_str2, mqtt_topic_key); strcat(find_str2, "7"); // gps data TO text data_gps_longitude[0] = random(0, 10) + '0'; data_gps_longitude[1] = 0; data_gps_breadth[0] = '9'; data_gps_breadth[1] = random(0, 10) + '0'; data_gps_breadth[2] = 0; // send data modem_step = 32; sendATcmd(); } } if (((current_millis - timer_get_temp) >= period_get_temp) && (modem_step == 101)) { if (reqTemp) { if ((current_millis - timer_get_temp) >= (period_get_temp + 750UL)) { if ((current_millis - timer_get_temp) <= (period_get_temp + 1000UL)) { currTemp = getTemp2(); #if (USE_UART_LOG == 1) Serial.println(currTemp); #endif } timer_get_temp = current_millis; reqTemp = 0; } } else { getTemp1(); reqTemp = 1; } } if (((current_millis - timer_read_vin) >= period_read_vin) && (modem_step == 101)) { timer_read_vin = current_millis; getVinModem(); #if (USE_UART_LOG == 1) Serial.println(modemVin); #endif } if (modem_step == 100) { LEDGREOFF; if ((current_millis - timer_reg_modem) >= 15000UL) { // wait 15 sec registration modem modem_step = 0; sendATcmd(); } } else if (modem_step == 101) { LEDGREOFF; if (startFlag) { LEDREDOFF; startFlag = 0; #if (USE_UART_LOG == 1) Serial.println("Ready"); #endif digitalWrite(LED_BUILTIN, HIGH); } // nothing do loadDataFromModem(); } else if (modem_step < 100) { LEDGREON; if ((rresp == 0) && (oresp == 0)) { // go to next cmd modem_step = s800getNextStepCmdByNum(modem_step); if (modem_step < 100) sendATcmd(); } else { if ((current_millis - timer_reg_modem) >= period_fixed_wait) { if (rresp > 0) { resetModem(); } else if (oresp > 0) { // go to next cmd #if (USE_UART_LOG == 1) Serial.println("No response!"); #endif if (modem_step == 43) { timer_send_gps_data = 0; mqtt_mode = 0; modem_step = 44; sendATcmd(); } else { modem_step = s800getNextStepCmdByNum(modem_step); if (modem_step < 100) sendATcmd(); } } } else { // main work loadDataFromModem(); } } } } byte doCmdForModem(byte inByte) { // processing/find key packets if (findRespFromBuf(find_str1)) { if (!found_key1_status) { #if (USE_UART_LOG == 1) Serial.println("Key ON"); #endif LEDBLUON; found_key1_status = 1; } } else if (findRespFromBuf(find_str2)) { if (found_key1_status) { #if (USE_UART_LOG == 1) Serial.println("Key OFF"); #endif LEDBLUOFF; found_key1_status = 0; } } // -- byte flGood, flResp; if (modem_step < 100) { if (rresp > 0) { flGood = 0; flResp = 0; for (byte i = 0; i < rresp; ++i) { if (fl_true_Rresp[i] == 0) { if (findRespFromBuf(text_Rresp[i])) { fl_true_Rresp[i] = 1; if ((rresp == 1) || (i == (rresp - 1))) flGood = 1; flResp = 1; } break; } } if (flGood) { // manual processing response for good cmd switch (modem_step) { case 43: { mqtt_mode = 1; break; } case 44: { mqtt_mode = 0; break; } default: {} } // go to next cmd modem_step = s800getNextStepCmdByNum(modem_step); if (modem_step < 100) sendATcmd(); return 1; } if (flResp) { clearRespBuf(); return 1; } } // manual processing response switch (modem_step) { case 43: { // send data // find end TX if (findRespFromBuf("SEND OK\r\n")) { mqtt_mode = 1; // go to next cmd modem_step = s800getNextStepCmdByNum(modem_step); if (modem_step < 100) sendATcmd(); return 1; } break; } case 24: { // operator name if (inByte == '+') { ussdStep = 1; operator_name[0] = 0; } else if ((ussdStep == 1) && (inByte == '"')) { ussdStep = 2; } else if (ussdStep == 2) { if (inByte == '"') { ussdStep = 3; } else { byte sl = strlen(operator_name); if (sl < (max_size_operator_name - 1)) { operator_name[sl] = inByte; operator_name[sl + 1] = 0; } } } break; } default: {} } } else { // mode 101 // find ring or other cmd } return 0; } byte findRespFromBuf(char* textResp) { if (resp_buf[pos_buf] > 0) { byte idxBuf; if (pos_buf == 0) idxBuf = maxSizeResponse - 1; else idxBuf = pos_buf - 1; byte lenResp = strlen(textResp); byte idxResp = lenResp - 1; byte cntResp = 0; for (byte i = 0; i < maxSizeResponse; ++i) { if (resp_buf[idxBuf] == 0) break; if (resp_buf[idxBuf] == textResp[idxResp]) { --idxResp; if ((++cntResp) == lenResp) return 1; } else { cntResp = 0; idxResp = lenResp - 1; } if ((--idxBuf) == 0) idxBuf = maxSizeResponse - 1; } } else if (pos_buf > 0) { if (strPos(resp_buf, textResp) >= 0) { return 1; } } return 0; } void sendATcmd() { char cmdAT[maxSizeATcommand]; s800getTextCmdByNum(modem_step, cmdAT); switch (modem_step) { // manual processing AT cmd case 42: { gsm.print(cmdAT); #if (USE_UART_LOG == 1) Serial.print(cmdAT); #endif byte fullSize = sendConnectPacket(1); fullSize += sendGPSlData(1); fullSize += sendGPSbData(1); fullSize += sendSubscribeKey(1); fullSize += sendPubTemp(1); fullSize += sendPubVin(1); fullSize += sendPubUptime(1); //fullSize += 2; // + disconnect packet gsm.print(fullSize, DEC); gsm.print("\r\n"); #if (USE_UART_LOG == 1) Serial.println(fullSize, DEC); #endif break; } case 43: { sendConnectPacket(0); #if (USE_UART_LOG == 1) Serial.println(""); #endif sendSubscribeKey(0); #if (USE_UART_LOG == 1) Serial.println(""); #endif sendGPSlData(0); #if (USE_UART_LOG == 1) Serial.println(""); #endif sendGPSbData(0); #if (USE_UART_LOG == 1) Serial.println(""); #endif sendPubTemp(0); #if (USE_UART_LOG == 1) Serial.println(""); #endif sendPubVin(0); #if (USE_UART_LOG == 1) Serial.println(""); #endif sendPubUptime(0); #if (USE_UART_LOG == 1) Serial.println(""); #endif /*sendDisConnectPacket(); #if (USE_UART_LOG == 1) Serial.println(""); #endif*/ break; } default: { gsm.print(cmdAT); #if (USE_UART_LOG == 1) Serial.print(cmdAT); #endif } } timer_reg_modem = current_millis; rresp = s800getCountRrespCmdByNum(modem_step); oresp = s800getCountOrespCmdByNum(modem_step); for (byte i = 0; i < max_resp_count_on_one_type_cmd; ++i) { fl_true_Rresp[i] = 0; // max 5 response text by one command and one type fl_true_Oresp[i] = 0; } if (rresp) { for (byte i = 0; i < rresp; ++i) { s800getRespByNum(0, modem_step, i, text_Rresp[i]); } } if (oresp) { for (byte i = 0; i < oresp; ++i) { s800getRespByNum(1, modem_step, i, text_Oresp[i]); } } clearRespBuf(); } void clearRespBuf() { memset(resp_buf, 0, maxSizeResponse); pos_buf = 0; } void loadDataFromModem() { if (gsm.available()) { while (gsm.available()) { byte readByte = gsm.read(); if (readByte > 0) { #if (USE_UART_LOG == 1) Serial.write(readByte); /*if ((readByte < 0x20) || (readByte >= 0x7F)) { Serial.print(" 0x"); Serial.print(readByte, HEX); Serial.print(" "); } else { Serial.write(readByte); }*/ #endif resp_buf[pos_buf] = readByte; ++pos_buf; if (pos_buf >= maxSizeResponse) pos_buf = 0; wdt_reset(); if (doCmdForModem(readByte) == 1) break; } } } } void resetModem() { LEDREDON; // reset modem pinMode(reset_sim800_pin, OUTPUT); digitalWrite(reset_sim800_pin, LOW); delay(115); pinMode(reset_sim800_pin, INPUT); digitalWrite(reset_sim800_pin, LOW); // new init modem and start new main loop timer_reg_modem = current_millis; modem_step = 100; startFlag = 1; operator_name[0] = 0; mqtt_mode = 0; timer_send_gps_data = 0; timer_uptime = current_millis; } byte sendConnectPacket(byte getSize) { byte sizeDevice = strlen(mqtt_device); byte sizeUser = strlen(mqtt_user); byte sizePass = strlen(mqtt_pass); byte fullSize = 16 + sizeDevice + sizeUser + sizePass; if (getSize) return (fullSize + 2); // fixed header sendByteToMQTTclient((byte)0x10); // MQTT Control Packet type 0001 connect, reserved 0000 sendByteToMQTTclient((byte)(fullSize)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload. // Variable header sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)0x04); // Length LSB (4) sendByteToMQTTclient((byte)'M'); sendByteToMQTTclient((byte)'Q'); sendByteToMQTTclient((byte)'T'); sendByteToMQTTclient((byte)'T'); // protocol name sendByteToMQTTclient((byte)0x04); // Protocol Level byte sendByteToMQTTclient((byte)0xC0); // Connect Flag bits, login and pass enable sendByteToMQTTclient((byte)0x00); // Keep Alive MSB (0) sendByteToMQTTclient((byte)time_live_connect_packet); // Keep Alive LSB // payload sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)sizeDevice); // Length LSB (4) - device for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i])); sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)sizeUser); // Length LSB (4) - user for (byte i = 0; i < sizeUser; ++i) sendByteToMQTTclient((byte)(mqtt_user[i])); sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)sizePass); // Length LSB (4) - pass for (byte i = 0; i < sizePass; ++i) sendByteToMQTTclient((byte)(mqtt_pass[i])); } void sendByteToMQTTclient(byte inByte) { gsm.write((byte)(inByte)); #if (USE_UART_LOG == 1) if ((inByte < 0x20) || (inByte >= 0x7F)) { Serial.print(" 0x"); Serial.print(inByte, HEX); Serial.print(" "); } else { Serial.write(inByte); } #endif } byte sendGPSlData(byte getSize) { byte sizeDevice = strlen(mqtt_device); byte sizeTopic = strlen(mqtt_topic_gps_longitude); byte sizeData = strlen(data_gps_longitude); byte fullSize = 4 + sizeDevice + sizeTopic + sizeData; if (getSize) return (fullSize + 2); // fixed header sendByteToMQTTclient((byte)0x30); // MQTT Control Packet type 0011, DUP QoS Retain 0000 flags sendByteToMQTTclient((byte)(fullSize)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload. // Variable header sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)(sizeDevice + sizeTopic)); // Length LSB (4) for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i])); for (byte i = 0; i < sizeTopic; ++i) sendByteToMQTTclient((byte)(mqtt_topic_gps_longitude[i])); sendByteToMQTTclient((byte)0x00); // Packet Identifier MSB (0) sendByteToMQTTclient((byte)0x00); // Packet Identifier LSB (10) // payload for (byte i = 0; i < sizeData; ++i) sendByteToMQTTclient((byte)(data_gps_longitude[i])); } byte sendGPSbData(byte getSize) { byte sizeDevice = strlen(mqtt_device); byte sizeTopic = strlen(mqtt_topic_gps_breadth); byte sizeData = strlen(data_gps_breadth); byte fullSize = 4 + sizeDevice + sizeTopic + sizeData; if (getSize) return (fullSize + 2); // fixed header sendByteToMQTTclient((byte)0x30); // MQTT Control Packet type 0011, DUP QoS Retain 0000 flags sendByteToMQTTclient((byte)(fullSize)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload. // Variable header sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)(sizeDevice + sizeTopic)); // Length LSB (4) for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i])); for (byte i = 0; i < sizeTopic; ++i) sendByteToMQTTclient((byte)(mqtt_topic_gps_breadth[i])); sendByteToMQTTclient((byte)0x00); // Packet Identifier MSB (0) sendByteToMQTTclient((byte)0x00); // Packet Identifier LSB (10) // payload for (byte i = 0; i < sizeData; ++i) sendByteToMQTTclient((byte)(data_gps_breadth[i])); } void sendDisConnectPacket() { // fixed header sendByteToMQTTclient((byte)0xE0); // MQTT Control Packet type 1110 connect, reserved 0000 sendByteToMQTTclient((byte)0x00); // Remaining Length } byte sendSubscribeKey(byte getSize) { byte sizeDevice = strlen(mqtt_device); byte sizeTopic = strlen(mqtt_topic_key); byte fullSize = 5 + sizeDevice + sizeTopic; if (getSize) return (fullSize + 2); // fixed header sendByteToMQTTclient((byte)0x82); // MQTT Control Packet type (8) 0100, reserved 0010 sendByteToMQTTclient((byte)(fullSize)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload. // Variable header sendByteToMQTTclient((byte)0x00); // Packet Identifier MSB (0) sendByteToMQTTclient((byte)(0x0A)); // Packet Identifier LSB (10) // payload sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)(sizeDevice + sizeTopic)); // Length LSB (4) for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i])); for (byte i = 0; i < sizeTopic; ++i) sendByteToMQTTclient((byte)(mqtt_topic_key[i])); sendByteToMQTTclient((byte)0x00); // Requested QoS(1) } void getVinModem() { float Vbat = (analogRead(power_level_pin) * 1.1) / 1023; float Vin = Vbat / Vdel; modemVin = Vin * 100; } void getTemp1() { ds18b20.reset(); ds18b20.write(0xCC); ds18b20.write(0x44); } word getTemp2() { byte dsData[9]; ds18b20.reset(); ds18b20.write(0xCC); ds18b20.write(0xBE); for (byte i = 0; i < 9; i++) dsData[i] = ds18b20.read(); if (OneWire::crc8(dsData, 8) != dsData[8]) return errTemp; word outTemp = (word)(dsData[1] << 8) + dsData[0]; if ((word)(outTemp & 0x8000) == (word)(0x8000)) { outTemp = (~outTemp) + (word)1; outTemp = (((word)6 * outTemp) + outTemp / (word)4) / (word)10; } else { outTemp = (((word)6 * outTemp) + outTemp / (word)4) / (word)10; if (outTemp == 0) return errTemp; outTemp += (word)2000; } return outTemp; } byte sendPubTemp(byte getSize) { if (currTemp == errTemp) return 0; char textTemp[] = "-100.0"; byte textPos = 0; word absTemp = currTemp; if (absTemp >= 2000) { absTemp -= 2000; } else { textTemp[textPos] = '-'; ++textPos; } if (absTemp >= 1000) { textTemp[textPos] = (absTemp / 1000) + '0'; absTemp = absTemp % 1000; ++textPos; textTemp[textPos] = (absTemp / 100) + '0'; absTemp = absTemp % 100; ++textPos; textTemp[textPos] = (absTemp / 10) + '0'; ++textPos; } else if (absTemp >= 100) { textTemp[textPos] = (absTemp / 100) + '0'; absTemp = absTemp % 100; ++textPos; textTemp[textPos] = (absTemp / 10) + '0'; ++textPos; } else if (absTemp >= 10) { textTemp[textPos] = (absTemp / 10) + '0'; ++textPos; } textTemp[textPos] = '.'; ++textPos; textTemp[textPos] = (absTemp % 10) + '0'; ++textPos; textTemp[textPos] = 0; byte sizeDevice = strlen(mqtt_device); byte sizeTopic = strlen(mqtt_topic_temp); byte sizeData = strlen(textTemp); byte fullSize = 4 + sizeDevice + sizeTopic + sizeData; if (getSize) return (fullSize + 2); // fixed header sendByteToMQTTclient((byte)0x30); // MQTT Control Packet type 0011, DUP QoS Retain 0000 flags sendByteToMQTTclient((byte)(fullSize)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload. // Variable header sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)(sizeDevice + sizeTopic)); // Length LSB (4) for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i])); for (byte i = 0; i < sizeTopic; ++i) sendByteToMQTTclient((byte)(mqtt_topic_temp[i])); sendByteToMQTTclient((byte)0x00); // Packet Identifier MSB (0) sendByteToMQTTclient((byte)0x00); // Packet Identifier LSB (10) // payload for (byte i = 0; i < sizeData; ++i) sendByteToMQTTclient((byte)(textTemp[i])); } byte sendPubVin(byte getSize) { if (currTemp == 999) return 0; char textTemp[] = " 9.99"; byte textPos = 0; word absTemp = modemVin; textTemp[textPos] = (absTemp / 100) + '0'; ++textPos; textTemp[textPos] = '.'; ++textPos; textTemp[textPos] = (absTemp % 100) / 10 + '0'; ++textPos; textTemp[textPos] = (absTemp % 100) % 10 + '0'; ++textPos; textTemp[textPos] = 0; byte sizeDevice = strlen(mqtt_device); byte sizeTopic = strlen(mqtt_topic_vin); byte sizeData = strlen(textTemp); byte fullSize = 4 + sizeDevice + sizeTopic + sizeData; if (getSize) return (fullSize + 2); // fixed header sendByteToMQTTclient((byte)0x30); // MQTT Control Packet type 0011, DUP QoS Retain 0000 flags sendByteToMQTTclient((byte)(fullSize)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload. // Variable header sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)(sizeDevice + sizeTopic)); // Length LSB (4) for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i])); for (byte i = 0; i < sizeTopic; ++i) sendByteToMQTTclient((byte)(mqtt_topic_vin[i])); sendByteToMQTTclient((byte)0x00); // Packet Identifier MSB (0) sendByteToMQTTclient((byte)0x00); // Packet Identifier LSB (10) // payload for (byte i = 0; i < sizeData; ++i) sendByteToMQTTclient((byte)(textTemp[i])); } byte sendPubUptime(byte getSize) { char textTemp[] = " 999"; byte textPos = 0; unsigned long absTemp = (current_millis - timer_uptime) / 60000; absTemp = constrain(absTemp, 0, 999); textTemp[textPos] = (absTemp / 100) + '0'; ++textPos; textTemp[textPos] = (absTemp % 100) / 10 + '0'; ++textPos; textTemp[textPos] = (absTemp % 100) % 10 + '0'; ++textPos; textTemp[textPos] = 0; byte sizeDevice = strlen(mqtt_device); byte sizeTopic = strlen(mqtt_topic_uptime); byte sizeData = strlen(textTemp); byte fullSize = 4 + sizeDevice + sizeTopic + sizeData; if (getSize) return (fullSize + 2); // fixed header sendByteToMQTTclient((byte)0x30); // MQTT Control Packet type 0011, DUP QoS Retain 0000 flags sendByteToMQTTclient((byte)(fullSize)); // Remaining Length is the length of the variable header (10 bytes) plus the length of the Payload. // Variable header sendByteToMQTTclient((byte)0x00); // Length MSB (0) sendByteToMQTTclient((byte)(sizeDevice + sizeTopic)); // Length LSB (4) for (byte i = 0; i < sizeDevice; ++i) sendByteToMQTTclient((byte)(mqtt_device[i])); for (byte i = 0; i < sizeTopic; ++i) sendByteToMQTTclient((byte)(mqtt_topic_uptime[i])); sendByteToMQTTclient((byte)0x00); // Packet Identifier MSB (0) sendByteToMQTTclient((byte)0x00); // Packet Identifier LSB (10) // payload for (byte i = 0; i < sizeData; ++i) sendByteToMQTTclient((byte)(textTemp[i])); } //--s800str.h-- #include <avr\pgmspace.h> #define maxSizeATcommand 60 #define maxSizeResponse 24 const char at0cmdAT[] PROGMEM = "AT\r\n"; const char at1cmdHTTPACTION[] PROGMEM = "AT+HTTPACTION=0\r\n"; const char at1rsp1[] PROGMEM = "+HTTPACTION:"; const char at1rsp2[] PROGMEM = ","; const char at2cmdSAPBR11[] PROGMEM = "AT+SAPBR=1,1\r\n"; const char at2rsp1[] PROGMEM = "operation not allowed\r\n"; const char at3cmdREADSMS[] PROGMEM = "AT+CMGL=4\r\n"; // "AT+CMGL=\"ALL\"\r\n"; const char at4cmdDDET[] PROGMEM = "AT+DDET=1\r\n"; const char at5cmdATE0[] PROGMEM = "ATE0\r\n"; const char at6cmdCLIP1[] PROGMEM = "AT+CLIP=1\r\n"; const char at7cmdATS0[] PROGMEM = "ATS0=0\r\n"; const char at8cmdATV1[] PROGMEM = "ATV1\r\n"; const char at9cmdATCMEE2[] PROGMEM = "AT+CMEE=2\r\n"; const char at10cmdATCMGF1[] PROGMEM = "AT+CMGF=0\r\n"; const char at11cmdATCREG[] PROGMEM = "AT+CREG?\r\n"; const char at11rsp1[] PROGMEM = "+CREG:"; const char at11rsp2[] PROGMEM = ",1\r\n"; const char at12cmdDELSMS[] PROGMEM = "AT+CMGDA=6\r\n"; // "AT+CMGDA=\"DEL ALL\"\r\n"; const char at13cmdSAPBR311[] PROGMEM = "AT+SAPBR=3,1,\"CONTYPE\",\"GPRS\"\r\n"; const char at14cmdSAPBR312[] PROGMEM = "AT+SAPBR=3,1,\"APN\",\"internet\"\r\n"; const char at15cmdSAPBR313[] PROGMEM = "AT+SAPBR=3,1,\"USER\",\"\"\r\n"; const char at16cmdSAPBR314[] PROGMEM = "AT+SAPBR=3,1,\"PWD\",\"\"\r\n"; const char at17cmdSAPBR21[] PROGMEM = "AT+SAPBR=2,1\r\n"; const char at17rsp1[] PROGMEM = "+SAPBR:"; const char at17rsp2[] PROGMEM = ",1,\""; const char at18cmdHTTPINIT[] PROGMEM = "AT+HTTPINIT\r\n"; const char at19cmdHTTPCID[] PROGMEM = "AT+HTTPPARA=\"CID\",1\r\n"; const char at20cmdHTTPURL[] PROGMEM = "AT+HTTPPARA=\"URL\",\"arduino.ru\"\r\n"; const char at21cmdHTTPREAD[] PROGMEM = "AT+HTTPREAD\r\n"; const char at22cmdHTTPTERM[] PROGMEM = "AT+HTTPTERM\r\n"; const char at23cmdCSCLK1[] PROGMEM = "AT+CSCLK=1\r\n"; // =1 if use DTR pin modem const char at24cmdGETOPS[] PROGMEM = "AT+COPS?\r\n"; // get operator const char at24rsp1[] PROGMEM = "+COPS:"; const char at24rsp2[] PROGMEM = "\"\r\n"; const char at25cmdCSQ[] PROGMEM = "AT+CSQ\r\n"; // get net const char at26cmdCMGS[] PROGMEM = "AT+CMGS="; // begin send sms const char at26rsp1[] PROGMEM = ">"; // begin send sms const char at27cmdCMGS[] PROGMEM = "none"; // text sms const char at27rsp1[] PROGMEM = "+CMGS:"; // text sms const char at28cmdBALMEG[] PROGMEM = "AT+CUSD=1,\"*100#\"\r\n"; // get balance megafon const char at28rsp1[] PROGMEM = "+CUSD:"; const char at28rsp2[] PROGMEM = ", 72\r\n"; // init new gprs packet const char at29cmdCGATT[] PROGMEM = "AT+CGATT?\r\n"; const char at29rsp1[] PROGMEM = "+CGATT: 1\r\n"; const char at30cmdCIPMODE[] PROGMEM = "AT+CIPMODE=0\r\n"; const char at31cmdCIPMUX[] PROGMEM = "AT+CIPMUX=0\r\n"; // set context and open connect const char at32cmdCIPSTATUS[] PROGMEM = "AT+CIPSTATUS\r\n"; const char at32rsp1[] PROGMEM = "IP INITIAL\r\n"; const char at33cmdCSTT[] PROGMEM = "AT+CSTT=\"internet\"\r\n"; const char at32rsp2[] PROGMEM = "IP START\r\n"; /*34*/ const char at35cmdCIICR[] PROGMEM = "AT+CIICR\r\n"; const char at32rsp3[] PROGMEM = "IP GPRSACT\r\n"; /*36*/ const char at37cmdCIFSR[] PROGMEM = "AT+CIFSR\r\n"; const char at32rsp4[] PROGMEM = "IP STATUS\r\n"; /*38*/ const char at39cmdCIPSTART[] PROGMEM = "AT+CIPSTART=\"TCP\",\"m23.cloudmqtt.com\",15069\r\n"; const char at39rsp1[] PROGMEM = "CONNECT OK\r\n"; const char at32rsp5[] PROGMEM = "STATE: CONNECT OK\r\n"; /*40*/ // send data to server const char at41cmdCIPQSEND[] PROGMEM = "AT+CIPQSEND=0\r\n"; const char at42cmdCIPSEND[] PROGMEM = "AT+CIPSEND="; const char at42rsp1[] PROGMEM = ">"; const char at43cmdNull[] PROGMEM = "\r\n"; const char at43rsp1[] PROGMEM = "SEND OK\r\n"; /*"SEND OK\r\n"*/ const char at44cmdCIPSHUT[] PROGMEM = "AT+CIPSHUT\r\n"; const char at44rsp1[] PROGMEM = "SHUT OK\r\n"; // set option get data const char at45cmdCIPHEAD[] PROGMEM = "AT+CIPHEAD=0\r\n"; const char at46cmdCIPSRIP[] PROGMEM = "AT+CIPSRIP=0\r\n"; // typical response const char rspOK[] PROGMEM = "OK\r\n"; const char rspEndLine[] PROGMEM = "\r\n"; const char * const at_list_cmd[] PROGMEM = { // text command at0cmdAT, at1cmdHTTPACTION, at2cmdSAPBR11, at3cmdREADSMS, at4cmdDDET, at5cmdATE0, at6cmdCLIP1, at7cmdATS0, at8cmdATV1, at9cmdATCMEE2, at10cmdATCMGF1, at11cmdATCREG, at12cmdDELSMS, at13cmdSAPBR311, at14cmdSAPBR312, at15cmdSAPBR313, at16cmdSAPBR314, at17cmdSAPBR21, at18cmdHTTPINIT, at19cmdHTTPCID, at20cmdHTTPURL, at21cmdHTTPREAD, at22cmdHTTPTERM, at23cmdCSCLK1, at24cmdGETOPS, at25cmdCSQ, at26cmdCMGS, at27cmdCMGS, at28cmdBALMEG, at29cmdCGATT, at30cmdCIPMODE, at31cmdCIPMUX, at32cmdCIPSTATUS, at33cmdCSTT, at32cmdCIPSTATUS /*34*/, at35cmdCIICR, at32cmdCIPSTATUS /*36*/, at37cmdCIFSR, at32cmdCIPSTATUS /*38*/, at39cmdCIPSTART, at32cmdCIPSTATUS /*40*/, at41cmdCIPQSEND, at42cmdCIPSEND, at43cmdNull, at44cmdCIPSHUT, at45cmdCIPHEAD, at46cmdCIPSRIP }; const PROGMEM uint8_t at_rresp_cmd[] = { // 0-count right response 1, 4, 0, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 3 /*24*/, 1, 1, 2, 3, 2, 1, 1, 2, 1, 2, 1, 2, 1, 2, 2, 2, 1, 2, 0, 1, 1, 1 }; const PROGMEM uint8_t at_oresp_cmd[] = { // 1-count other response - need manual action by response 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0 }; const PROGMEM uint8_t at_move_cmd[] = { // step after action cmd 4, 21, 17, 12, 5, 6, 7, 8, 9, 10, 11, 13, 101, 14, 15, 16, 23, 18, 19, 20, 1, 22, 101, 24 /* ? 24 */, 29, 101, 27, 101, 101, 30, 31, 45, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 101, 101, 46, 101 }; const char * const at_list_rresp[] PROGMEM = { rspOK, // at0 rspOK, at1rsp1, at1rsp2, rspEndLine, // at1 rspOK, // at3 rspOK, // at4 rspOK, // at5 rspOK, // at6 rspOK, // at7 rspOK, // at8 rspOK, // at9 rspOK, // at10 at11rsp1, at11rsp2, rspOK, // at11 rspOK, // at12 rspOK, // at13 rspOK, // at14 rspOK, // at15 rspOK, // at16 at17rsp1, at17rsp2, rspOK, // at17 rspOK, // at18 rspOK, // at19 rspOK, // at20 rspOK, // at21 rspOK, // at22 rspOK, // at23 at24rsp1, at24rsp2, rspOK, // at24 ? rspOK, // at25 at26rsp1, // at26 at27rsp1, rspOK, // at27 rspOK, at28rsp1, at28rsp2, // at28 at29rsp1, rspOK, // at29 rspOK, // at30 rspOK, // at31 rspOK, at32rsp1, // at32 rspOK, // at33 rspOK, at32rsp2, // at34 rspOK, // at35 rspOK, at32rsp3, // at36 rspEndLine, // at37 rspOK, at32rsp4, // at38 rspOK, at39rsp1, // at39 rspOK, at32rsp5, // at40 rspOK, // at41 rspEndLine, at42rsp1, // at42 at44rsp1, // at44 rspOK, // at45 rspOK // at46 }; const char * const at_list_oresp[] PROGMEM = { rspOK, at2rsp1, // at2 at43rsp1 // at43 }; void s800getTextCmdByNum(byte numCmd, char* textCmd); byte s800getCountRrespCmdByNum(byte numCmd); byte s800getCountOrespCmdByNum(byte numCmd); void s800getRespByNum(byte typeResp, byte numCmd, byte numResp, char* textCmd); byte s800getNextStepCmdByNum(byte numCmd); #define GSM_RX 3 // пин RX на модуле подключаем к указаному пину на Ардуино TX #define GSM_TX 2 // пин TX на модуле подключаем к указаному пину на Ардуино RX #define WORK_LEVEL_LED 0 // 1 if HIGH level ON led, else 0 #define reset_sim800_pin 4 // pin for reset modem #define dtr_sim800_pin 10 // pin DTR for sleep mode #define power_level_pin A6 // input power level for control #define ledRed_pin 7 // pin RED led #define ledGre_pin 8 // pin GREEN led #define ledBlu_pin 9 // pin BLUE led #if (WORK_LEVEL_LED == 0) #define LEDREDON digitalWrite(ledRed_pin,LOW) #define LEDGREON digitalWrite(ledGre_pin,LOW) #define LEDBLUON digitalWrite(ledBlu_pin,LOW) #define LEDREDOFF digitalWrite(ledRed_pin,HIGH) #define LEDGREOFF digitalWrite(ledGre_pin,HIGH) #define LEDBLUOFF digitalWrite(ledBlu_pin,HIGH) #else #define LEDREDON digitalWrite(ledRed_pin,HIGH) #define LEDGREON digitalWrite(ledGre_pin,HIGH) #define LEDBLUON digitalWrite(ledBlu_pin,HIGH) #define LEDREDOFF digitalWrite(ledRed_pin,LOW) #define LEDGREOFF digitalWrite(ledGre_pin,LOW) #define LEDBLUOFF digitalWrite(ledBlu_pin,LOW) #endif char* LastPos(char *str1, char *str2); int strPos(char *str11, char *str22); //--s800str.cpp-- #include "Arduino.h" #include "s800str.h" void s800getTextCmdByNum(byte numCmd, char* textCmd) { const char * addrStroki = pgm_read_word_near((int)(at_list_cmd + numCmd)); strcpy_P(textCmd, addrStroki); } byte s800getCountRrespCmdByNum(byte numCmd) { return pgm_read_byte_near(at_rresp_cmd + numCmd); } byte s800getCountOrespCmdByNum(byte numCmd) { return pgm_read_byte_near(at_oresp_cmd + numCmd); } byte s800getNextStepCmdByNum(byte numCmd) { return pgm_read_byte_near(at_move_cmd + numCmd); } void s800getRespByNum(byte typeResp, byte numCmd, byte numResp, char* textCmd) { byte startPos = 0; if (numCmd > 0) for (byte i = 1; i <= numCmd; ++i) { switch (typeResp) { case 0: { startPos += pgm_read_byte_near(at_rresp_cmd + i - 1); break; } case 1: { startPos += pgm_read_byte_near(at_oresp_cmd + i - 1); break; } default : {} } } switch (typeResp) { case 0: { const char * addrStroki = pgm_read_word_near((int)(at_list_rresp + startPos + numResp)); strcpy_P(textCmd, addrStroki); break; } case 1: { const char * addrStroki = pgm_read_word_near((int)(at_list_oresp + startPos + numResp)); strcpy_P(textCmd, addrStroki); break; } default : {} } } char* LastPos(char *str1, char *str2) { // find substring in string int L1 = strlen(str1); int L2 = strlen(str2); for (int i = L1 - L2; i >= 0; i--) { int j = 0; for (; j < L2; j++) if ((str1[i + j] != str2[j])) break; if (j == L2) return str1 + i; } return 0; } int strPos(char *str11, char *str22) { // find position in string(1) substring(2) char*p = LastPos(str11, str22); int n = p - str11; return n; } Скетч использует 12290 байт (40%) памяти устройства. Всего доступно 30720 байт. Глобальные переменные используют 985 байт (48%) динамической памяти, оставляя 1063 байт для локальных переменных. Максимум: 2048 байт.Andycat, а зачем сохраняем в mcusr_mirror , если потом не используем? Или я проглядел?
Это кусок кода для работоспособности wdt на arduino nano
Я понял что это не mqtt. Но это же переменная не используется потом вроде?
На форуме была целая тема по поводу этого кода и он вроде из Даташита, и если я правильно помню, концы смотреть в #include <avr/wdt.h>
Щас гуру подтянутся - разьяснят.
AT OK AT+CIPSHUT SHUT OK AT+DDET=0 OK ATE0 OK AT+CLIP=0 OK ATS0=0 OK ATV1 OK AT+CMEE=2 OK AT+CMGF=1 OK AT+CSCLK=0 OK AT+CIPMODE=0 OK AT+CIPMUX=1 OK AT+CIPHEAD=0 OK AT+CIPSRIP=0 OK AT+CSTT="internet" OK AT+CIICR OK AT+CIPSTATUS OK STATE: IP GPRSACT AT+CIFSR t▒b▒IRU*R▒('LK▒▒,",▒9%J▒▒ C: 2,,"","","","INITIAL" C: 3,,"","","","INITIAL" C: 4,,"","","","INITIAL" C: 5,,"","","","INITIAL" 100.70.64.195 OK STATE: IP STATUS ReadyAT+CIPSTART=0,"TCP","m23.cloudmqtt.com",15069 C: 0,,"","","""INTIA" C 1,"",","""INTIAL C 2,"",","""INTIL" OK 0, CONNECT OK AT+CIPSEND=0 > 0x10 8 0x0 0x4 MQTT 0x4 0xC0 0x0 0xF0 0x0 0x14 12345678901234567890 0x0 0x8 fag******xbt 0x0 0xC ba*****YaX 0, SEND OK +RECEIVE,0,4: 0x2 0x1 AT+CIPSEND=0 > 0x82 " 0x0 0xA 0x0 0x1D watering/12345678901234567890 0x1 0/ 0x0 0xB log/connect 0x0 0x0 12345678901234567890 - connected 0, SEND OK +RECEIVE,0,5: 0x90 0x3 0x1Последовательность команд SIM800L работы с MQTT брокером, устройство работает 24/7, в случае проблем переподключается между серверами.
// начало работы Start! // начало модуля первоначальной настройкой модема // ждем ответ на команды в течении 5 секунд, в случае отсутствия - перезагрузка модема ATZ // сбросим настройки модема в default OK ATE0 // отключение ЭХО, т е модем в обратку не дублирует команды OK ATV1 // развернуты подробный ответ от модема OK AT+CMEE=2 // вывод подробных описаний ошибок OK AT+CIPSHUT // закрыть все интернет сессии SHUT OK // этот ответ лучше ждать подольше, до 10 секунд AT+CLIP=0 // отключение АОН OK ATS0=0 // модем не берет трубку при входящем звонке OK AT+CMGF=1 // обычный режим вывода SMS OK AT+CSCLK=0 // отключение работы энергосберегающего режима через пин DTR OK AT+CIPHEAD=0 // не добавлять заголовок при приеме данных OK AT+CIPRXGET=0 // автоматический вывод принятых данных OK AT+CIPSRIP=0 // не показывать данные отправителя при приеме данных OK AT+CSPN? // получить имя оператора из SIM карты +CSPN: "M2M Express",0 // парсим ответ, в зависимости от того, чья карта стоит, будем использовать разные APN OK // инициализация основная закончилась // переходим в режим регистрации модема у оператора AT+CREG? // каждые 5 секунд запрашиваем статус +CREG: 0,2 OK SMS Ready // ответ ждем в течении 2х минут, если за это время не зарегестрировались - перезагрузка модема AT+CREG? +CREG: 0,3 OK AT+CREG? +CREG: 0,3 OK AT+CREG? +CREG: 0,3 OK AT+CREG? +CREG: 0,0 OK AT+CREG? +CREG: 0,0 OK AT+CREG? +CREG: 0,0 OK AT+CREG? +CREG: 0,5 // успешно зарегестрировались OK AT+COPS? // запрашиваем имя оператора +COPS: 1,0,"MegaFon" // парсим ответ - заносим имя оператора в переменную - потом отдадим на сервер для статистики OK AT+CSQ? // запрашиваем уровень связи +CSQ: 12,0 // парсим ответ, потом отдадим серверу для статистики OK AT+CIPMODE=0 // командный режим передачи данных OK AT+CMGDA="DEL ALL" // удаление всех SMS на SIM карте OK // закончилась полная инициализация модема // начало модуля соединения с mqtt сервером // ответы на команды, просто отвечающие ОК, без глобальных изменений так же ждем 5 секунд, в случе отсутствия - проблема - перезагружаем модем AT+CIPSTATUS // запрашиваем статус сессии OK STATE: IP INITIAL AT + CSTT = "internet.emt.ee" // прописываем APN в зависимости от установленной SIM карты OK AT+CIPSTATUS // запрашиваем статус OK STATE: IP START AT+CIICR // активируем контекст, по даташиту команда выполняется до 62 секунд, оптимально 35 секунд ждать ответ OK AT+CIPSTATUS // запрашиваем статус OK STATE: IP GPRSACT AT+CIFSR // получаем адрес 0.137.119.101 OK STATE: IP STATUS AT+CIPSTART="TCP","m23.cloudmqtt.com",***** // коннектимся к серверу OK AT+CIPSTATUS // запрашиваем статус OK STATE: TCP CONNECTING AT+CIPSTATUS OK STATE: TCP CONNECTING // // в течении 10 секунд ждем подключения к серверу, иначе или меняем сервер на резервный или опять поднимаем заново интернет сессию // общее время ожидания к mqtt серверу ждем в течении 2 минут, иначе перезагрузка модема // AT+CIPSTATUS OK STATE: TCP CONNECTING AT+CIPSTATUS OK STATE: TCP CONNECTING AT+CIPSTATUS CONNECT OK OK STATE: CONNECT OK // успешное подключение // начинаем работать с брокером AT+CIPSEND >x10 3x0 x4 MQTTx4 xC0 x0 xFD x0 xF Qw37Tu89u78-91px0 x8 ****** xC ******* // connect packet SEND OK AT+CIPSEND >x82 x1C x0 xA x0 x17 smd/Qw37Tu89u78-91p/cmdx1 x2 x1 // подписываемся на нужные топики SEND OK AT+CIPSEND >05x0 xB log/connectx0 x0 Qw37Tu89u78-91p - connected;MegaFon;12 // отправляем на сервер данные о подключении 23 0 x90 x3 x1 SEND OK // после каждой отправки ждем данное подтверждение в течении 8 секунд, в случае отсутствия - переподключаемся к серверу AT+CIPSEND // каждае 240 секунд (время удержания соединения, меньшее, чем указано в connect packet) >xC0 x0 // шлем PING REQ , потом ждем 14 секунд PING RESP SEND OK xD0 /*пришел PING RESP, если не дождались - реконнект к серверу*/ AT+CIPSEND >xC0 x0 SEND OK xD0 AT+CIPSTATUS OK STATE: CONNECT OK AT+CIPCLOSE // принудительно разорвали связь или увидели ответ CLOSED CLOSE OK AT+CIPSTATUS // запускаем заново модуль соединения к серверу OK STATE: TCP CLOSED // который в зависимости от статуса AT+CIPSHUT // согласно даташита шлет нужную команду SHUT OK AT+CIPSTATUS OK STATE: IP INITIAL AT + CSTT = "internet.emt.ee" OK AT+CIPSTATUS OK STATE: IP START AT+CIICR OK AT+CIPSTATUS OK STATE: IP GPRSACT AT+CIFSR 0.137.201.64S OK STATE: IP STATUS AT+CIPSTART="TCP","m20.cloudmqtt.com",***** // коннектимся к резервному серверу OK AT+CIPSTATUS OK STATE: TCP CONNECTING // .......... ждем коннекта AT+CIPSTATUS OK STATE: TCP CONNECTING AT+CIPSTATUS CONNECT OK OK STATE: CONNECT OK AT+CIPSEND >x10 3x0 x4 MQTTx4 xC0 x0 xFD x0 xF Qw37Tu89u78-91px0 x8 ****** xC ******* SEND OK AT+CIPSEND >x82 x1C x0 xA x0 x17 smd/Qw37Tu89u78-91p/cmdx1 x2 SEND OK AT+CIPSEND >x82 xC x0 xA x0 x7 log/srvx1 x90 x3 x1 SEND OK AT+CIPSEND >05x0 xB log/connectx0 x0 Qw37Tu89u78-91p - connected;MegaFon;12 23 7 x90 x3 x1 SEND OK AT+CIPSTATUS OK STATE: CONNECT OK AT+CIPCLOSE // опять принудительно разрываем связь CLOSE OK AT+CIPSTATUS OK STATE: TCP CLOSED AT+CIPSHUT SHUT OK AT+CIPSTATUS OK STATE: IP INITIAL AT + CSTT = "internet.emt.ee" OK AT+CIPSTATUS OK STATE: IP START AT+CIICR OK AT+CIPSTATUS OK STATE: IP GPRSACT AT+CIFSR 0.149.212.52S OK STATE: IP STATUS AT+CIPSTART="TCP","m23.cloudmqtt.com",****** // теперь уже соединяемся с основным сервером OK AT+CIPSTATUS OK STATE: TCP CONNECTING // ...... ждем соединения AT+CIPSTATUS OK STATE: TCP CONNECTING AT+CIPSTATUS CONNECT OK OK STATE: CONNECT OK AT+CIPSEND >x10 3x0 x4 MQTTx4 xC0 x0 xFD x0 xF Qw37Tu89u78-91px0 x8 ******* xC ******** SEND OK AT+CIPSEND >x82 x1C x0 xA x0 x17 smd/Qw37Tu89u78-91p/cmdx1 x2 x1 SEND OK AT+CIPSEND >05x0 xB log/connectx0 x0 Qw37Tu89u78-91p - connected;MegaFon;12 23 0 x90 x3 x1 SEND OK 0x1D x17 smd/Qw37Tu89u78-91p/cmdcmd1AT+CIPSEND // пришла команда в подписанный топик, выполнили ее >0"x0 x18 smd/Qw37Tu89u78-91p/respx0 x0 resp12 // отправили подтверждающий ответ SEND OK AT+CIPSEND >xC0 x0 // бесконечно крутимся в цикле PING REQ SEND OK xD0 // PING RESP-
часть кода, обработка интернет сессии по даташиту
-
void processStatus(byte inBt) { // основной анализ статусов, логика строго по даташиту static unsigned long timerConnecting; // таймер для замера времени коннекта к брокеру if (findRespFromBuf((char *) "IP INITIAL\r\n", inBt)) { // если начальный статус // 0 needCloseConnect = false; // разрывать связь не надо // прописываем APN gprsATcmdByIdx(0, false); gprsATcmd((char *)getAPNname(opsCard), false); gprsATcmd((char *)"\"\r", true); currentGprsModem = waitOKcmd; // ждем ОК } else if (findRespFromBuf((char *) "IP START\r\n", inBt)) { // следующий статус // 1 gprsATcmdByIdx(1, true); // активируем контекст currentGprsModem = waitCIICRcmd; // ждем ОК } else if (findRespFromBuf((char *) "IP GPRSACT\r\n", inBt)) { // следующий статус // 3 if (needCloseConnect) { // если нужно свзь разорвать gprsATcmdByIdx(2, true); // отключаем контекст currentGprsModem = waitOKcmd; // ждем ОК } else { // если подключаем связь gprsATcmdByIdx(3, true); // получаем адрес currentGprsModem = waitRNcmd; // ждем вывода } } else if (findRespFromBuf((char *) "IP STATUS\r\n", inBt)) { // дальше // 4 if (needCloseConnect) { // если рвем связь gprsATcmdByIdx(2, true); // отключаем контекст } else { // продолжаем подключение gprsATcmdByIdx(4, false); // коннектимся к серверу if (mainMQTTserver) { // выбор сервера и отправка соотвествующего имени в зависимости от режима #ifdef DEBUG_MODE gprsATcmd((char *)"m20.cloudmqtt.com", false); gprsATcmd((char *)"\",", false); gprsATcmd((char *)"*****", false); #else char strServer[maxSizeBrokerID]; strcpy(strServer, (char *)mqttServer2); gprsATcmd((char *)strServer, false); gprsATcmd((char *)"\",", false); strcpy(strServer, (char *)mqttPort2); gprsATcmd((char *)strServer, false); #endif } else { // основной сервер #ifdef DEBUG_MODE gprsATcmd((char *)"m23.cloudmqtt.com", false); gprsATcmd((char *)"\",", false); gprsATcmd((char *)"*****", false); #else char strServer[maxSizeBrokerID]; strcpy(strServer, (char *)mqttServer1); gprsATcmd((char *)strServer, false); gprsATcmd((char *)"\",", false); strcpy(strServer, (char *)mqttPort1); gprsATcmd((char *)strServer, false); #endif } gprsATcmd((char *)"\r", true); // шлем окончание команды timerConnecting = currentMillis; // обнуляем таймер ожидания коннекта } currentGprsModem = waitOKcmd; // ждем ок } else if (findRespFromBuf((char *) "CONNECT OK\r\n", inBt)) { // приконнектилось // 6 if (needCloseConnect) { // если нужен разрыв gprsATcmdByIdx(5, true); // закрываем контекст currentGprsModem = waitOKcmd; // ждем ОК } else { // если подключаемся currentGprsModem = serverConnected; // успешно выходим } } else if (findRespFromBuf((char *) "TCP CONNECTING\r\n", inBt)) { // в процессе подключения // 5 if (needCloseConnect) { // если нужно разорвать связь gprsATcmdByIdx(2, true); // гасим currentGprsModem = waitOKcmd; // ждем ОК } else { // ждем подключения if ((currentMillis - timerConnecting) >= gprsPeriodConnecting) { // если время вышло if (mainMQTTserver) mainMQTTserver = 0; else mainMQTTserver = 1; // меняем сервер ++totalReconnectMQTT; // увеличиваем счетчик смены брокеров gprsATcmdByIdx(2, true); // гасим контекст currentGprsModem = waitOKcmd; // ждем ОК } else { // если продолжыется подключение currentGprsModem = sendCipStatus; // запрашиваем статус } } } else if (findRespFromBuf((char *) "IP CONFIG\r\n", inBt)) { // шаг // 2 currentGprsModem = sendCipStatus; // запрос статуса } else if (findRespFromBuf((char *) "TCP CLOSING\r\n", inBt)) { // шаг // 7 currentGprsModem = sendCipStatus; // запрос статуса } else if (findRespFromBuf((char *) "TCP CLOSED\r\n", inBt)) { // отключились от сервера // 8 gprsATcmdByIdx(2, true); // гасим сессию currentGprsModem = waitOKcmd; // ждем ОК } else if (findRespFromBuf((char *) "DPD DEACT\r\n", inBt)) { // отключилась сессия // 9 currentGprsModem = sendCipStatus; // запрос статуса } else if (findRespFromBuf((char *) "CONNECT FAIL\r\n", inBt)) { // ошибка соединения gprsATcmdByIdx(2, true); // гасим сессию currentGprsModem = waitOKcmd; // ждем ОК } }-
к сожалению, какая бы не была хорошая схема, в среднем один из 20и модемов SIM800L зависает наглухо один раз в 50....70 дней, на команды отвечает, а по факту данные не передает. Поэтому рекомендую в схему добавить эл.ключ/реле, в случае принудительной перезагрузки третий раз за 15 минут, тупо отрубать питание. И конечно для стабильной работы строго использовать Hardware UART atmega328p.
плюсую, также сделал в проекте управления webasto - суровое реле питание рубит.
просто с правильным SoftwareSerial видимо никто не экспериментировал...
просто с правильным SoftwareSerial видимо никто не экспериментировал...
А что, в природе такое бывает?
IMHO, SoftwareSerial - костыль, который, возможно, может быть в некоторых экзотических случаях использован для отладки, но который обязательно должен быть удален из финального кода.
аппаратная реализация сериала конечно лучше программной...
я знаю как минимум пяток реализаций программного, недостатки того, что из коробки...
захватывает все прерывания PCINT и нет поддержки параметров число бит данных, контроль, стоп биты
первый решился бы разработкой библиотеки менеджера прерываний, второй решен в одной из библиотек, но
только для ограниченного набора частот кварца
смотрю профессиональные девайсы, а там используется SIM300... более стабилен в работе?
смотрю профессиональные девайсы
а что в вашем понятии профессиональные девайсы? мой последний проект/заказ c SIM800L развернут на нескольких тысяч устройств, в планах 200000+ , но считать его профессиональным я например не могу.
и да, соглашусь с мнением выше, использовать software serial из коробки можно только для вывода какого нибудь не критичного лога. Если у вас он стабильно работает, могу только поздравить.
ЗЫ. И вообще ветка про MQTT.
Sim300 применяется в ВЭРС-ПК к примеру, имеет все необходимые сертификаты, можно почистить флуд...
но считать его профессиональным я например не могу.
Интересно, почему ?
но считать его профессиональным я например не могу.
Интересно, почему ?
потому что я не профессиональный программист/электронщик и не имею соответствующего сертификата как у какого нибудь КБ с кучей специалистов разной направленности :)
но да, устройства работают хорошо и стабильно, поэтому конечно вопрос спорный что считать проф.устройством.
использовать software serial из коробки можно только для вывода какого нибудь не критичного лога.
Даже для этого нельзя, если софт интенсивно прерывания юзает. software serial его положит. Список его авторов я уже дето выкладывал. Этих уродов регулярно упоминаю в проклятиях. Надо быть последним фашистским человеконенавистником чтоб такое нахерячить. И да - тех кого устраивает как оно работает - дальше хелоуворда не пробовали. Он просто не может стабильно работать не убив все вокруг.
Температура, влажность, давление на BME280+ESP8266(WeMos D1 mini), отправляемые на MQTT сервер.
Код сборная солянка, страшненький, написан наспех на коленке, но работает стабильно.
При включении подключается в течении 2 минут к WiFi точке доступа, в случае облома запускает сервер куда вбиваются данные WiFi и MQTT. Далее получает данные, отправлет и засыпает на 25 минут.
Потребление через понижайку от аккумулятора 18650 ~1.5мА в спящем режиме
Установленные железки в реальных условиях
смотреть логи брокера - искать что ему не нравиться
Не подскажите каким образом это делается?
Обычно - глазами.
использовать software serial из коробки можно только для вывода какого нибудь не критичного лога.
Даже для этого нельзя, если софт интенсивно прерывания юзает. software serial его положит. Он просто не может стабильно работать не убив все вокруг.
Есть еще CustomSoftwareSerial, SomeSerial, я их использую
использовать software serial из коробки можно только для вывода какого нибудь не критичного лога.
Даже для этого нельзя, если софт интенсивно прерывания юзает. software serial его положит. Он просто не может стабильно работать не убив все вокруг.
Есть еще CustomSoftwareSerial, SomeSerial, я их использую
А какая, собственно, разница?
Любая программная реализация последовательного порта будет конфликтовать с прерываниями. Вопрос лишь в том, что раньше отвалится - сам COM-порт или все остальное оборудование, требующее прерываний.
PS. Лично я программный COM-порт не использую. Где-то при отладке - еще может быть, а в готовом изделии - никогда.
А какая, собственно, разница?
Любая программная реализация последовательного порта будет конфликтовать с прерываниями. Вопрос лишь в том, что раньше отвалится - сам COM-порт или все остальное оборудование, требующее прерываний.
PS. Лично я программный COM-порт не использую. Где-то при отладке - еще может быть, а в готовом изделии - никогда.
использует PCINT однако, только захватывает все прерывания, править библиотеку приходится освобождая ненужные, DetSimen написал библиотеку для радиолюбителей использующую софтовый сериал, всё работает при правильном подходе )))
использует PCINT однако, только захватывает все прерывания, править библиотеку приходится освобождая ненужные,
Ну переписали мы таким образом библиотеку. Ну пошли у нас прерывания со стороны. И вот тут каждое устройство стало тянуть одеяло на себя. И кто-то из них в этом перетягивании однозначно проиграет. Чудес не бывает: либо с софтсериал полезут ошибки, либо другое устройство будет работать ненормально со всеми вытекающими.
DetSimen написал библиотеку для радиолюбителей использующую софтовый сериал, всё работает при правильном подходе )))
Вот именно - при правильном! А отключить часть пинов от pcint и думать, что все проблемы уже решены - подход явно неправильный.
Подскажите как использовать Willmessage. После установки флагов как указать топик и сообщение?