You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

树莓派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:验证并统一时区配置

若怀疑时区问题,可执行以下操作:

  1. 查看系统当前时区:timedatectl
  2. 设置正确时区(以上海时区为例):sudo timedatectl set-timezone Asia/Shanghai
  3. 若需在crontab中显式指定时区,可在crontab配置顶部添加:
    TZ=Asia/Shanghai
    

内容的提问来源于stack exchange,提问作者DvDRaga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 04:11:00