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

树莓派Raspbian系统下继电器定时关灯异常问题求助

树莓派Python继电器定时照明故障排查与解决

问题描述

在树莓派Raspbian系统中,使用Python脚本控制继电器实现照明模块12小时开/12小时关的定时规则:

  • 设置10:00开灯、22:00关灯时,照明能准时开启,但永远无法自动关闭;
  • 若在22:00后重启脚本,系统能识别并关闭照明,次日也能准时开灯;
  • 测试短间隔定时(如12:00开、13:00关)时,功能完全正常,无任何报错。

现有代码实现

定时时间初始化

self.timer_on = datetime.time(self.thresholds['TON'],0)
self.timer_off = datetime.time(self.thresholds['TOFF'], 0)

定时检查函数

def timer_check(self):
    now = datetime.datetime.now().time()
    if self.timer_on <= now < self.timer_off:
        GPIO.output(self.light_pin, False) #Turn the light on
    else:
        GPIO.output(self.light_pin, True) #Turn the light off

函数调用逻辑

def check_vs_thresholds(self):
    '''
    Determines when and if to turn on or off the heater, ac, and humidifier.
    Also checks if the temps are high or low enough to warrant creating an alert. 
    '''
    # 温度过低时开加热器
    if self.heat_pin:
        self.heater_check()

    # 温度过高时开空调
    if self.ac_pin:
        self.cooler_check()

    # 湿度低时开加湿器
    if self.hum_pin:
        self.humidity_check()

    # 检查照明定时
    if self.light_pin:
        self.timer_check()

主循环执行

def run(self):
    while True:
        self.update_readings_from_sensor()
        self.check_vs_thresholds()
        self.record()

故障原因分析

从现象和代码来看,核心问题大概率出在时间判断逻辑的可靠性或主循环阻塞上:

  1. datetime.time比较的潜在问题:虽然10:00 <= now <22:00的逻辑在理论上成立,但如果主循环执行间隔较长(比如超过1分钟),可能刚好错过22:00的时间节点,且后续因未知原因导致判断异常;
  2. 主循环阻塞:update_readings_from_sensor()或record()函数如果出现阻塞(比如传感器读取超时、磁盘写入卡顿),会导致timer_check()无法按时执行;
  3. 状态未更新:长时间运行后,定时时间变量可能未正确跨天更新,但此情况不符合短间隔正常的现象。

解决方案

方案1:增强时间判断逻辑(改用datetime.datetime)

改用完整的日期时间对象进行比较,同时自动更新次日的定时时间,避免time对象比较的潜在问题:

修改初始化代码

import datetime

def __init__(self, thresholds, light_pin):
    self.thresholds = thresholds
    self.light_pin = light_pin
    GPIO.setup(self.light_pin, GPIO.OUT)
    
    # 构造当天的开/关完整时间
    today = datetime.date.today()
    self.timer_on = datetime.datetime.combine(today, datetime.time(thresholds['TON'], 0))
    self.timer_off = datetime.datetime.combine(today, datetime.time(thresholds['TOFF'], 0))
    
    # 处理跨天定时(比如22:00开,10:00关)
    if self.timer_off < self.timer_on:
        self.timer_off += datetime.timedelta(days=1)

修改定时检查函数

def timer_check(self):
    now = datetime.datetime.now()
    
    # 当前时间超过关灯时间时,自动更新次日的定时时间
    if now >= self.timer_off:
        self.timer_on += datetime.timedelta(days=1)
        self.timer_off += datetime.timedelta(days=1)
    
    # 执行开关灯逻辑
    if self.timer_on <= now < self.timer_off:
        GPIO.output(self.light_pin, False)  # 开灯
    else:
        GPIO.output(self.light_pin, True)   # 关灯

方案2:使用专业定时任务库(APScheduler)

放弃自己轮询的方式,改用APScheduler库实现精确定时,避免主循环阻塞问题:

安装APScheduler

pip install apscheduler

重构照明控制代码

from apscheduler.schedulers.background import BackgroundScheduler
import RPi.GPIO as GPIO
import datetime

class LightController:
    def __init__(self, light_pin, ton, toff):
        self.light_pin = light_pin
        GPIO.setmode(GPIO.BCM)
        GPIO.setup(self.light_pin, GPIO.OUT)
        
        # 初始化后台调度器
        self.scheduler = BackgroundScheduler()
        # 添加每日定时任务:ton点开灯,toff点关灯
        self.scheduler.add_job(self.turn_light_on, 'cron', hour=ton)
        self.scheduler.add_job(self.turn_light_off, 'cron', hour=toff)
        self.scheduler.start()
        
        # 初始状态判断
        now = datetime.datetime.now().time()
        if ton <= now.hour < toff:
            self.turn_light_on()
        else:
            self.turn_light_off()
    
    def turn_light_on(self):
        GPIO.output(self.light_pin, False)
        print(f"[{datetime.datetime.now()}] 照明已开启")
    
    def turn_light_off(self):
        GPIO.output(self.light_pin, True)
        print(f"[{datetime.datetime.now()}] 照明已关闭")
    
    def stop(self):
        self.scheduler.shutdown()
        GPIO.cleanup()

在主程序中使用

if __name__ == "__main__":
    try:
        controller = LightController(light_pin=18, ton=10, toff=22)
        while True:
            # 处理其他传感器或设备逻辑
            pass
    except KeyboardInterrupt:
        controller.stop()

方案3:添加日志排查

如果暂时不想修改核心逻辑,可以先添加日志输出,定位具体故障点:

def timer_check(self):
    now = datetime.datetime.now().time()
    # 打印关键信息
    print(f"当前时间: {now} | 开灯时间: {self.timer_on} | 关灯时间: {self.timer_off}")
    condition = self.timer_on <= now < self.timer_off
    print(f"条件判断结果: {condition}")
    
    if condition:
        GPIO.output(self.light_pin, False)
        print("执行操作: 开灯")
    else:
        GPIO.output(self.light_pin, True)
        print("执行操作: 关灯")

运行脚本后,观察22:00前后的日志输出,即可明确是判断逻辑异常还是函数未执行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 16:45:57