Как реализовать MQTT по GPRS на модеме A6 в асинхронном режиме

sav13
sav13 аватар
Offline
Зарегистрирован: 17.06.2013

Всем привет
Создаю контроллер, работающий по GPRS с протоколом MQTT
Контроллер использую ESP32

Нашел хорошую библиотеку TinyGSM все это реализующую. Но вот беда. Когда эта библиотека взаимодействует с GSM модемом, то использует функцию waitResponse(). Получается, после посылки команды в модем контроллер ничем не может заниматься в основном цикле до ожидания ответа

Если бы это было только один раз, но GPRS соединение периодически отваливается и приходится запускать переподключение в основном цикле программы.

Никто не видел реализации такой работы в асинхронном режиме?

Чтобы я запускал команду в модем и спокойно бы обрабатывал основной цикл, периодически проверя статус ответа модема?

Путь в нем будет LoopGSM() отвечающий за прием данных от модема, но только когда есть эти данные, если уж нельзя реализовать данную функцию по прерыванию

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Там унутре waitResponse() вызываеца TINY_GSM_YIELD(), может ей чонить присвоить, поиграца.

Я глубоко не рыл, счас посмотрю, что оно значит. 

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

вот как она описана

#ifndef TINY_GSM_YIELD
  #define TINY_GSM_YIELD() { delay(0); }
#endif

можно её подменить на определение своей функции вне этой библиотеки.  И таймаут там, кста, настраиваемый.

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

 

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

sav13 пишет:

Чтобы я запускал команду в модем и спокойно бы обрабатывал основной цикл, периодически проверя статус ответа модема?

Не использовать библиотеки
Написать самим

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

DetSimen пишет:

вот как она описана

#ifndef TINY_GSM_YIELD
  #define TINY_GSM_YIELD() { delay(0); }
#endif

можно её подменить на определение своей функции вне этой библиотеки.  И таймаут там, кста, настраиваемый.

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

Очень напрягают такие конструкции в библиотеке

    sendAT(GF("+CGATT=1"));
    if (waitResponse(60000L) != 1)
      return false;

или такая конструкция в цикле

      sendAT(GF("+CPIN?"));
      if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
        delay(1000);
        continue;
      }

Пока нашел другое решение. Повесил весь свой основной код на прерывание по таймеру.
Пускай основной цикл только занимается модемом. А мне только статусы проверять при каждом срабатывании таймера

andycat пишет:
sav13 пишет:

Чтобы я запускал команду в модем и спокойно бы обрабатывал основной цикл, периодически проверя статус ответа модема?

Не использовать библиотеки Написать самим

Трудоемкость реализации MQTT over GPRS да еще и в AT командах моего модема A6/A7 достаточно велика.

Хотелось бы обойтись без крайностей. 

TinyGSM нашел как единственную более менее законченную и рабочую реализацию

DetSimen
DetSimen аватар
Offline
Зарегистрирован: 25.01.2017

Ну я в таких вопросах нихрена не компетентен.  :(   Ждите гуру. 

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

sav13 пишет:

TinyGSM нашел как единственную более менее законченную и рабочую реализацию

TinyGSM - кривое глюкало.

Самое правильное все-таки написать самому. Трудоемкость там не так уж велика, как вам кажется.  Пишете ведь не с нуля... Берете ту же TinyGSM или аналогичную библиотеку для SIM800|900 (команды модемов очень близки) - и дорабатываете.

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

Код выкладывать не стану  - стыдно. :)

Кстати, примеры работы с GPRS для А6 есть в темах Logik-а на форуме.

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

sav13 пишет:

Хотелось бы обойтись без крайностей. 

Ну тогда если вам не требуется подписываться на топик MQTT сервера, тупо шлите

в модем последовательности команд по таймеру, т.е. например каждые 45 секунд отправка

цикла команд отправки PUBLISH пакетов MQTT с инициализацией сессии GPRS

с периодичностью 0,5 секунд, ответы игнорировать. Обязательно после цикла отправки

шлите DISCONNECT пакет MQTT. А что бы быть ну почти уверенным что все будет работать

каждые например 30 минут сбрасывайте модем и инициализируйте заново.

Вот для примера последовательность для SIM800, для вашего модема она другая.

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

ЗЫ. Где то тут пробегала ссылка на хорошую библиотеку таймеров если уж не хотите сами с millis заморачиваться

Update: кстати про прерывания - в примере #4 чтения СМС при уменьшении скорости Serial со 115200 на меньшее, скетч перестает работать, не успевает обрабатывать ответ от модема и символы теряются, пришлось кардинально менять логику поиска подстроки (поиск с конца строки - время обработки увеличилось в 4 раза), и часть критичных переменных в ОЗУ переносить - тогда только стало работать с любой скоростью Serial, да еще и HTTP запросы слать и ответы обрабатывать успевал.

sav13
sav13 аватар
Offline
Зарегистрирован: 17.06.2013

Всем большое спасибо за помощь. Работать с модемом в основном цикле и вызывать остальной код по таймеру оказалось хорошей идеей. Пока все работает довольно надежно.

b707 пишет:

TinyGSM - кривое глюкало.

Самое правильное все-таки написать самому. Трудоемкость там не так уж велика, как вам кажется.  Пишете ведь не с нуля... Берете ту же TinyGSM или аналогичную библиотеку для SIM800|900 (команды модемов очень близки) - и дорабатываете.

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

В TinyGSM есть стыковка с MQTT библиотекой PuSubClient. При этом код MQTT переносится без проблем с WiFi и Ethernet интерфейсов. Так что пока буду мириться. 

Писать свою реализацию MQTT включая все QOS, подписки, авторизацию и пр. все таки чере чур

 

andycat пишет:

Ну тогда если вам не требуется подписываться на топик MQTT сервера, тупо шлите

в модем последовательности команд по таймеру, т.е. например каждые 45 секунд отправка

цикла команд отправки PUBLISH пакетов MQTT с инициализацией сессии GPRS

с периодичностью 0,5 секунд, ответы игнорировать. Обязательно после цикла отправки

шлите DISCONNECT пакет MQTT. А что бы быть ну почти уверенным что все будет работать

каждые например 30 минут сбрасывайте модем и инициализируйте заново.

Вот для примера последовательность для SIM800, для вашего модема она другая.

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

ЗЫ. Где то тут пробегала ссылка на хорошую библиотеку таймеров если уж не хотите сами с millis заморачиваться

Как раз управление по подписке - самая нужная функция. Так что как раз важна поддержка соединения. Просто посылать данные скорее всего реализовал бы на HTTP протоколе. Он как то проще и не требует постоянного соединения.

Так как код пишу на ESP32 - работа с таймерами там отлично реализована в библиотке Ticker