Lua ignores scope variable

This may be a silly question, however, I don't know what's going on.

I have a simple script that picks google time and I need to set it to a global variable time

. This way, inside the event, receive

I print the selected time and it works correctly.

The problem is that the variable is time

always 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)

      

This is how I call the function (using terminal nodemcu-uploader):

➜  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 to

+3


source to share


2 answers


The NodeMCU programming model is similar to Node.js, only in Lua. It is asynchronous and event driven. Therefore, many functions have parameters for callback functions.

Source: https://github.com/nodemcu/nodemcu-firmware/#programming-model

This means that functions that take callback functions as parameters are not blocked. What it returns means that you can't just read a piece of code in turn and expect it to be executed in that order.

So, the sequence of events in the original program is something like this:

  • getTime

    runs but does not block. Performed
  • print("variable: ".. time)

    ... time

    is still empty at this point.
  • A connection to google.com has been established.
  • The HEAD request is sent to google.com.
  • The response is a receive handler for the receive and receive event (i.e. an anonymous callback function).
  • time

    is filled.

I see two obvious fixes, one using your global variable time

and one without it. Both are based on the pass-call-function-as-parameter pattern.

Note that you should always set up event listeners ( conn:on

in your case) prior to firing these events ( conn:connect

) to avoid some events. Your code



conn:connect(80,'google.com')
conn:on("connection"...

      

works only because it is conn:connect

not blocked and because it takes some time until the connection is established. By the time this happens, an on-connection event handler has been registered.

Saving a 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 a 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)

      

+1


source


It looks like the area is fine. Check the order in which the output is printed.



conn:connect

and con:on

perform functions because they are asynchronous. getTime()

just returns before calling them.

+2


source







All Articles