使用Lua / NodeMCU,如何在运行代码块之前等待> 1 mqtt发布调用?

时间:2017-01-07 16:48:53

标签: lua mqtt nodemcu

我的应用程序涉及一个运行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()完成时被调用。

但是当我有一个以上的publish()来电并希望我的回叫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()调用合并为一个调用,但这感觉就像一个丑陋的黑客,并会产生其他不利影响。如果我的两条消息在概念上是截然不同的,那么这种方法会推动逻辑将它们分成订阅者 - 哎呀。如果他们需要去讨论不同的话题,那就更糟了。必须有更好的方法。

我想也许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 个答案:

答案 0 :(得分:1)

选项1: 一次发布所有数据,然后进入睡眠状态。

选项2: 将回调分为两部分。第一部分检查你是否完成,如果你完成,第二部分会进入休眠状态。 当然,你可以用不同的方式解决这个问题,计算剩下的数量,计算你发送的数量,发送和删除列表中的项目,直到列表为空,...

当然还有更多选择,但这些选择既简单又充足。

编辑:按要求提供的示例

local totalItemCount = 5

function publishCallback()
  itemsPublished = (itemsPublished or 0) + 1
  print("item published")
  if itemsPublished == totalItemCount then
    print("I'm done, good night!")
  end
end   

for i = 1, totalItemCount do
  publishCallback()
end
  

项目已发布

     

项目已发布

     

项目已发布

     

项目已发布

     

项目已发布

     

我已经完成了,晚安!