Welcome to the Pycom forum Forum
    • \[\[global:header.categories\]\]
    • \[\[global:header.recent\]\]
    • \[\[global:header.tags\]\]
    • \[\[global:header.popular\]\]
    • Login

    Explore Pybytes | Official Documentation | Report a Firmware Bug/Issue | GitHub

    Syncing RTC To Network Time

    Scheduled Pinned Locked Moved LoPy
    24 Posts 8 Posters 13.8k Views 10 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • D Offline
      dchappel
      last edited by

      Documentation states:

      "The current calendar time may be set using machine.RTC().datetime(tuple) function, and maintained by following means:

      • By a backup battery (which may be an additional, optional component for a particular board).

      • Using networked time protocol (requires setup by a port/user).

      • Set manually by a user on each power-up (many boards then maintain RTC time across hard resets, though some may require setting it again in such case)."

      Does anyone have a simple way they have come up with to sync the RTC to an open network source (bullet 2 above)?

      C 1 Reply Last reply Reply Quote 0
      • K Offline
        Knoahlr
        last edited by Knoahlr

        @dchappel
        In my boot.py after connecting to WiFi, I open up a socket and query the NIST servers, they provide UTC time accurate to the second. You can the parse the string and initialize your RTC from there.
        This is all you have to do. However, time will differ, unless you live on the prime meridian.

        >>import socket
        >>s=socket.socket()
        >>s.connect(socket.getaddrinfo("time.nist.gov",13)[0][-1])
        >>s.recv(1024)
        >>'\n57777 17-01-24 16:42:49 00 0 0 595.8 UTC(NIST) * \n'
        

        Im using an older firmware that doesn`t include the RTC class, so I have a formula to calculate the epoch time during boot and save it to a variable. This works for most applications as epoch time is more common.

        Hope this helps.

        1 Reply Last reply Reply Quote 0
        • C Offline
          crankshaft @dchappel
          last edited by

          @dchappel - to communicate with a ntp server you need the socket.sendto(), however I believe this is not implemented yet.

          Also, the rtc interrupts is not implemented yet, so you can't really power down the device int low power mode and wake it up again.

          The RTC module is there, but in my opinion it is not yet usable.

          1 Reply Last reply Reply Quote 1
          • T Offline
            thefebruaryman
            last edited by thefebruaryman

            I have been looking at the same issue tonight and came up with this script

            # imports
            from machine import Pin
            import pycom
            import time
            import ustruct
            from machine import RTC
            import socket
            from socket import AF_INET, SOCK_DGRAM
            
            pycom.heartbeat(False)
            
            rtc = RTC()
            rtc.init((1970, 0, 0, 0, 0, 0, 0, 0))
            
            def getNTPTime(host = "pool.ntp.org"):
                port = 123
                buf = 1024
                address = socket.getaddrinfo(host,  port)[0][-1]
                msg = '\x1b' + 47 * '\0'
                msg = msg.encode()
                TIME1970 = 2208988800 # 1970-01-01 00:00:00
            
                # connect to server
                client = socket.socket(AF_INET, SOCK_DGRAM)
                client.sendto(msg, address)
                msg, address = client.recvfrom(buf)
                t = ustruct.unpack("!12I", msg)[10]
                t -= TIME1970
                rtc.calibration(t)
                return t
            
            def pin_handler(arg):
                print("Got an interrupt in pin %s" % (arg.id()))
                pycom.rgbled(0x0000ff)
                time.sleep(1)
                pycom.rgbled(0x000000)
                print(getNTPTime())
                print(rtc.now())
            
            # use the button on the expansion board  P10
            p_in = Pin('G17',  mode=Pin.IN,  pull=Pin.PULL_UP)
            # on button push trigger pin_handler
            p_in.callback(Pin.IRQ_FALLING,  pin_handler)
            

            however the calibration method doesn't like it

            >>> Got an interrupt in pin P10
            Unhandled exception in interrupt handler
            Traceback (most recent call last):
            File "<stdin>", line 36, in pin_handler
            File "<stdin>", line 28, in getNTPTime
            OverflowError: overflow converting long int to machine word
            
            L 1 Reply Last reply Reply Quote 0
            • L Offline
              livius @thefebruaryman
              last edited by

              @thefebruaryman

              what you got when you do?:
              print(str(ustruct.unpack("!12I", msg)[10]))

              think about people first, then computers

              1 Reply Last reply Reply Quote 0
              • T Offline
                thefebruaryman
                last edited by

                t = ustruct.unpack("!12I", msg)[10]
                

                returns

                1485764691
                

                which in python I can normally

                >>> time.ctime(1485764691)
                'Mon Jan 30 08:24:51 2017'
                
                L 1 Reply Last reply Reply Quote 0
                • L Offline
                  livius @thefebruaryman
                  last edited by

                  @thefebruaryman
                  ok - then you succesfully got value
                  but issue is in calibration procedure
                  but i suppose you can fix problem by setting time by

                  ct = time.ctime(t)
                  rtc.init((ct[0], ct[1], ct[2], ct[3], ct[4], ct[5], 0, 0))
                  

                  think about people first, then computers

                  1 Reply Last reply Reply Quote 0
                  • D Offline
                    dchappel
                    last edited by dchappel

                    Here is what I came up with (builds on Knoahlr contribution below):

                    import socket
                    import machine
                    
                    s=socket.socket()
                    s.connect(socket.getaddrinfo("66.199.22.67",13)[0][-1])
                    r=s.recv(1024).decode()
                    s.close()
                    
                    year = 2000 + int(r[6:9])
                    month = int(r[10:12])
                    day = int(r[13:15])
                    hour = int(r[16:18])
                    min = int(r[19:21])
                    sec = int(r[22:24])
                    rtc = machine.RTC()
                    rtc.init((year, month, day, hour, min, sec, 0, 0))
                    print(rtc.now())
                    

                    Current time (in seconds since 1970 / UNIX time) is now available using utime.time().

                    I found that I needed to use the numeric IP address for NIST. Alpha URL gave me a timeout. Since I got it to work with numeric I didn't go back and try to understand why...

                    K 1 Reply Last reply Reply Quote 0
                    • K Offline
                      Knoahlr @dchappel
                      last edited by Knoahlr

                      @dchappel You might want to use RegEX,
                      Assuming Current time is your response from the NIST server.

                      >>import re
                      >>CurrentTime='\n57783 17-01-30 16:14:50 00 0 0  37.8 UTC(NIST) * \n'
                      >>DateList=re.search("[0-9]+-[0-9]+-[0-9]+",CurrentTime).group(0).split("-")
                      >>DateList
                      ['17', '01', '30']
                      >>TimeList=re.search("[0-9]+:[0-9]+:([0-9]+.[0-9]+)",CurrentTime).group(0).split(":")
                      >>TimeList
                      ['16', '14', '50 00']
                      

                      Cheers.

                      1 Reply Last reply Reply Quote 0
                      • T Offline
                        thefebruaryman
                        last edited by

                        Ok I got it. I have to use utime for localtime method to work with the large int else you get an error.

                        from machine import Pin
                        import pycom
                        import utime
                        import ustruct
                        from machine import RTC
                        import socket
                        from socket import AF_INET, SOCK_DGRAM
                        
                        pycom.heartbeat(False)
                        
                        rtc = RTC()
                        rtc.init((1970, 0, 0, 0, 0, 0, 0, 0))
                        
                        def getNTPTime(host = "pool.ntp.org"):
                            port = 123
                            buf = 1024
                            address = socket.getaddrinfo(host,  port)[0][-1]
                            msg = '\x1b' + 47 * '\0'
                            msg = msg.encode()
                            TIME1970 = 2208988800 # 1970-01-01 00:00:00
                        
                            # connect to server
                            client = socket.socket(AF_INET, SOCK_DGRAM)
                            client.sendto(msg, address)
                            msg, address = client.recvfrom(buf)
                            t = ustruct.unpack("!12I", msg)[10]
                            t -= TIME1970
                            tuple_time = utime.localtime(t)
                            rtc.init((tuple_time))
                            client.close()
                        
                        
                        def pin_handler(arg):
                            print("Got an interrupt in pin %s" % (arg.id()))
                            pycom.rgbled(0x0000ff)
                            utime.sleep(1)
                            pycom.rgbled(0x000000)
                            getNTPTime()
                            print(rtc.now())
                        
                        # use the button on the expansion board  P10
                        p_in = Pin('G17',  mode=Pin.IN,  pull=Pin.PULL_UP)
                        # on button push trigger pin_handler
                        p_in.callback(Pin.IRQ_FALLING,  pin_handler)
                        
                        1 Reply Last reply Reply Quote 1
                        • A Offline
                          abilio
                          last edited by abilio

                          We've just finished adding support for a NTP (SNTP) client. Syncing time will be as easy as:

                          import machine
                          rtc = machine.RTC()
                          rtc.ntp_sync("pool.ntp.org") # select an appropriate server
                          

                          By default it will resync every hour, but you can change the period by passing it as a parameter: rtc.ntp_sync("pool.ntp.org", 1200) # do it every 20 minutes

                          This feature will probably be included in the next release. Hope you'll find it useful.

                          T K R 3 Replies Last reply Reply Quote 4
                          • T Offline
                            thefebruaryman @abilio
                            last edited by

                            @abilio that's great news and much easier to use. Cheers for the good work!

                            1 Reply Last reply Reply Quote 0
                            • K Offline
                              Knoahlr @abilio
                              last edited by

                              @abilio Will the method sync the RTC to local time or UTC ?

                              A 1 Reply Last reply Reply Quote 0
                              • A Offline
                                abilio @Knoahlr
                                last edited by abilio

                                @Knoahlr, to UTC, but then you'll be able to set the time offset calling:

                                time.timezone(3600) # GMT +1 for the Netherlands
                                

                                A call to time.localtime() will return the time using the provided offset. If you want the number of seconds since Epoch adjusted to the timezone, you can do something like:

                                time.time() + time.timezone()
                                

                                Also, time.gmtime() will be included, working like time.localtime(), but without adjusting for the offset.

                                So far, this is what would be available in the release.

                                K 1 Reply Last reply Reply Quote 0
                                • K Offline
                                  Knoahlr @abilio
                                  last edited by

                                  @abilio Great, amazing feature.

                                  1 Reply Last reply Reply Quote 0
                                  • R Offline
                                    rdixey @abilio
                                    last edited by

                                    @abilio Apparently this is not yet implemented in 1.6.1.b1 ?

                                    '1.6.1.b1'
                                    >>> os.uname()
                                    (sysname='LoPy', nodename='LoPy', release='1.6.1.b1', version='v1.8.6-450-g31ef5170 on 2017-02-15', machine='LoPy with ESP32', lorawan='1.0.0')
                                    >>> import machine
                                    >>> rtc = machine.RTC()
                                    >>> rtc.ntp_sync("pool.ntp.org")
                                    Traceback (most recent call last):
                                      File "<stdin>", line 1, in <module>
                                    AttributeError: 'RTC' object has no attribute 'ntp_sync'
                                    >>> 
                                    >>> import time
                                    >>> time.timezone(3600)
                                    Traceback (most recent call last):
                                      File "<stdin>", line 1, in <module>
                                    AttributeError: 'module' object has no attribute 'timezone'
                                    
                                    A 1 Reply Last reply Reply Quote 0
                                    • A Offline
                                      abilio @rdixey
                                      last edited by

                                      @rdixey, you are totally right and I must personally apologize for it. We forgot to merge it with master just to realize it after making the release (yeah, it happened twice :( ) . I will work so is included in the next firmware release.

                                      R 1 Reply Last reply Reply Quote 0
                                      • R Offline
                                        rdixey @abilio
                                        last edited by

                                        @abilio These new rtc.ntp_sync() & time.timezone() functions work nicely with the 1.6.4.b1 update. They are very convenient!

                                        I think there is a typo on the Utime doc page though. The first function listed there is utime.mktime([secs]), is this intended to be utime.gmtime()?

                                        Thanks for the good work on this :)

                                        L S 2 Replies Last reply Reply Quote 0
                                        • L Offline
                                          livius @rdixey
                                          last edited by

                                          @rdixey said in Syncing RTC To Network Time:

                                          mktime

                                          It is standard in many languages - google for it ;-)

                                          think about people first, then computers

                                          R 1 Reply Last reply Reply Quote -1
                                          • S Offline
                                            santorcuato @rdixey
                                            last edited by

                                            @rdixey said in Syncing RTC To Network Time:

                                            @abilio These new rtc.ntp_sync() & time.timezone() functions work nicely with the 1.6.4.b1 update. They are very convenient!

                                            I think there is a typo on the Utime doc page though. The first function listed there is utime.mktime([secs]), is this intended to be utime.gmtime()?

                                            Thanks for the good work on this :)

                                            Its not working for me :-(

                                            Can you post a working example?

                                            Thanks!

                                            R 1 Reply Last reply Reply Quote 0

                                            Hello! It looks like you're interested in this conversation, but you don't have an account yet.

                                            Getting fed up of having to scroll through the same posts each visit? When you register for an account, you'll always come back to exactly where you were before, and choose to be notified of new replies (either via email, or push notification). You'll also be able to save bookmarks and upvote posts to show your appreciation to other community members.

                                            With your input, this post could be even better 💗

                                            Register Login
                                            • 1
                                            • 2
                                            • 1 / 2
                                            • First post
                                              Last post

                                            Pycom on Twitter

                                            Pycom