问题
I'm building a battery powered IoT device based on ESP8266 with NodeMCU. I use mqtt to periodically perform measurements and publish results. I know, that to allow network stack running, I should avoid tight loops and rely on callback functions. Therefore it seemed to me that the right organization of my measurement code should be:
interval=60000000
function sleep_till_next_sample()
node.dsleep(interval)
end
function close_after_sending()
m:close()
sleep_till_next_sample()
end
function publish_meas()
m:publish("/test",result,1,0,close_after_sending)
print("published:"..result)
end
function measurement()
-- The omitted part of the function accesses
-- the hardware and places results
-- in the "result" variable
m = mqtt.Client("clientid", 120, "user", "password")
m:connect("172.19.1.254",1883,0, publish_meas)
end
The init.lua ensures, that the node has connected to the WiFi AP (if not, it retries up to 20 times, and if no connection is established, it puts the node on sleep until the next measurement time). After WiFi connection is done, it calls the measurement function.
The interesting thing is, that the above code doesn't work. There are no errors displayed in the console, but the mqtt broker does not receive published messages. To make it working, i had to add additional idle time, by adding timers in the callback functions.
The finally working code looks like below:
interval=60000000
function sleep_till_next_sample()
node.dsleep(interval)
end
function close_after_sending()
m:close()
tmr.alarm(1,500,0,function() sleep_till_next_sample() end)
end
function publish_meas()
m:publish("/test",result,1,0,function() tmr.alarm(1,500,0,close_after_sending) end)
print("published:"..result)
end
function measurement()
-- The omitted part of the function accesses
-- the hardware and places results
-- in the "result" variable
m = mqtt.Client("clientid", 120, "user", "password")
m:connect("172.19.1.254",1883,0, function() tmr.alarm(1,500,0, publish_meas) end)
end
The above works, but I'm not sure if it is optimal. To conserve the battery power I'd like to minimize the time before the node is put on sleep after the measurement is completed and results published.
Is there any better way to chain the necessary calls to m:connect, m:publish, m:close and finally node.dsleep so, that the results are correctly published in the minimal time?
回答1:
Perhaps this was solved by more recent firmware. I am working through a problem that I thought might be somewhat explained by this issue, so tried to reproduce the problem as described.
My simplified test code is substantially similar; it calls dsleep() from the PUBACK callback of mqtt.Client.publish():
m = mqtt.Client("clientid", 120, "8266test", "password")
m:lwt("/lwt", "offline", 0, 0)
function main(client)
print("connected - at top of main")
m:publish("someval",12345,1,0, function(client)
rtctime.dsleep(SLEEP_USEC)
end)
end
m:on("connect", main)
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)
and when run, does successfully publish to my MQTT broker.
I am using:
NodeMCU custom build by frightanic.com
branch: master
commit: 81ec3665cb5fe68eb8596612485cc206b65659c9
SSL: false
modules: dht,file,gpio,http,mdns,mqtt,net,node,rtctime,sntp,tmr,uart,wifi
build built on: 2017-01-01 20:51
powered by Lua 5.1.4 on SDK 1.5.4.1(39cb9a32)
来源:https://stackoverflow.com/questions/34382676/mqtt-on-esp8266-with-nodemcu-problems-with-publishing