【发布时间】:2017-05-22 06:57:27
【问题描述】:
我的应用程序涉及运行 NodeMCU 的电池供电 ESP8266,目的是通过 MQTT 定期更新传感器值。
为了节省电池寿命,我想在完成工作后立即致电dsleep()。这项工作可能涉及对mqqt.Client.publish() 的多次调用。这给我们带来了我面临的问题。
我是 Lua 新手,但据我了解,在 publish() 完成后运行一些代码的正确方法是给它一个 PUBACK 回调:
m = mqtt.Client(...)
m.publish("/my/topic", "some message", 1, 0, callback_func)
在像上面这样的简单情况下,效果很好 - 即使 MQTT 消息的实际发送与 publish() 调用是异步的(请参阅对此 here 的良好讨论),callback_func() in上面的例子只有在publish() 完成后才会被调用。
但是,当我对publish() 进行了超过 1 次调用并希望我的回调 a) 在它们全部完成后被调用,并且 b) 只被调用一次,我就被卡住了。
对此的天真方法是将回调(可选)仅放在第 N 次 publish() 调用:
m = mqtt.Client(...)
m.publish("/my/topic", "some message", 1, 0)
m.publish("/another/topic", "unrelated message", 1, 0, callback_func)
但这不会达到预期的效果。作为documented:
注意:多次调用 publish() 时,将为所有发布命令调用最后定义的回调函数。
所以在上面的例子中,callback_func() 最终被调用了两次(每次成功调用一次 publish()。
我可以将多个 publish() 调用合并为一个调用,但这感觉就像一个丑陋的 hack,并且会产生其他不利影响。如果我的两条消息在概念上是不同的,那么这种方法将推动逻辑将它们分离到订阅者中 - 呸。如果他们需要讨论不同的主题,那就更糟了。一定有更好的办法。
我以为mqqt.Client.close() 可能会等待我的不同publish() 调用完成,但它没有。
我没有想法,希望有更多 Lua 和/或 NodeMCU+mqqt 经验的人可以帮助我朝着正确的方向前进。
这是我的实际代码,如果有帮助的话:
-- prior to this, we've gotten on the wifi network and acquired an IP
dofile("temp.lua") -- provides get_temp()
m = mqtt.Client("clientid", 120, "8266test", "password")
function mainloop(client)
print("connected - at top of loop")
m:publish("uptime",tmr.time(),1,0, function(client) print("sent uptime") end)
temp, humi = get_temp()
if (temp ~= nil) then
print(string.format("temp: %d", temp))
print(string.format("humi: %d", humi))
m:publish("temp",temp,1,0)
m:publish("humi",humi,1,0, function(client) -- note: this callback will be used for all publish() calls
rtctime.dsleep(SLEEP_USEC)
end)
end
end
m:on("connect", mainloop)
m:on("offline", function(client) is_connected = false print ("offline") end)
m:connect(MQQT_SVR, 1883, 0, mainloop,
function(client, reason) print("failed reason: "..reason) end)
【问题讨论】: