![]() |
Forum Index : Microcontroller and PC projects : NTP Clock
Author | Message | ||||
jman![]() Guru ![]() Joined: 12/06/2011 Location: New ZealandPosts: 711 |
Hi After much trial and error with NTP I finally have a working clock. Two challenges had to be over come. 1st how to send a valid request via UDP 2nd decipher the response from the NTP Server The request is done via UDP and consists of a 48 Bytes the 1st byte is the important one as this contains the LI, Version and Mode so we set the byte with the following LI 00 = no warning (2 bits) VN 010 = version 2 (3bit) Mode 111 = reserved for private use (I assume I am private :) ) so the first byte = &B1011 or 23 decimal or Chr$(27) that's what we have to use to send the correct value via the com port (Would be a great feature to be able to send hex values from via the com port) The returned data consists of 48 bytes with the data we are after in bytes 40-43 the value of the returned data is a 32 bit number made up of the 4 bytes with byte 40 MSB and byte 43 LSB. This number is the number of seconds since 00:00:00 1/1/1900 to get to Epoch time (1/1/1970) we need to - 2208988800 (Seventy years in seconds) From there we can work out the time. If anybody has better or cleaner way to convert the Epoch time to human readable time please do share. To connect to the internet this system uses an ESP8266 WiFi module connected to com1 these are really cheap and make a great way to connect a Mite to the internet note we are NOT concerned or using the advanced NTP features such as request latency etc.. ' Configuration constants TZ = 12 'From GMT (+ or -) PowerSave=0 '1 moudule Off after update 0 Allways On '1 Will cause a small delay during update UpDate=60 'Update frequency in Minutes DST=1 '1 Use DST 0 Disable DMS=9 'Month DST Time Starts DHS=2 'DST Start Hour DME=4 'Month DST Time Starts DHE=3 'DST Stop Hour SSID$ = "PutYourSSIDHere" 'name of wireless access point To connect To PASS$ = "Password" 'WiFi Password Port$ = "123" 'NTP UDP port NTP$="27.116.36.44" 'NTP Server you want to use SetPin 14,DOUT Dim Months(12) 'Array for Months For I=1 To 12 Read Months(I) Next I Dim Days$(7) For I=0 To 6 Read Days$(I) Next I Dim Mnths$(12) 'Array for Months Names For I=1 To 12 Read Mnths$(I) Next LeapMnth=2505600 'Seconds in Leap Year February Lcount=48 Dim Line$(48) 'UDP data array Memory PWM 2, 2500, 2, 10 'Adjust Freqency for contrast adjustment LCD Init 2, 3, 4, 5, 6, 7 'Setup the LCD for display Reset Open "COM1:115200, 1024" As #1 'Module must be set to same rate Print #1, "AT+CWMODE=1" Pause 1000 Print #1, "AT+CIPMUX=0" ' Set Single connection Pause 2000 ConnectToWiFi: LCD Clear Print #1,"AT+CWJAP="+Chr$(34)+SSID$+Chr$(34)+","+Chr$(34)+PASS$+Ch r$(34) LCD 1, 1, "Connecting To" LCD 2, 1, SSID$ Pause 8000 'give it time to connect Flushbuf Print #1, "AT+CIFSR" Pause 1500 Line Input #1,IP$ Line Input #1,IP$ Line Input #1,IP$ LCD 1, 1, "Connected IP " LCD 2, 1, IP$ Print IP$ Line$(1)=Chr$(27) '1st byte Minimum requirement for valid respone Line$(2)="" 'Incase we end up back here For I = 1 To 47 'Load next 47 bytes with null Line$(2)=Line$(2)+Chr$(0) Next I GetNTPTime: flushbuf Print #1, "AT+CIPSTART="+Chr$(34)+"UDP"+Chr$(34)+","+Chr$(34)+NTP$+Chr $(34)+",123" Delay Print #1,"AT+CIPSEND=48" '+Str$(Len(&hE3)) Delay Print #1, Line$(1)+Line$(2) '+Line$(3)+Line$(4); Delay Print #1, "AT+CIPCLOSE" Pause 1500 For I =1 To 10 Line Input #1,IP$ 'Unrelated info Print IP$ Next I IP$ = Input$(1, #1) Print ip$ IP$ = Input$(8, #1) ' Sanity Check If Ip$<> "+IPD,48:" Then Print "Connection Error" LCD Clear LCD 1, 1, "Connection Error" LCD 2, 1, "Retrying" Pause 3000 GoTo ConnectToWiFi EndIf IP$ = Input$(48, #1) flushbuf lw1$=Str$(Asc(Mid$(ip$,41,1))) 'Extract 1st Byte lw2$=Str$(Asc(Mid$(ip$,42,1))) 'Extract 2nd Byte lw3$=Str$(Asc(Mid$(ip$,43,1))) 'Extract 3rd Byte lw4$=Str$(Asc(Mid$(ip$,44,1))) 'Extract 4th Byte lb1% = Val(lw1$) << 8 lb1% = (lb1% Or Val(lw2$)) <<16 'MSB 32 Bit Number lb2% = Val(lw3$) << 8 lb2% = lb2% Or Val(lw4$) 'LSB 32 Bit Number LB%=LB1% Or LB2% LB% = LB% - 2208988800 ' - 70 Years start @ 1/1/1970 Epoch time Jan2014 = LB% - 1388534400 'Start at Jan 1/1/2014 TimeZone = (TZ*60*60) 'Set TimeZone Jan2014=Jan2014+TimeZone 'Adjust for Timezone Year=2014 'Set Year to 2014 GetYear: LEAP = Year Mod 4 '0 if leap year If LEAP = 0 Then SecondsInYear = 31622400 '366*60*60**24 Else SecondsInYear = 31536000 '365*60*60*24 EndIf If Jan2014 > SecondsInYear Then Jan2014 = Jan2014 - SecondsInyear Year = Year + 1 GoTo GetYear EndIf Month = 1 ' Start with Month = 1 GetMonth: SecondsInMonth = Months(Month) If Leap = 0 Then If Month = 2 Then SecondsInMonth=LeapMnth EndIf EndIf If Jan2014 >= SecondsInMonth Then Jan2014 = Jan2014 - SecondsInMonth Month = Month+1 GoTo GetMonth EndIf FindDays: Day = Int(Jan2014/86400) Jan2014 = Jan2014 Mod 86400 Hour = Int(Jan2014/3600) Jan2014 = Jan2014 Mod 3600 Min = Int(Jan2014/60) Jan2014 = Jan2014 Mod 60 Sec = Jan2014 Day = Day + 1 If DST = 1 Then GoSub DsTime If CurrDT < DsStop Or CurrDT > DsStart Then Hour = Hour + 1 EndIf EndIf If Hour=24 Then hour=0 Date$=Str$(Day)+"/"+Str$(Month)+"/"+Str$(Year) Time$=Str$(Hour)+":"+Str$(Min)+":"+Str$(Sec) Print Time$ Print Date$ LCD Clear Timer=0 Do While Timer < (UpDate*60*1000) 'Update frequency DayOfWeek LongDate$=Days$(Dow)+" "+Left$(Date$,2)+" "+Mnths$(Val(Mid$(Date$,4,2))) LengthCheck: If Len(LongDate$) < 16 Then LongDate$=LongDate$+" " GoTo LengthCheck EndIf LCD 1, 1, LongDate$ LCD 2, 1, "NTP "+Time$ If PowerSave=1 Then Pin(14)=0 'PowerSave Loop Pin(14)=1 If PowerSave Then Pause 5000 LCD 2, 1, "Updating.. " GoTo GetNTPTime End DsTime: 'DSTime is used to find the stop and start dates for DST 'Reference http://delphiforfun.org/programs/math_topics/dstcalc.htm Local YT YT=Int((5*Year)/4) DsdStop=7-((4+YT) Mod 7) 'NZ 1st Sunday in April DsdStart=31-((YT-1) Mod 7) 'NZ Last Sunday in September 'You will need modify the above lines to suit your DST 'DsdStart=14-((1+Year*5/4) mod 7) 'USA 2nd Sunday in March 'DsdStop=7-((1+YT) mod 7) 'USA 1st Sunday November 'DsdStart=31-((4+YT) mod 7) 'EU Last sunday in March 'DsdStop=31-((1+YT) mod 7) 'EU Last Sunday October DsStart=(DMS*10000)+(DsdStart*100)+DHS DsStop=(DME*10000)+(DsdStop*100)+DHE CurrDT=(Val(Mid$(Date$,4,2))*10000)+(Day*100)+Hours Return Sub DayOfWeek 'TZ's Method A = Int((14-Val(Mid$(Date$,4,2)))/12) M = Val(Mid$(Date$,4,2)) + 12*a - 2 Y = Val(Mid$(Date$,7,4)) -a D = Val(Mid$(Date$,1,2)) Dow=(D+Y+Int(Y/4)-Int(y/100)+Int(Y/400)+Int(31*M/12)) Mod 7 End Sub Sub Delay Pause 500 End Sub Sub FLUSHBUF Do:Z$=Input$(1,#1):Loop While Loc(#1) <> 0 End Sub Sub Reset Pin(14)=0 ' Reset Module Disabled Pause 500 Pin(14)=1 End Sub Data 2678400,2419200,2678400,2592000,2678400,2592000,2678400 Data 2678400,2592000,2678400,2592000,2678400 Data "Sunday","Monday","Tuesday","Wednesday","Thursday" Data "Friday","Saturday" Data "Jan","Feb","Mar","Apr","May","June" Data "July","Aug","Sep","Oct","Nov","Dec" Regards Jman |
||||
viscomjim Guru ![]() Joined: 08/01/2014 Location: United StatesPosts: 925 |
Hi Jman, again, a very cool project using the esp8266. Nice work. Have you run across any issues with the 8266 and the "busy s..." response from it? Looking at different sources, it seems like this creeps up every once in a while making things a bit of a pain. When I do encounter it, it seems like the only way out is a power cycle, (for me anyway). I see that Expressif has added new .bin files today. I am hoping that will fix some of the issues. Thanks again for a great project! |
||||
jman![]() Guru ![]() Joined: 12/06/2011 Location: New ZealandPosts: 711 |
Hi Viscomjim When you get the "busy s..." problem have you tried a AT+RST ? Regards Jman |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6266 |
A good bit of detective work, sorting out the NTP packets and a good example of the esp8266. I prefer wired ethernet but I have realised that the price of the esp8266 is a lot cheaper and easier to use than any ethernet solution. Geoff's article in December Silicon Chip makes then too good to ignore! I have just started a new post with unix time routines that may be of interest. Jim VK7JH MMedit |
||||
viscomjim Guru ![]() Joined: 08/01/2014 Location: United StatesPosts: 925 |
@Jman, yes, I have done the AT+RST and also a hardware reset like it looks like you do. It is hard to pin down this error and what actually works to correct it, but for now the power cycle is 100%, which for me is a fail. I am hoping the new .bin files have corrected the problem. Again, its not all the time, just seems somewhat random... |
||||
centrex![]() Guru ![]() Joined: 13/11/2011 Location: AustraliaPosts: 320 |
A bit off topic but dealing with the ESP8266 module. The article in Silicon Chip page 32 Nov2014, the connections are not correct pin 23 should be pin 21 on the micromite. cliff Jman thanks for the code. Cliff |
||||
paceman Guru ![]() Joined: 07/10/2011 Location: AustraliaPosts: 1329 |
Here's the Australian Daylight Saving Time info for JMan's "dstime" routine. From April 2008, Daylight Saving dates have been synchronised across Tasmania, New South Wales, Victoria, the ACT and South Australia, although South Australia remains half an hour behind throughout the year due to the observance of Australian Central Standard Time. Daylight saving time commences at 2am (AEST) on the first Sunday in October and ending at 2am AEST (3am DST) on the first Sunday in April. Queensland, West Australia and the Northern Territory do not observe Daylight saving. Greg |
||||
WhiteWizzard Guru ![]() Joined: 05/04/2013 Location: United KingdomPosts: 2931 |
Please can someone let me know what this article is . . . ![]() Thanks WW |
||||
centrex![]() Guru ![]() Joined: 13/11/2011 Location: AustraliaPosts: 320 |
my note about the connection to the ESP module should have read Dec issue of Silicon Chip. White Wizard, Geoffg has written an article in the magazine on the use of the module and a pointer to a web site http://garden.geoffg.net which gives the temp and humidity in his garden it also has a pointer to the software that runs the device. As far as getting a copy of the article you may have to Google Silicon Chip or someone may be able to purchase the magazine and fwd it to you. It is a worthwhile read and along with Jman code very helpful. regards cliff Cliff |
||||
WhiteWizzard Guru ![]() Joined: 05/04/2013 Location: United KingdomPosts: 2931 |
Thanks for the info Cliff. Just checked it out and I reckon Geoff has a bug in his code - 19.7°C at 05:23 (surely not!!!!) ![]() |
||||
BobD![]() Guru ![]() Joined: 07/12/2011 Location: AustraliaPosts: 935 |
it was a warm night last night. We had 25.1 at 4:30am and Melbourne CBD was a bit higher. |
||||
WhiteWizzard Guru ![]() Joined: 05/04/2013 Location: United KingdomPosts: 2931 |
You must be running the same 'buggy' code as Geoff! ![]() |
||||
plasma Guru ![]() Joined: 08/04/2012 Location: GermanyPosts: 437 |
Thx a lot for the code |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |