Tuesday, November 1, 2016

ESP8266 getting the right time with the LUA language

Sometimes you need the right time in your projects. For example when you need to registrate a sensor reading at the right time or date. Or you want to make a clock etc. etc. etc.

The easiest way is to put the time in your source code and then start your program. But that is not veryy efficient. Firstly you will get a delay by uploading the program to your ESP, second the build-in hardware times re surely going to deviate from the real time, and last but not least if there is a short power failure the program will start again with the time setting that is pre-programmed.

So I found a LUA program that gets the time on a weblog maintained by Peter Jennings. You can find the weblog here:

http://benlo.com/esp8266/esp8266Projects.html#googleTime

Now lets examine the code.



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
-- retrieve the current time from Google
-- tested on NodeMCU 0.9.5 build 20150108

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

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)
    print('\nRetrieved in '..((tmr.now()-t)/1000)..' milliseconds.')
    print('Google says it is '..string.sub(payload,string.find(payload,"Date: ")
           +6,string.find(payload,"Date: ")+50000))
    conn:close()
    end) 
t = tmr.now()    
conn:connect(80,'google.com') 


Well the code is actually quite simple. It opens a web-connection to google.com then retrieves the information starting with Date: and there we have the time.

So when I loaded the program into my ESP I got the following result:



Anything wrong with that ??
Well yes. Actually I am living in the Netherlands. The program prints GMT time which is 1 hour off. Next there is no difference in summer- and winter- time so that puts the time another hour off. So for me the time is 2 hours off.

Now I could make an adjustment in the software for that but this would make things complicated. So I went looking for anonther solution.

This particular line:

    print('Google says it is '..string.sub(payload,string.find(payload,"Date: ")
           +6,string.find(payload,"Date: ")+35))


actually looks in the retrieved information for the word Date: and prints everything from Date: to the next 35 characters.
So lets expand this and see if we can find any thing interesting in then rest of the retrieved information. So I altered the code in:

    print('Google says it is '..string.sub(payload,string.find(payload,"Date: ")
           +6,string.find(payload,"Date: ")+5000))


And nothing happened. No extra information came up.

So I needed a different source.



I looked at the website time.is this site actually puts the right info on your screen. As the info on the site itself displays: Time.is displays exact, official atomic clock time for any time zone.

So let's see if we can adapt the code from Peter Jennings to our needs.





And there it is, right after the word Expires: the real time at my location.

So the adapted code is:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
-- retrieve the current time from Google

wifi.setmode(wifi.STATION)
wifi.sta.config("XXXXXXXXXXXXX","YYYYYYYYYYYYY")

print("Time Function")
conn=net.createConnection(net.TCP, 0) 

conn:on("connection",function(conn, payload)
 conn:send("HEAD / HTTP/1.1\r\n".. 
 "Host: time.is\r\n"..
 "Accept: */*\r\n"..
 "User-Agent: Mozilla/4.0 (compatible; esp8266 Lua;)"..
 "\r\n\r\n") 
 end)
 
conn:on("receive", function(conn, payload)
 print('Time.is says it is '..string.sub(payload,string.find(payload,"Date: ")
 +6,string.find(payload,"Date: ")+500))
 time = string.sub(payload,string.find(payload,"Expires: ")
 +9,string.find(payload,"Expires: ")+34)
 print("It is now ")
 print(time)
 print (" ")
a = string.sub(time,18,19)
b = string.sub(time,21,22)
print (a .. " hour")
print (b .. " minutes")

print(" ")
print(" ")
print("it is ".. a .. " hour " .. b .. " minutes")

 conn:close()
 end) 
t = tmr.now() 
conn:connect(80,'time.is') 

As you can see I made some small modifcations for your (and mine) convenience. The time is put in the variable called time (duh). I added 2 variables named a and b. They contain the hour and the minutes. This makes it easy to adapt to your own program needs. Next I printed the variables and printed a line in which they are used to display the right time.

Any flaws ???

Yes. Off course there is a pitfall.
The code gets the time from the internet by looking at your IP adress and getting info about this adress from your provider.  However it is possible that your provider is located in a different time-zone. Then you actually will get the time from the time-zone where the main acces-point of your provider is.
Here in the Netherlands that will not be a big problem as we are all in the same time-zone. However if you are living in the States or any other country that is divided in multiple time-zones you might run into a problem. That's worth checking before you use the modified code.

Till next time.
Have fun !!

Luc Volders