Python二进制时钟脚本添加定时NTP时间同步功能求助
二进制时钟NTP自动校准实现方案
核心改动点
- 内置纯标准库实现的NTP客户端,无需安装第三方依赖,直接向公共NTP服务器拉取标准时间,不依赖系统自身的时间同步
- 采用单调时钟计算时间流逝,避免系统时间跳变导致显示错乱
- 可自定义同步间隔、时区偏移、NTP服务器地址
- 带异常兜底:NTP请求失败时自动沿用最后一次校准的时间继续运行,不会中断时钟显示
- 脚本启动时立即执行第一次同步,无需等待首个同步周期
关键配置说明
SYNC_INTERVAL:同步间隔,单位秒,默认设置为2小时(2*3600),可根据需求自行修改TIMEZONE_OFFSET:时区偏移,单位秒,国内使用东八区设为8*3600即可,其他时区按实际偏移调整- NTP服务器默认使用阿里云公共NTP(
ntp.aliyun.com),国内访问延迟低,海外使用可替换为pool.ntp.org - NTP请求默认设置2秒超时,不会因为网络问题阻塞主循环
修改后完整代码
#!/usr/bin/env python3 '''A binary clock: displays the current time (HHMMSS) in binary-coded decimal.''' import time import socket import struct from itertools import zip_longest from gpiozero import LED def get_ntp_time(server='ntp.aliyun.com', port=123, timeout=2): """从指定NTP服务器获取当前UTC时间戳(Unix时间,1970年起算)""" # 构造NTP客户端请求报文 ntp_packet = b'\x1b' + 47 * b'\0' with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as sock: sock.settimeout(timeout) sock.sendto(ntp_packet, (server, port)) resp_data, _ = sock.recvfrom(48) # 解析返回报文中的传输时间戳 tx_timestamp = struct.unpack('!12I', resp_data)[10] # NTP时间从1900年起算,转换为Unix时间戳需减去70年的秒数差 return tx_timestamp - 2208988800 def bcd(digits): 'Convert a string of decimal digits to binary-coded-decimal.' def bcdigit(d): 'Convert a decimal digit to BCD (4 bits wide).' # [2:] strips the '0b' prefix added by bin(). return bin(d)[2:].rjust(4, '0') return (bcdigit(int(d)) for d in digits) def vertical_strings(strings): 'Orient an iterable of strings vertically: one string per column.' iters = [iter(s) for s in strings] concat = ''.join return ''.join(map(concat, zip_longest(*iters, fillvalue=' '))) def light(strings, leds): x = 0 for l in strings: if l == '1' and leds[x] is not None: leds[x].on() elif l == '0' and leds[x] is not None: leds[x].off() x = x + 1 def main(): # H8 M8 S8 leds = [ None, LED(14), None, LED(24), None, LED(12), # H40 H4 M40 M4 S40 S4 LED(22), LED(15), LED(11), LED(25), LED(13), LED(16), # H20 H2 M20 M2 S20 S2 LED(10), LED(18), LED(5), LED(8), LED(19), LED(20), # H10 H1 M10 M1 S10 S1 LED(9), LED(23), LED(6), LED(7), LED(26), LED(21)] # 校准参数配置 SYNC_INTERVAL = 2 * 3600 # 同步间隔:2小时 TIMEZONE_OFFSET = 8 * 3600 # 时区偏移:东八区 time_offset = 0 last_sync_time = -SYNC_INTERVAL # 启动立即触发第一次同步 try: while True: current_mono = time.monotonic() # 到达同步间隔时执行NTP同步 if current_mono - last_sync_time >= SYNC_INTERVAL: try: ntp_utc = get_ntp_time() # 计算时间偏移:校准后的本地时间 = 单调时钟值 + time_offset time_offset = ntp_utc + TIMEZONE_OFFSET - current_mono last_sync_time = current_mono sync_success_t = time.strftime('%H%M%S', time.gmtime(current_mono + time_offset)) print(f"NTP同步成功,当前标准时间:{sync_success_t}") except Exception as e: print(f"NTP同步失败:{str(e)},将沿用上次校准结果继续运行") # 用校准后的时间生成时分秒 current_ts = current_mono + time_offset t = time.strftime('%H%M%S', time.gmtime(current_ts)) print(t) b = bcd(t) s = vertical_strings(b) print(s + '\n') light(s, leds) time.sleep(0.2) except KeyboardInterrupt: print('done') if __name__ == '__main__': main()
实现说明
- 时间计算全程使用
time.monotonic()单调时钟,该时钟只会单调递增,不会被系统时间调整、手动改时间等操作影响,不会出现时间回退、跳变导致LED显示错乱的问题 - 同步逻辑不会阻塞主显示循环,即使NTP请求超时也只会等2秒就继续运行,LED刷新保持原有的0.2秒间隔不受影响
- 所有NTP协议逻辑均用Python标准库实现,树莓派上无需额外执行
pip install安装依赖,替换原脚本即可直接运行
内容的提问来源于stack exchange,提问作者dandspach
相关产品推荐
相关产品推荐

