This might be a silly question, however, I don't know what is happening.
I have a simple script who fetches google time and I need to set it to the time global variable. So, inside the receive event, I print the time fetched and it works properly.
The problem is the variable time always as empty when called outside the event. Here is the code:
-- test.lua
time = ""
function getTime()
conn = net.createConnection(net.TCP, 0)
conn:connect(80,'google.com')
conn:on("connection", function(conn, payload)
conn:send("HEAD / HTTP/1.1\r\n"..
"Host: google.com\r\n"..
"Accept: */*\r\n"..
"User-Agent: Mozilla/4.0 (compatible; esp8266 Lua;)"..
"\r\n\r\n"
)
end)
conn:on("receive", function(conn, payload)
conn:close()
time = string.sub(payload,string.find(payload,"Date: ")
+6,string.find(payload,"Date: ")+35)
end)
print("testing: " .. time) -- WORKS!
end
getTime()
print("variable: ".. time)
Here is how I'm calling the function (using nodemcu-uploader terminal):
➜ test nu terminal
--- Miniterm on /dev/cu.wchusbserial1410 115200,8,N,1 ---
--- Quit: Ctrl+] | Menu: Ctrl+T | Help: Ctrl+T followed by Ctrl+H ---
> dofile('lib/test.lua')
variable:
> testing: Sat, 20 May 2017 01:37:35 GMT
Any help would be really appreciated! Thanks
It looks like the scope is fine. Check out the order the output prints.
conn:connect and con:on take functions because they are asynchronous. getTime() simply returns before they are called.
The NodeMCU programming model is similar to that of Node.js, only in Lua. It is asynchronous and event-driven. Many functions, therefore, have parameters for callback functions.
Source: https://github.com/nodemcu/nodemcu-firmware/#programming-model
That means that functions which accept callback functions as parameters are non-blocking. That it return means that you can't just read a piece of code line-by-line and expect it to be executed in that order.
So, the sequence of events in your original program roughly is this:
getTime is triggered but does not block.print("variable: ".. time) is executed. time is still empty at this point.time is populated.I see two obvious fixes, one using your global time variable and one without. Both are based on the passing-callback-function-as-parameter pattern.
Note that you should always set up your event listeners (conn:on in your case) before those events are triggered (conn:connect) to avoid missing some events. Your code
conn:connect(80,'google.com')
conn:on("connection"...
only works because conn:connect is non-blocking and because it takes some time until the connection is established. By the time this happens the on-connection event handler has been registered.
Keeping global variable
time = ""
function getTime(cb)
conn = net.createConnection(net.TCP, 0)
conn:on("connection", function(socket, payload)
socket:send("HEAD / HTTP/1.1\r\n" ..
"Host: google.com\r\n" ..
"Accept: */*\r\n" ..
"User-Agent: Mozilla/4.0 (compatible; esp8266 Lua;)" ..
"\r\n\r\n")
end)
conn:on("receive", function(socket, payload)
socket:close()
time = string.sub(payload, string.find(payload, "Date: ")
+ 6, string.find(payload, "Date: ") + 35)
print("time inside on-receive: " .. time)
cb()
end)
conn:connect(80, 'google.com')
end
function do_something_with_time()
print("time inside callback: " .. time)
end
getTime(do_something_with_time)
Without global variable
function getTime(cb)
conn = net.createConnection(net.TCP, 0)
conn:on("connection", function(socket, payload)
socket:send("HEAD / HTTP/1.1\r\n" ..
"Host: google.com\r\n" ..
"Accept: */*\r\n" ..
"User-Agent: Mozilla/4.0 (compatible; esp8266 Lua;)" ..
"\r\n\r\n")
end)
conn:on("receive", function(socket, payload)
socket:close()
local time = string.sub(payload, string.find(payload, "Date: ")
+ 6, string.find(payload, "Date: ") + 35)
print("time inside on-receive: " .. time)
cb(time)
end)
conn:connect(80, 'google.com')
end
function do_something_with_time(time)
print("time inside callback: " .. time)
end
getTime(do_something_with_time)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With