1

I'm using esp8266 with the firmware produced with Marcel's NodeMCU custom builds http://frightanic.com/nodemcu-custom-build/ I tested the "dev" branch and the "master".

I changed a little bit the "Connect to MQTT Broker" code found here https://github.com/nodemcu/nodemcu-firmware

-- init mqtt client with keepalive timer 120sec
m = mqtt.Client("clientid", 120, "user", "password")

m:on("connect", function(con) print ("connected") end)
m:on("offline", function(con) print ("offline") end)

-- m:connect( host, port, secure, auto_reconnect, function(client) )
-- for secure: m:connect("192.168.11.118", 1880, 1, 0)
-- for auto-reconnect: m:connect("192.168.11.118", 1880, 0, 1)
m:connect("192.168.11.118", 1880, 0, 0, function(conn) print("connected") end)

-- publish a message with data = hello, QoS = 0, retain = 0
local i = 1
while i < 10 do
  m:publish("/topic","hello",0,0, function(conn) print("sent") end)
  i = i + 1
end

m:close();  

I'm using mosquitto as a mqtt broker and I have launched a subscriber on all topic #.

The result is: the messages arrives correctly but they are really slow to arrive on the subscriber (around 1 second each)... why?

I tried also to change the mqtt architecture in favor of UDP.. the esp8266 send the 100 messages fast.

UPDATE 1#:

I have done some more experiments:

  • Testing the broker and the subscriber with an [android phone + a mqtt publisher], the subscriber receive messages immediately
  • I loaded a nodemcu with "debug" enabled and I have done an interesting discovery: read on

For what I have understood reading debug log and source code.. There is a sort of queue that saves the messages in memory and a timer (I don't know the frequency/interval) reads a message from the queue and it sends it through mqtt. If you try to send 100 messages, the queue increases, but it is not able to deliver messages at the same time (maybe there is a race condition? ).

There is a second problem here, after it has enqueued more than 15 messages, the firmware crash and the device reboots: it seems a symptom of memory no more available.

  • 1
    Rather than describe the changes it may be more useful to edit the question to actually show the changes you have made – hardillb Oct 29 '15 at 12:44
  • 1
    "slow mqtt publish" is probably wrong...you don't know yet whether publishing is slow or whether the broker is slow distributing the messages to the subscriber, right? Have you tried publishing with another "device" (e.g. Java or Python application)? – Marcel Stör Oct 29 '15 at 13:38
  • I will try to test with another machine with an mqtt client/publisher (using the same subscriber and broker ) and I will post here the results. Thanks you – Andrea De Gaetano Oct 29 '15 at 14:00
  • Hi, I've tested now also with a Mqtt client for android connecting to the same broker and publishing from android.. and the message arrive immediately. maybe I can try with "debug" firmware.. – Andrea De Gaetano Oct 29 '15 at 22:51

1 Answers1

4

It may not be the answer you're looking for but yes, NodeMCU MQTT uses an internal queue for messages. It was added at the end of March 2015. It was added due to the asynchronous nature of the NodeMCU API.

If you have two calls to m.publish in quick succession, remember they're asynchronous, there isn't enough time for the 1st message to be delivered before the 2nd is triggered. Before the introduction of that queue the firmware would simply have crashed if you had published in a loop.

I simplified your code even more and added some debugging statements:

m = mqtt.Client("clientid", 120, "user", "password")

m:connect("m20.cloudmqtt.com", port, 0, function(conn) 
    print("MQTT connected")
    for i=1,10 do
      print("MQTT publishing...")
      m:publish("/topic", "hello", 0, 0, function(conn) 
        print("MQTT message sent")
        print("  heap is " .. node.heap() .. " bytes")
      end)
      print("  heap is " .. node.heap() .. " bytes in loop " .. i)
    end
end)

Knowing that the calls to m.publish are asynchronous the output shouldn't be too surprising:

MQTT connected
MQTT publishing...
  heap is 37784 bytes in loop 1
MQTT publishing...
  heap is 37640 bytes in loop 2
MQTT publishing...
  heap is 37520 bytes in loop 3
MQTT publishing...
  heap is 37448 bytes in loop 4
MQTT publishing...
  heap is 37344 bytes in loop 5
MQTT publishing...
  heap is 37264 bytes in loop 6
MQTT publishing...
  heap is 37192 bytes in loop 7
MQTT publishing...
  heap is 37120 bytes in loop 8
MQTT publishing...
  heap is 37048 bytes in loop 9
MQTT publishing...
  heap is 36976 bytes in loop 10
sent
  heap is 38704 bytes
sent
  heap is 38792 bytes
sent
  heap is 38856 bytes
sent
  heap is 38928 bytes
sent
  heap is 39032 bytes
sent
  heap is 39112 bytes
sent
  heap is 39184 bytes
sent
  heap is 39256 bytes
sent
  heap is 39328 bytes
sent
  heap is 39400 bytes

You see that the available heap space is decreasing while publishing and increasing again as the queue is emptied.

Marcel Stör
  • 22,695
  • 19
  • 92
  • 198
  • Thanks you Marcel! Your answer is very useful. BTW I think the current implementation have some problem, because putting too many publish request in a loop (i=0;i<100;i++) , the device reboot also with the queue mechanism. I'm doing more experiment and I will keep updating the post once I have more results. I'm also trying to build my own customized firmware.. :) – Andrea De Gaetano Oct 31 '15 at 08:31
  • 1
    Glad it was helpful. You know about [my Docker imager to build NodeMCU](https://github.com/marcelstoer/docker-nodemcu-build) and [my cloud build service](http://frightanic.com/nodemcu-custom-build/index.php), right? – Marcel Stör Nov 01 '15 at 08:03
  • of course! do you know which option I should pass to "make" in order to enable "debug" log on firmware? – Andrea De Gaetano Nov 01 '15 at 23:29
  • 1
    You'll want to look at `DEVELOP_VERSION`, `NODE_DEBUG` and `COAP_DEBUG ` in https://github.com/nodemcu/nodemcu-firmware/blob/master/app/include/user_config.h. – Marcel Stör Nov 02 '15 at 00:12
  • Hey Marcel :) I've built a version that send the message directly, changing the code of "static int mqtt_socket_publish( lua_State* L )" in the module mqtt.c: the message are received immediately! So, as you said, it doesn't mantain the order but it is fast.. In some way, the queue have reduced the number of msg for each second .. I'm not aware on how the timer works... I will do more experiments... thanks you! – Andrea De Gaetano Nov 02 '15 at 00:28
  • marked this as a solution because Marcel gave me enough information to find the problem and think about a solution (remove the queue). Thanks Marcel! – Andrea De Gaetano Nov 09 '15 at 14:40
  • 1
    I do understand why the queues are introduced, but they have a bad side effect. I build a battery powered node. So I want to put it on deep as soon as the message is sent. Unfortunately, when I call node.dsleep in the callback of mqtt.client: publish, the message is lost. How can I have my function called back when the queue is emptied and all messages are delivered? – wzab Dec 20 '15 at 13:16
  • OK. It seems, that my problem is not related to the mqtt queues. I've asked the separate question describing it: http://stackoverflow.com/questions/34382676/mqtt-on-esp8266-with-nodemcu-problems-with-publishing – wzab Dec 20 '15 at 15:42