Quantcast
Channel: Raspberry Pi Forums
Viewing all articles
Browse latest Browse all 8082

MicroPython • Re: Synchronize Pico W RTC to standard time

$
0
0
MicroPython itself has no understanding of time zones, doesn't have support for those in its time functions. 'localtime' is 'gmtime' and both are UTC. I have heard rumours that it will someday support time zones but don't know how that's progressing.
Yup, a problem I found which led me to my SOCKET solution. FWIW, here are the files implementing the RPI 3B+ Server and PICO clients.

SERVER

Code:

# pico_rtc_server: Deliver PICO RTC datetime Tuple from another RPI__version__ = "1.0"__program__ = "pico_rtc_server.py"import syssys.path.append('/media/work/bin') # in case running in /home/pi/src#sys.path.append('/mnt/pi_lib/pico_w/common') # This is not set running in SYSTEMD#sys.path.append('/mnt/pi_lib/common')import socketimport datetime as dtimport pico_rtc_params as paramsfrom log_time import log_timefrom traceback import print_excdef get_rtc_bytes():        # https://docs.micropython.org/en/latest/library/machine.RTC.html#machine-rtc    # RTC Tuple Format (year, month, day, weekday, hours, minutes, seconds, subseconds)    now=dt.datetime.now()    # Construct string representing the RTC tuple    # Need full 8 values    rtc_str=str(now.year)+","+\             str(now.month)+","+\             str(now.day)+","+\             str(now.isoweekday() )+","+\             str(now.hour)+","+\             str(now.minute)+","+\             str(now.second)+","+\             str(0)    # Do not need setting lower than a second        #https://www.geeksforgeeks.org/python-convert-string-to-bytes/    rtc_bytes = bytes(rtc_str, 'utf-8')        return rtc_bytesdef main():        print(log_time("main")+"Program "+__program__+". Version "+__version__)    # Follow log file name convention for wc_* jobs running in production    if not params.debug:          params.log_file=params.log_file_prefix+\                         dt.datetime.now().strftime("%Y-%m-%d_%H%M%S")+".log"        with open(params.log_file,"w") as f:            f.write(log_time("main")+"PICO_RTC_SERVER.LOG")            print(log_time("main")+"Log file = "+params.log_file)     while True:        try:            try:                s.close() # Try to close in case left open from pgm failure            except:                pass            s = socket.socket(socket.AF_INET, \                              socket.SOCK_STREAM)            s.setsockopt(socket.SOL_SOCKET,\                         socket.SO_REUSEADDR, 1) # REUSEADDR to prevent in use error# Don't want to on server side   s.settimeout(params.timeout)            # In case of already in use see https://bobbyhadz.com/blog/socket-error-errno-98-address-already-in-use-in-python            # $ lsof -i :{port)            # $ sudo kill -9 {pid}            s.bind((params.host, params.port))            s.listen()                        while True:# Keep Accepting Calls                conn, addr = s.accept()                with conn:                    with open(params.log_file,"a") as f:                        f.write(log_time("main")+f"Connected by {addr}")                    if params.debug: print(log_time("main")+f"Connected by {addr}")                    data = conn.recv(1024) # Dummy payload to trigger send                    msg=f".... Data {data}"                    with open(params.log_file,"a") as f:                        f.write(log_time("main")+msg)                    if params.debug: print(log_time("main")+msg) # This loop work in simple testing. Don't know why the recv hangs here                    #                     while True:#                         data = conn.recv(1024) # Dummy payload to trigger send#                         if params.debug: print(log_time("main")+f"Data {data}") #                         if not data:#                             break#                      # End of .recv loop                                        rtc_bytes=get_rtc_bytes() # Get RTC tuple in bytes                    msg=f".... Returning {rtc_bytes}"                    with open(params.log_file,"a") as f:                        f.write(log_time("main")+msg)                    if params.debug: print(log_time("main")+msg)                                        conn.sendall(rtc_bytes)                                    # end of conn with            # End of .accept loop                    # This except catches all errors and will restart the socket process        except KeyboardInterrupt:            print("CNTL-C")            return                    except Exception as err:            with open(params.log_file,"a") as f:                f.write(log_time("main")+"Exception caught\n")                print_exc(file=f)            if params.debug:                print(log_time("main")+"Exception "+str(err))                return            # End of main loop#************************************************************************************************if __name__ == '__main__':    main()

Code:

#pico_rtc_server.py Parameters# Common parmsdebug=Falseif debug:    work_dir="."else:    work_dir="/media/work"log_file=work_dir+"/log/pico_rtc_server.log"log_file_prefix=work_dir+"/log/pico_rtc_server_"# Socket parms#host="" # Use empty string so all IP addresses used.host="wethCAM.local"port=65432timeout=5
CLIENT

Code:

# set_rtc(): Set the Real Time Clock on the PICO W# V2 2024-01-26 - Notified that timezone API is no longer free.#                 Switching to SOCKET program call to wethCAM.local to get#                 date and time. See set_rtc.py for previous descriptions.# This function is called by both BOOT.PY and MAIN.PY since the RTC needs to be# updated every few hour.# The PICO W has a RTC but not supported by a battery. That means that# when the PICO loses power, so does the RTC. It will boot up with its# 'epoch' of 2021-01-01 00:00:00.# Getting the correct time in Micropyton is also complicated because# MP does not support time zones.# This V2 function uses a SOCKET call to wethCAM.local to retrieve date/time# Set PICO RTC# https://docs.micropython.org/en/latest/library/machine.RTC.html#class-rtc-real-time-clock# https://mpython.readthedocs.io/en/master/library/micropython/machine/machine.RTC.html# ... it is recommended to perform time calibration every 7 hours.# https://github.com/micropython/micropython/issues/10578# ports/rtc: Inconsistencies between ports and the documentationfrom machine import RTCfrom sys import print_exception# https://docs.micropython.org/en/latest/library/socket.htmlimport socketfrom log_time import log_timeimport rtc_params as paramsdef set_rtc(log_file): # log_file is the name to write log entries to    service_used="pico_rtc_server"        try:        sockaddr = socket.getaddrinfo(params.host, params.port)[0][-1]        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)        s.settimeout(params.timeout)        s.connect(sockaddr)                s.sendall(bytes(log_file, 'utf-8'))# Dummy payload as byte type        rtc_byte= s.recv(1024) # Get RTC payload from wethCAM.local        rtc_str = str(rtc_byte, 'UTF-8') # Convert byte to str        tup = tuple(map(int, rtc_str.split(','))) # Convert str to tuple        rtc=RTC()        rtc.datetime(tup)        s.close()    except Exception as err:            with open(log_file,"a") as f:                f.write(log_time("set_rtc()")+"Exception caught")                print_exception(err,f)            return False, service_used    return True, service_used

Code:

host="wethCAM.local" # wethcam.LOCALport=65432timeout=60 # seconds

Statistics: Posted by DS256 — Sat Apr 05, 2025 2:01 pm



Viewing all articles
Browse latest Browse all 8082

Trending Articles