2015年4月9日 星期四

NodeMCU - NTP Client



今天想到要利用NTP Server 來 Sync 時間 , 搜尋了一下,找到了這個連結 ........


ntp.lua 內容如下:

-- -----------------------------------------------------------------------------------
-- for a continuous run:
-- TIME=loadfile("ntp.lua")()
-- TIME:run(timer,updateinterval,syncinterval,[ntp-server])
-- TIME.hour TIME.minute TIME.second are updated every 'updateinterval'-seconds
-- NTP-server is queried every 'syncinterval'-seconds
--
-- a one-time run:
-- ntprun=loadfile("ntp.lua")
-- ntprun():sync(function(T) print(T:show_time()) end)
--
-- config:
-- choose a timer for udptimer
-- choose a timeout for udptimeout 
--    timer-function to close connection is needed - memory leaks on unanswered sends :(
-- set tz according to your timezoneddddddd
-- choose a NTP-server near you and don't stress them with a low syncinterval :)
-- -----------------------------------------------------------------------------------

return({
    hour=0,
    minute=0,
    second=0,
    lastsync=0,
    ustamp=0,
    tz=8,
    udptimer=2,
    udptimeout=1000,
    ntpserver="193.170.62.252",
    sk=nil,
    sync=function(self,callback)
        -- print("SYNC " .. self.ustamp .. " " .. self.ntpserver)
        -- request string blindly taken from http://arduino.cc/en/Tutorial/UdpNTPClient ;)
        local request=string.char( 227, 0, 6, 236, 0,0,0,0,0,0,0,0, 49, 78, 49, 52,
        0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
        )
        self.sk=net.createConnection(net.UDP, 0)
        self.sk:on("receive",function(sck,payload) 
            -- tmr.stop(self.udptimer)
            sck:close()
            self.lastsync=self:calc_stamp(payload:sub(41,44))
            self:set_time()
            if callback and type(callback) == "function" then 
                callback(self)
            end
            collectgarbage() collectgarbage()
            -- print("DONE " .. self.ustamp)
        end)
        self.sk:connect(123,self.ntpserver)
        tmr.alarm(self.udptimer,self.udptimeout,0,function() self.sk:close() end)
        self.sk:send(request)
    end,
    calc_stamp=function(self,bytes)
        local highw,loww,ntpstamp
        highw = bytes:byte(1) * 256 + bytes:byte(2)
        loww = bytes:byte(3) * 256 + bytes:byte(4)
        ntpstamp=( highw * 65536 + loww ) + ( self.tz * 3600)    -- NTP-stamp, seconds since 1.1.1900
        self.ustamp=ntpstamp - 1104494400 - 1104494400         -- UNIX-timestamp, seconds since 1.1.1970
        -- print(string.format("NTP: %u",ntpstamp))
        -- print(string.format("UIX: %u",self.ustamp))
        return(self.ustamp)
    end,
    set_time=function(self)
        self.hour = self.ustamp % 86400 / 3600
        self.minute = self.ustamp % 3600 / 60
        self.second = self.ustamp % 60
        -- print(string.format("%02u:%02u:%02u",hour,minute,second))
    end,
    show_time=function(self)
        return(string.format("%02u:%02u:%02u",self.hour,self.minute,self.second))
    end,
    run=function(self,t,uinterval,sinterval,server)
        if server then self.ntpserver = server end
        self.lastsync = sinterval * 2 * -1    -- force sync on first run
        tmr.alarm(t,uinterval * 1000,1,function()
            self.ustamp = self.ustamp + uinterval
            self:set_time()
            -- print(self:show_time())
            if self.lastsync + sinterval < self.ustamp then
                self:sync()
            end
        end)
    end
})


測試了一下,真的能用, 輸出如下:

> ntptable=loadfile("ntp.lua")()
> --調整時區設定, 在這我設成台北時間: GMT+8
> ntptable.tz=8
> --設定timerid=1 , 定時每1秒從"tock.stdtime.gov.tw"讀取NTP時間
> ntptable:run(1,1,0,"211.22.103.157")
> print(ntptable:show_time())
05:10:38
> print(ntptable:show_time())
05:11:20


or

> ntpfun=loadfile("ntp.lua")
> ntpfun():sync(function(T) print(T:show_time()) end)
> 05:15:59
ntpfun():sync(function(T) print(T:show_time()) end)
> 05:16:29


or

> ntptable=loadfile("ntp.lua")()
> ntptable:sync(function(T) print(T:show_time()) end)
> 05:15:59
ntptable:sync(function(T) print(T:show_time()) end)
> 05:16:29


註:別忘了要設時區,不然時間會有時差的....

另外,若有需要,可自行依當地時區,再進行日光節約時間校正 .....

以下為台灣國家時間與屏率標準實驗室NTP Server :
tock.stdtime.gov.tw  211.22.103.157
watch.stdtime.gov.tw  118.163.81.63
time.stdtime.gov.tw  118.163.81.61
clock.stdtime.gov.tw  211.22.103.158
tick.stdtime.gov.tw  118.163.81.62






相關參考資料:

鳥哥的Linux 私房菜-- NTP 時間伺服器

NTP 伺服器位址 - 國家時間與頻率標準實驗室

NTP - Wikipedia

夏令時間- 維基百科,自由的百科全書 - Wikipedia