#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 时间同步模块 从4G模块获取时间并同步到系统 """ import re import os from datetime import datetime, timedelta import config # from logger_bak import get_logger from logger_manager import logger_manager def parse_4g_time(cclk_response, timezone_offset=8): """ 解析 AT+CCLK? 返回的时间字符串,并转换为本地时间 Args: cclk_response: AT+CCLK? 的响应字符串 timezone_offset: 时区偏移(小时),默认8(中国时区 UTC+8) Returns: datetime 对象(已转换为本地时间),如果解析失败返回 None """ try: # 匹配格式: +CCLK: "YY/MM/DD,HH:MM:SS+TZ" # 时区单位是四分之一小时(quarters of an hour) match = re.search(r'\+CCLK:\s*"(\d{2})/(\d{2})/(\d{2}),(\d{2}):(\d{2}):(\d{2})([+-]\d{1,3})?"', cclk_response) if not match: return None yy, mm, dd, hh, MM, ss, tz_str = match.groups() # 年份处理:26 -> 2026 year = 2000 + int(yy) month = int(mm) day = int(dd) hour = int(hh) minute = int(MM) second = int(ss) # 创建 UTC 时间的 datetime 对象 dt_utc = datetime(year, month, day, hour, minute, second) # 解析时区偏移(单位:四分之一小时) if tz_str: try: # 时区偏移值(四分之一小时) tz_quarters = int(tz_str) # 转换为小时(除以4) tz_hours = tz_quarters / 4.0 logger = logger_manager.logger if logger: logger.info(f"[TIME] 时区偏移: {tz_str} (四分之一小时) = {tz_hours} 小时") # 转换为本地时间 dt_local = dt_utc + timedelta(hours=tz_hours) except ValueError: # 如果时区解析失败,使用默认值 logger = logger_manager.logger if logger: logger.warning(f"[TIME] 时区解析失败: {tz_str},使用默认 UTC+{timezone_offset}") dt_local = dt_utc + timedelta(hours=timezone_offset) else: # 没有时区信息,使用默认值 logger = logger_manager.logger if logger: logger.info(f"[TIME] 未找到时区信息,使用默认 UTC+{timezone_offset}") dt_local = dt_utc + timedelta(hours=timezone_offset) logger = logger_manager.logger if logger: logger.info(f"[TIME] UTC时间: {dt_utc.strftime('%Y-%m-%d %H:%M:%S')}") logger.info(f"[TIME] 本地时间: {dt_local.strftime('%Y-%m-%d %H:%M:%S')}") return dt_local except Exception as e: logger = logger_manager.logger if logger: logger.error(f"[TIME] 解析时间失败: {e}, 响应: {cclk_response}") else: print(f"[TIME] 解析时间失败: {e}, 响应: {cclk_response}") return None def get_time_from_4g(timezone_offset=8): """ 通过4G模块获取当前时间(已转换为本地时间) Args: timezone_offset: 时区偏移(小时),默认8(中国时区) Returns: datetime 对象(本地时间),如果获取失败返回 None """ try: # 发送 AT+CCLK? 命令(延迟导入避免循环依赖) from hardware import hardware_manager # 检查 at_client 是否已初始化 if hardware_manager.at_client is None: logger = logger_manager.logger if logger: logger.warning("[TIME] ATClient 尚未初始化,无法获取4G时间") else: print("[TIME] ATClient 尚未初始化,无法获取4G时间") return None resp = hardware_manager.at_client.send("AT+CCLK?", "OK", 3000) if not resp or "+CCLK:" not in resp: logger = logger_manager.logger if logger: logger.warning(f"[TIME] 未获取到时间响应: {resp}") else: print(f"[TIME] 未获取到时间响应: {resp}") return None # 解析并转换时区 dt = parse_4g_time(resp, timezone_offset) return dt except Exception as e: logger = logger_manager.logger if logger: logger.error(f"[TIME] 获取4G时间异常: {e}") else: print(f"[TIME] 获取4G时间异常: {e}") return None def sync_system_time_from_4g(timezone_offset=8): """ 从4G模块同步时间到系统 Args: timezone_offset: 时区偏移(小时),默认8(中国时区) Returns: bool: 是否成功 """ dt = get_time_from_4g(timezone_offset) if not dt: return False try: # 转换为系统 date 命令需要的格式 time_str = dt.strftime('%Y-%m-%d %H:%M:%S') # 设置系统时间 cmd = f'date -s "{time_str}" 2>&1' result = os.system(cmd) if result == 0: logger = logger_manager.logger if logger: logger.info(f"[TIME] 系统时间已设置为: {time_str}") else: print(f"[TIME] 系统时间已设置为: {time_str}") # 可选:同步到硬件时钟 try: os.system('hwclock -w 2>/dev/null') logger = logger_manager.logger if logger: logger.info("[TIME] 已同步到硬件时钟") except: pass return True else: logger = logger_manager.logger if logger: logger.error(f"[TIME] 设置系统时间失败,退出码: {result}") else: print(f"[TIME] 设置系统时间失败,退出码: {result}") return False except Exception as e: logger = logger_manager.logger if logger: logger.error(f"[TIME] 同步系统时间异常: {e}") else: print(f"[TIME] 同步系统时间异常: {e}") return False