树莓派PWM风扇控制脚本Crontab执行时间戳滞后问题求助
Crontab运行PWM风扇控制脚本时日志时间戳滞后5分钟的问题分析
我修改了一款树莓派PWM风扇控制的Python脚本,新增了每5分钟向fan.log写入日志的逻辑。手动运行脚本时时间戳显示正常,但通过crontab运行时,日志中的时间戳始终比实际时间晚5分钟,脚本其他功能正常。以下是脚本代码:
#!/usr/bin/python3 import RPi.GPIO as IO # 引入GPIO库以使用GPIO引脚 import time # 引入time库以实现延时功能 import subprocess # 引入subprocess库以获取CPU温度 boardPort = 18 # GPIO引脚 fanFreq = 2000 # 频率 IO.setwarnings(False) # 禁用GPIO警告信息 IO.setmode(IO.BCM) # 使用BCM引脚编号规则 - PIN8对应GPIO14 IO.setup(boardPort,IO.OUT) # 将GPIO18初始化为风扇输出引脚 fan = IO.PWM(boardPort,fanFreq) # 将GPIO18设置为PWM输出,频率为2000Hz fan.start(0) # 生成占空比为0%的PWM信号(风扇关闭) minTemp = 40 # 温度与转速范围参数 maxTemp = 70 minSpeed = 0 maxSpeed = 100 count = -1 def get_temp(): # 获取CPU温度的函数 output = subprocess.run(['vcgencmd', 'measure_temp'], capture_output=True) temp_str = output.stdout.decode() try: return float(temp_str.split('=')[1].split('\'')[0]) except (IndexError, ValueError): raise RuntimeError('Could not get temperature') def renormalize(n, range1, range2): # 将读取的温度值映射到风扇转速范围的函数 delta1 = range1[1] - range1[0] delta2 = range2[1] - range2[0] return (delta2 * (n - range1[0]) / delta1) + range2[0] while 1: # 无限循环执行 cels = get_temp() temp = cels # 获取当前CPU温度 if temp < minTemp: # 将温度值限制在设定的范围内 temp = minTemp elif temp > maxTemp: temp = maxTemp temp = int(renormalize(temp, [minTemp, maxTemp], [minSpeed, maxSpeed])) fan.ChangeDutyCycle(temp) # 根据温度设置风扇占空比,范围从minSpeed到maxSpeed count += 1 if count % 10 == 0: timeStr = time.strftime("%d/%m/%Y, %H:%M:%S") f = open("/home/pi/FanControl/fan.log", "w") f.write(timeStr + " - 当前温度为" + str(cels) + "°C,风扇转速为" + str(temp) + "%。\n") f.close if count == 1000: count = 0 time.sleep(30) # 延时30秒
问题原因分析
1. 文件未正确关闭导致缓存延迟写入
脚本中f.close语句缺少括号,并未实际调用文件关闭方法。这会导致写入的日志内容停留在Python的内存缓冲区中,无法立即同步到磁盘:
- 手动运行脚本时,当你终止脚本,Python会自动清理所有打开的文件对象,强制将缓冲区内容写入磁盘,因此时间戳显示正常。
- crontab后台运行的脚本持续运行,缓冲区需积累到系统阈值(或等待特定触发条件)才会写入磁盘,因此你看到的日志时间戳会滞后实际生成时间约5分钟(与你的循环周期匹配)。
2. 时区配置差异(次要可能性)
crontab的运行环境不会加载用户shell的个性化配置(如~/.bashrc中的时区设置),若系统默认时区与你手动登录时使用的时区不一致,可能导致时间戳偏差。但你描述的是固定滞后5分钟,这种情况更倾向于缓存问题(时区差异通常为小时级偏差)。
修复方案
方案1:修复文件关闭代码
将f.close改为f.close(),确保每次写入日志后立即关闭文件,强制缓冲区内容写入磁盘:
if count % 10 == 0: timeStr = time.strftime("%d/%m/%Y, %H:%M:%S") f = open("/home/pi/FanControl/fan.log", "w") f.write(timeStr + " - 当前温度为" + str(cels) + "°C,风扇转速为" + str(temp) + "%。\n") f.close() # 添加括号调用关闭方法 if count == 1000: count = 0
方案2:使用with语句(推荐)
使用Python的with上下文管理器自动管理文件生命周期,无需手动调用close(),避免类似错误:
if count % 10 == 0: timeStr = time.strftime("%d/%m/%Y, %H:%M:%S") # 使用with语句自动关闭文件 with open("/home/pi/FanControl/fan.log", "w") as f: f.write(f"{timeStr} - 当前温度为{cels}°C,风扇转速为{temp}%。\n") if count == 1000: count = 0
方案3:验证并统一时区配置
若怀疑时区问题,可执行以下操作:
- 查看系统当前时区:
timedatectl - 设置正确时区(以上海时区为例):
sudo timedatectl set-timezone Asia/Shanghai - 若需在crontab中显式指定时区,可在crontab配置顶部添加:
TZ=Asia/Shanghai
内容的提问来源于stack exchange,提问作者DvDRaga
相关产品推荐
相关产品推荐

