I have learned from experience that if I don't re-connect mqtt, then it just eventually times out and stops working. My code is below, the first iteration (I've omitted wifi and list implementations for brevity):
function initMQTT()
m = mqtt.Client("ESP3", 120, "user", "pass")
listItems = List.new()
-- 9600 for a test
uart.setup( 0, 38400, 8, 0, 1, 0);
uart.on("data", "\n", function(data)
processMQ(data)
end, 0)
end
function sendAll(conn)
local rv = List.popleft(listItems)
if rv == nil then
m:close()
else
m:publish(rv[1], rv[2], 0, 0, sendAll);
end
end
function decim(y)
x = tonumber(y)
if x == nil then return nil end
l = string.len(x)
a = string.sub(x,0,l-2)
b = string.sub(x,l-1);
return ""..a.."."..b
end
function processMQ(data)
if (data=='') then return end
pos = 0
idx = 0
for st,sp in function() return string.find(data," ",pos,true) end do
item = string.sub(data,pos,st-1);
List.pushright(listItems, {"/emontx/current/"..idx,tonumber(item)});
idx = idx + 1
pos = sp + 1
end
item = string.sub(data,pos)
List.pushright(listItems, {"/emontx/voltage",decim(item)});
pushAll()
end
function pushAll()
m:connect("192.168.0.16", 1883, 0, function(conn)
sendAll(conn)
end)
end
initMQTT()
This *almost* works - except if two lines come in quick succession, I get failures that the mqtt is already connected. So I re-wire it to this:
function sendAll()
local rv = List.popleft(listItems)
if rv == nil then
m:close()
amPushing=0
else
m:publish(rv[1], rv[2], 0, 0, sendAll);
end
end
function pushAll()
if amPushing == 0 then
amPushing = 1
m:connect("192.168.0.16", 1883, 0, function(conn)
sendAll(conn)
end)
end
end
This gets much further, but now occasionally still bombs with
PANIC: unprotected error in call to Lua API (wtaf.lua:117: already connected)What I *assume* is happening is the m:close() must return immediately, but the connection is still deemed to be open until some time later (perhaps some kind of MQTT 'bye' from the server).
All these callbacks, even though (I assume) they're non-preempted, seems a very tortuous solution compared with just having m:close() be synchronous. I'm not sure (new to LUA) how to make access to a shared resource (mqtt) 'safe' and what primitives I should be using (yield?) to achieve this.