首页 文章

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

提问于
浏览
0

我的应用涉及一个运行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

    选项1:立即发布所有数据,然后进入睡眠状态 .

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

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

    Edit: 按要求提供示例

    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
    

    项目发布项目发布项目发布项目发布项目发布我已经完成了,晚安!

相关问题