每隔一段时间重复一个声音/动作

3
我正在尝试编写一个Python程序,每隔一定时间就会播放一次声音,但它并没有真正起作用。当我测试代码并到达指定的时间时,它将永远重复播放声音。
以下是代码:
import os
from datetime import datetime

now = datetime.now()
currentHour = now.hour
currentMin = now.minute

#I also tested with if but it didn't work
while currentHour==15 and currentMin==33:
    os.system("aplay /home/pi/sound.wav") #Plays the sound thru aplay

如果你的脚本崩溃或计算机重新启动会发生什么?你应该使用操作系统提供的工具,如cron或Windows任务计划程序。 - jfs
2个回答

3
你的逻辑是错误的。
首先,while循环在大多数情况下只会在第一次迭代后结束,而你希望程序继续运行直到你告诉它停止。
此外,在循环内部你没有更新now变量,这基本上是一个坏主意。
例如,当时间达到15:33时,以下代码将继续运行,并且声音只会播放一次。
myHour = 15
myMin = 33
is_played = False
while True:
    now = datetime.now()
    currentHour = now.hour
    currentMin = now.minute
    if currentHour == myHour and currentMin == myMin and not is_played:
        is_played = True
        os.system("aplay /home/pi/sound.wav")
    if currentHour != myHour or currentMin != myMin:
        is_played = False

Xiaotian Pei 提出了一个很棒的想法,为了有效地利用您的 CPU 资源,让我们使用 Timer 模块:

def to_play_sound(hour, min):
    now = datetime.now()
    currentHour = now.hour
    currentMin = now.minute
    if currentHour == hour and currentMin == min and not is_played:
        is_played = True
        os.system("aplay /home/pi/sound.wav")
    if currentHour != myHour or currentMin != myMin:
        is_played = False
while True:
    t = Timer(30.0, to_play_sound, [15, 33])
    t.start()

J.F. Sebastian 也提出了一个很好的想法:

import datetime
import subprocess
while True:
    now = datetime.now()
    # compute `deadline`
    while True:
        deadline = now.replace(hour=hour, minute=min)
        if deadline > now:
            break
        else:
            deadline += datetime.timedelta(1)
    sleep_until(deadline) # sleep
    subprocess.check_call(['aplay', '/home/pi/sound.wav']) # play the sound!

阅读这里了解sleep_until的实现细节。


2
这将在15:33至15:34之间播放歌曲多次。 - Rodrigo López
1
你误解了 Timer() 的工作原理:to_play_sound 函数只会被调用一次,但你希望它能够永久地被调用。相反,尝试在循环中使用代码 sleep_until(deadline),其中 deadline 可以被计算为 while True: deadline = now.replace(hour=hour, minute=min) if deadline > now: break else: deadline += timedelta(1) - jfs
您可能已经注意到计算deadline的循环中没有sleep_until()。 您需要另一个循环来调用其中的sleep_until()。 我评论中的循环仅计算一个新的deadlinewhile True:(将deadline循环放在此处)#在内部循环后使用deadline:sleep_until(deadline);play_sound() 最外层循环结束。 - jfs
几乎完成 1. 在外部循环中使用now = datetime.now(),以便它可以处理超过一天的工作 2. 您可以使用subprocess.check_call(['aplay', '/home/pi/sound.wav'])来引发异常,如果文件无法播放(它还可以避免不必要地运行shell)。 - jfs
  1. 导入不正确,请在发布代码之前运行它或明确指出您尚未对其进行测试。
  2. 将“python scheduler”放入您喜欢的搜索引擎中,并阅读各种调度程序的源代码,以查看许多其他应该处理的问题。
  3. 删除所有自定义代码,改用cron、Windows任务计划程序等。
- jfs
显示剩余2条评论

1

这是对@bshuster13答案的补充。

你实际上需要一个timer。使用忙循环并检测是否到了做某事的正确时间不是一个好主意。看看python中的Timer。我认为你会想出更好的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接