Lua script does not execute in sequence

3.4k Views Asked by At

I want to get the time using an EPS8266 with nodeMCU to set my RTC over I2C.

This is my sript:

-- file print.lua     
local file = assert(loadfile("httpget.lua"))    
file()                  --get Date and Time from google    
print("Print follows:") --this should be executed after "file()"    
print(date)

This is file httpget.lua:

-- file httpget.lua
print('httpget.lua started')
conn=net.createConnection(net.TCP, 0)
-- show the retrieved web page
conn:on("receive", function(conn, payload) 
                     date = string.sub(payload,string.find(payload,"Date: ")
                     +6,string.find(payload,"Date: ")+35)
                     conn:close()
                     end) 

conn:on("connection", function(conn, payload) 
                       print('\nConnected') 
                       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)

-- when disconnected, let it be known
conn:on("disconnection", function(conn, payload)
                         print("Disconnected\r\n"..date)
                         end)                                             
conn:connect(80,'google.com')
conn = nil

The result is:

> dofile("print.lua")
httpget.lua started
Print follows:              -- this should be at the end
nil                         -- date==nil because httpget.lua not executed
> 
Connected
Disconnected
Sun, 26 Apr 2015 10:30:03 GMT

If I execute the scipt again (without reset), I get date from the execution before. What can I do to execute "httpget.lua" and get the "date" in the scipt that follows?

I use a ESP8266 with NodeMCU 0.9.6 build 20150406 powered by Lua 5.1.4. https://github.com/nodemcu/nodemcu-firmware/wiki/nodemcu_api_en#index

I load the sripts via USB with ESPlorer v2.0 to my ESP8266. The conn.net... commands are part of the NodeMCU firmware (see link). You can only run the script with an EPS8288 and NodeMCU firmware. My problem is: I find no way to end conn:net routine properly and return data to the next programm part.

2

There are 2 best solutions below

0
On

As the commenters point out the network code will run asynchronously, i.e. the conn:on calls will return immediately and their callbacks are invoked at a later point. The conn:connect call is probably not asynchronous, but that doesn't help.

Directly after the conn:connect call finishes your print calls will run, trying to print the global variable date. Most of the time this will print nil since the network latency to fetch the data from Google will be in the >10's of milliseconds which means your code has already had plenty of time to execute the print statements. In some rare occasions you might actually get the correct date, if you are really lucky with the network latency (that would be very surprising though).

To resolve this you need to put the code to be executed on the completion of the network request in a callback that you pass to the conn:on that receives the data. In your current code structure this is a bit difficult to do in a nice way though.

A simple solution is to do:

local function onReceiveCb(str)
 print("Print follows:")
 print(str)
end
local file = assert(loadfile("httpget.lua"))
....

Note that I've added a onReceiveCb function before including the httpget code. In httpget you invoke the callback:

conn:on("receive", function(conn, payload) 
                     date = string.sub(payload,string.find(payload,"Date: ")
                     +6,string.find(payload,"Date: ")+35)
                     conn:close()
                     onReceiveCb(date) -- Call the callback!
                     end) 
1
On

The proposal with the callback function did not work. I got a compiler error. I have solved it now in an other way. In the conn:on("disconnection", function(conn, payload), I load the file to set my RTC. This way I can pass data to the program which sets the RTC. (see my output)

Thanks for your help!!!

> dofile("httpget.lua");
httpget.lua started
> 
Connected
Disconnected

----------------
Date: Mon, 27 Apr 2015 12:02:17 GMT -- printed in httpget.lua
Date: Mon, 27 Apr 2015 12:02:17 GMT -- printed in set_date.lua
Set RTC:
23 2 19 2 39 4 21  -- Bytes 0-6 in decimal of the DS1307 (1h for Daylight Savings Time added)
done

--This is the working script:

print('httpget.lua started')

conn=net.createConnection(net.TCP, 0) 

-- show the retrieved web page
conn:on("receive", function (conn, payload)  
                     date = string.sub(payload,string.find(payload,"Date: ")
                     +0,string.find(payload,"Date: ")+35)
                     conn:close()
                     end) 

-- when connected, request page (send parameters to a script)
conn:on("connection", function(conn, payload) 
                       print('\nConnected') 
                       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)

-- when disconnected, let it be known
conn:on("disconnection", function(conn, payload)
                         print("Disconnected\r\n")
                         print("----------------")
                         print(date)
                         dofile("set_date.lua");
                         end)

conn:connect(80,'google.com')
conn=nil