Скрыть объявление
На нашем форуме недоступен просмотр изображений для неавторизованных пользователей. Если Вы уже зарегистрированы на нашем форуме, то можете войти. Если у Вас еще нет аккаунта, мы будем рады, если Вы к нам присоединитесь. Зарегистрироваться Вы можете здесь.

Нужна помощь Библиотека PubSubClient

Тема в разделе "ESP8266 Arduino IDE", создана пользователем max506, 28 сен 2016.

  1. max506

    max506 Новичок

    Сообщения:
    66
    Симпатии:
    2
    Пытаюсь работать с библиотекой PubSubClient, модуль ESP8266 Wemos D1.
    Получаю данные от Ардуино по UART.
    С интервалом 5 сек посылаю на MQTT broker Mosquitto порядка 10 метрик, используя для этого функцию client.publish(topic, value).
    Столкнулся со странной особенностью, а именно если предварительно подписаться на отсылаемую тему методом client.subscribe(topic), то публикация значений в эту тему (отработка метода client.publish) происходит за в среднем 3 миллисекунды, хотя бывают и задержки. Если же не подписываться, то метод отрабатывает за 200!!! миллисекунд. Это из-за чего так? Можно ли как-нибудь ускорить работу метода публикации?
     
    Последнее редактирование: 29 сен 2016
  2. Сергей_Ф

    Сергей_Ф Moderator Команда форума

    Сообщения:
    2.127
    Симпатии:
    226
    @max506 могу только предположить, что подписка устанавливает и держит соединение с сервером. Без подписки соединение переустанавливается каждую публикацию - вот и тратится время на это. Код не смотрел, могу ошибаться.
     
  3. max506

    max506 Новичок

    Сообщения:
    66
    Симпатии:
    2
    Вот код, которым я пользуюсь
    Код (Text):
    1. #include <ESP8266WiFi.h>
    2. #include <PubSubClient.h>
    3.  
    4.  
    5. const char *ssid = "......";  // Имя вайфай точки доступа
    6. const char *pass = "......";  // Пароль от точки доступа
    7.  
    8. const char *mqtt_server =  "......";  // Имя сервера MQTT
    9. const int mqtt_port = 1883; // Порт для подключения к серверу MQTT
    10. const char *mqtt_user = "";
    11. const char *mqtt_pass = "";
    12.  
    13. String subscr_topic = "/esp/topic1/";
    14. String prefix = "/esp/";
    15. String buf_recv;
    16.  
    17.  
    18. WiFiClient wclient;  
    19. PubSubClient client(wclient, mqtt_server, mqtt_port);
    20.  
    21.  
    22. // Функция получения данных от MQTT брокера
    23. void callback_subscr(const MQTT::Publish &pub)
    24. {
    25.  
    26.   String topic = pub.topic();
    27.   String value = pub.payload_string();
    28.  
    29.  
    30.   if( topic.substring(0,subscr_topic.length()) == subscr_topic)   // передаем в UART только данные, на которые подписывались
    31.      Serial.println(topic.substring(subscr_topic.length())+"="+value);
    32.    
    33. }
    34.  
    35.  
    36. // Отправка данных на MQTT брокер
    37. void Send(){
    38.  
    39.   char ch;
    40.   String pub_topic;
    41.   String val;
    42.   int pos_delim;
    43.   long t;
    44.  
    45.     // полчение данных по UART от Arduino
    46.     while (Serial.available()) {
    47.  
    48.       ch = (char)Serial.read();
    49.    
    50.       if (ch == '\r') continue;
    51.  
    52.       if (ch == '\n') {
    53.    
    54.         // Данные приходят в виде строк в формате <тема>=<значение>
    55.         pos_delim = buf_recv.indexOf('=');
    56.         pub_topic = buf_recv.substring(0,pos_delim);
    57.         val = buf_recv.substring(pos_delim+1);
    58.  
    59.        
    60.         // #### Вызов метода публикации "виснет" на 200 миллисекунд, если предварительно не подписаться на публикуемую тему !!!!!
    61.         t=millis();
    62.         client.publish(prefix+pub_topic,val);
    63.         Serial.println(millis()-t);
    64.      
    65.      
    66.         buf_recv="";
    67.         break;
    68.       }
    69.      
    70.       buf_recv += ch;
    71.  
    72.     }
    73. }
    74.  
    75.  
    76. void setup() {
    77.  
    78.   Serial.begin(9600);
    79.  
    80. }
    81.  
    82. void loop() {
    83.  
    84.   // подключаемся к wi-fi
    85.   if (WiFi.status() != WL_CONNECTED) {
    86.     Serial.print("Connecting to ");
    87.     Serial.print(ssid);
    88.     Serial.println("...");
    89.     WiFi.begin(ssid, pass);
    90.  
    91.     if (WiFi.waitForConnectResult() != WL_CONNECTED)
    92.       return;
    93.     Serial.println("WiFi connected");
    94.   }
    95.  
    96.   // подключаемся к MQTT серверу
    97.   if (WiFi.status() == WL_CONNECTED) {
    98.     if (!client.connected()) {
    99.       Serial.println("Connecting to MQTT server");
    100.       if ( client.connect(MQTT::Connect("ESP_Witty").set_auth(mqtt_user, mqtt_pass)) ) {
    101.         Serial.println("Connected to MQTT server");
    102.         client.set_callback(callback_subscr);
    103.         client.subscribe(subscr_topic+"#"); // подписывааемся на темы с изменяемыми данными
    104.                      
    105.       } else {
    106.         Serial.println("Could not connect to MQTT server");
    107.       }
    108.     }
    109.  
    110.     if (client.connected()){
    111.    
    112.       client.loop();
    113.  
    114.       Send();
    115.     }
    116.  
    117.   }
    118.  
    119. }
     
  4. max506

    max506 Новичок

    Сообщения:
    66
    Симпатии:
    2
    А может кто-нибудь код глянуть, я не очень понимаю в библиотеках классов.
    Может есть возможность не подписываться на все темы и при этом публиковать сообщения, на которые не подписан, с нормальной скоростью.
     
  5. krepton85

    krepton85 Новичок

    Сообщения:
    67
    Симпатии:
    3
    Смотрю вы пользуетесь той же библиотекой pubsubclient, что и я. Этих библиотек есть 2 вида, та что мы с вами используем самая редкая, и есть др. которой все пользуются, она доступна в репазитории arduino ide методы ее использования в скетче различаются с нашей. Наша построена на объекте класса String - все текстовые строки, а та что самая популярная на строках char*.
    Мною были замечены баги и в той и в той библиотеке, в нашей с вами - если в один из топиков на каторый мы подписаны быстро засыпать данные, например нажимая быстро одну и туже кнопку в приложении или дергать слайдер в приложении с которого не преривно сыпятся данные, то esp8266 виснет намертво и даже не ребутит. В др. библиотеке что есть в IDE если взять даже стандартный пример mqqt_pablish_in_callback и дописать в его с дисяток подписок, то модуль esp начинает уже виснуть на 5 подписке где-то, а далее ребутит.
     
  6. max506

    max506 Новичок

    Сообщения:
    66
    Симпатии:
    2
    Попробуйте использовать версию менеджера плат esp8266 не последнюю, а 2.0.0. С ней намного устойчивее работает.
     
  7. krepton85

    krepton85 Новичок

    Сообщения:
    67
    Симпатии:
    3
    Да я последнюю (2.2.3) и не использую. Я использую 2.2.0
     
  8. max506

    max506 Новичок

    Сообщения:
    66
    Симпатии:
    2
    Попробуй перейти на 2.0.0
     
  9. krepton85

    krepton85 Новичок

    Сообщения:
    67
    Симпатии:
    3
    Ок. Папробую.

    Реально это практически полностью помогло, решить проблему с зависанием если быстро засыпать данными в топик. Сейчас как бы тоже видно будто бы подвисает, но не намертво спустя пару секунд само атдупляется. :)
     
    Последнее редактирование: 26 дек 2016
  10. krepton85

    krepton85 Новичок

    Сообщения:
    67
    Симпатии:
    3
    Ура, ура, меня осинило :) Наконец то понял в чем были все проблеммы с зависанием, они были как раз в этом что вы описали. На отправку одного исходящего сообщения действительно уходит много времени и если нужно подрят отправить до 10 или более исходящих сообщений то цикл void loop давольно сильно на долго преривается может на сек 2 - 3 (с 11 -ю сообщениями).
    У меня в это время (раз в 5 сек) все остальные функции скетча очень сильно подвисало. И наконец то мне пришла в голову идиальная идея, как получить преривание loop длительностью всего в 1 сообщение (не важно сколько их будет).
    В общем решение хитрое, нужно сделать так что бы за один цикл void loop отправлялось только одно сообщение, все последующие распределены по 1 шт, на 1 цикл void loop. В кратце: что бы отправить 10 сообщений нужно что бы цикл void loop повторился 10 раз.
    С таким подходом все работает гораздо быстрей. Раз в 5 сек начинает отправлятся 10 (у меня даже 11) исходящих сообщений, за 11 циклов void loop, после чего таймер обнуляется вновь что бы вновь через 5 сек все повторилось.
     
  11. max506

    max506 Новичок

    Сообщения:
    66
    Симпатии:
    2
    Ну у меня в коде так и сделано. Выгребаю из Serial порта полностью одно сообщение, отправляю, затем снова Loop и снова чтение из Serial порта.
     
  12. krepton85

    krepton85 Новичок

    Сообщения:
    67
    Симпатии:
    3
    @max506, ну в общем то я и др. самую знаменитую библиатеку pubsubclient точно так же победил, но только там тот же косяк был с подписками, сделал так что бы создавалась только одна подписка за цикл loop, и в общем то библиотека работает довольно таки быстро, ничего не виснет, отправляю в тэст - примере 8 исходящих сообщений (на которые сама библиотека не подписана) и все за один цикл loop.
    И что нам сейчас делать? Так лень переписывать огромный скетч под др. либу. :)
     
    alek2 нравится это.
  13. olegmsn

    olegmsn Новичок

    Сообщения:
    24
    Симпатии:
    4
    Когдато написал SmartHome/ESP8266EASTRON.ino at master · merlokk/SmartHome · GitHub
    исполняется быстро.
    там прикол в том, что тут mqttClient.publish(str(), payload, retained) переменная retained должна быть false. Это не сохраняет переменную на сервере, но публикует ее намного быстрее.
     
  14. alek2

    alek2 Новичок

    Сообщения:
    5
    Симпатии:
    0
    @krepton85 Тоже столкнулся с такой проблемой, 5 топиков шлет без проблем, на 6 виснет. Скетчем не поделитесь?
     
  15. krepton85

    krepton85 Новичок

    Сообщения:
    67
    Симпатии:
    3
    @alek2, вот на примере из моего видео:
     
    alek2 нравится это.
  16. olegmsn

    olegmsn Новичок

    Сообщения:
    24
    Симпатии:
    4
  17. alek2

    alek2 Новичок

    Сообщения:
    5
    Симпатии:
    0
    @krepton85
    Большое спасибо, буду разбираться.
     
  18. alek2

    alek2 Новичок

    Сообщения:
    5
    Симпатии:
    0
    @krepton85
    Спасибо, все получилось, еще бы научили push уведомления отправлять.
     
  19. lpaha

    lpaha Новичок

    Сообщения:
    1
    Симпатии:
    0




    А у вас есть пример скетча для ардуины, на получения данных по UART ??
     
  20. feiiint

    feiiint Новичок

    Сообщения:
    2
    Симпатии:
    0
    Товарищи, помогите пожалуйста с решением задачки, у меня схожая проблема. Написал скетч который запоминает состояние после включения\выключения реле на esp8266-01S, и вносит его в EEPROM, после нештатного выключения электричества реле возвращается в исходное состояние. Т.е. после подачи питания мне нужно передать состояние на MQTT-сервер. В сущности, pubSubClientPublishing() нужно вызвать до pubSubClientSubscribe(), потому как pubSubClientSubscribe() следит за топиком и соответственно включает или выключает если в топике появляется 0 или 1. Скетч мой работает, но работает только после того как вызвана функа подписки. Пробовал делать паузу, т.к. было подозрение что публикация запускается раньше доступности сервера MQTT, потом подключил библиотеку 8266PING, после получения true на ответ сервера MQTT передает состояние в топик, и все равно не могу передать состояние (топик пустой), пока не будет выполнена подписка.
     

Поделиться этой страницей