187 lines
6.3 KiB
Python
187 lines
6.3 KiB
Python
#!/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
|
||
|