我的应用涉及一个运行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()
仅在 publish()
时调用已经完成了 .
但是当我有超过1次调用 publish()
并希望我的回调a)被调用后被调用're all complete, and b) only be called once, I'被卡住了 .
天真的方法是将回调(这是可选的)仅放在第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()
调用合并为一个调用,但这感觉就像一个丑陋的黑客,并会产生其他不利影响 . 如果我的两条消息在概念上是截然不同的,那么这种方法会推动逻辑将它们分成订阅者 - 哎呀 . 如果他们需要去讨论不同的话题,那就更糟了 . 肯定有更好的办法 .
我想也许 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)
1 回答
选项1:立即发布所有数据,然后进入睡眠状态 .
选项2:将回调拆分为两部分 . 第一部分检查你是否完成,如果你完成,第二部分会进入休眠状态 . 当然,你可以用不同的方式解决这个问题,计算剩余数量,计算你发送的数量,发送和删除列表中的项目,直到列表为空,...
当然还有更多的选择,但这些选择既简单又充足 .
Edit: 按要求提供示例