【问题标题】:NodeMCU and ESP8266: slow mqtt publishNodeMCU 和 ESP8266:mqtt 发布速度慢
【发布时间】:2017-01-08 21:39:55
【问题描述】:

我正在使用 esp8266 和 Marcel 的 NodeMCU 自定义构建生成的固件http://frightanic.com/nodemcu-custom-build/ 我测试了“dev”分支和“master”。

我在https://github.com/nodemcu/nodemcu-firmware 处更改了一点“连接到 MQTT 代理”代码

-- 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();  

我正在使用 mosquitto 作为 mqtt 代理,并且我已经启动了所有主题 # 的订阅者。

结果是:消息正确到达,但它们到达订阅者的速度真的很慢(每个大约 1 秒)......为什么?

我还尝试更改 mqtt 架构以支持 UDP.. esp8266 快速发送 100 条消息。

更新 1#:

我又做了一些实验:

  • 测试代理和 具有 [android 手机 + mqtt 发布者] 的订阅者,订阅者 立即接收消息
  • 我加载了一个启用“调试”的 nodemcu 我做了一个有趣的发现:继续阅读

对于我所理解的阅读调试日志和源代码.. 有一种将消息保存在内存中的队列和一个计时器(我不知道频率/间隔)从队列中读取消息并通过 mqtt 发送它。 如果您尝试发送 100 条消息,队列会增加,但无法同时传递消息(可能存在竞争条件?)。

这里还有第二个问题,在它排队超过 15 条消息后,固件崩溃并且设备重新启动:这似乎是内存不再可用的症状。

【问题讨论】:

  • 与其描述更改,不如编辑问题以实际显示您所做的更改可能更有用
  • "slow mqtt publish" 可能是错误的......您还不知道发布速度是否缓慢,或者代理是否将消息分发给订阅者的速度很慢,对吧?您是否尝试过使用其他“设备”(例如 Java 或 Python 应用程序)发布?
  • 我将尝试在另一台具有 mqtt 客户端/发布器的机器上进行测试(使用相同的订阅者和代理),我将在此处发布结果。谢谢你
  • 嗨,我现在也测试了一个 Mqtt 客户端,用于 android 连接到同一个代理并从 android 发布.. 并且消息立即到达。也许我可以尝试“调试”固件..

标签: mqtt iot mosquitto esp8266 nodemcu


【解决方案1】:

这可能不是您要寻找的答案,但是是的,NodeMCU MQTT 使用内部队列来存储消息。它是 2015 年 3 月末的 added。它是由于 NodeMCU API 的异步特性而添加的。

如果您连续两次调用m.publish,请记住它们是异步的,在触发第二条消息之前没有足够的时间传递第一条消息。如果您在循环中发布,那么在引入该队列之前,固件只会崩溃。

我进一步简化了您的代码并添加了一些调试语句:

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)

知道对m.publish 的调用是异步的,输出应该不会太令人惊讶:

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

您看到可用堆空间在发布时正在减少,而在队列清空时再次增加。

【讨论】:

  • 谢谢马塞尔!你的回答很有用。顺便说一句,我认为当前的实现存在一些问题,因为将太多的发布请求放在一个循环中 (i=0;i
  • 很高兴它有帮助。你知道my Docker imager to build NodeMCUmy cloud build service,对吧?
  • 当然!您知道我应该将哪个选项传递给“make”以启用“调试”固件登录吗?
  • 您需要查看github.com/nodemcu/nodemcu-firmware/blob/master/app/include/… 中的DEVELOP_VERSIONNODE_DEBUGCOAP_DEBUG
  • 我明白为什么要引入队列,但是它们有一个不好的副作用。我建立了一个电池供电的节点。因此,我想在消息发送后立即将其深入。不幸的是,当我在 mqtt.client:publish 的回调中调用 node.dsleep 时,消息丢失了。当队列被清空并且所有消息都被传递时,如何回调我的函数?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-16
  • 1970-01-01
  • 2021-02-20
  • 2018-01-27
  • 1970-01-01
  • 2011-06-06
相关资源
最近更新 更多