在Python中用闹钟实现时钟的最有效方法

时间:2014-12-18 00:29:33

标签: python datetime timer clock alarm

我正在尝试用Python实现带闹钟的数字时钟。现在我想知道实现闹钟功能的最佳方法是什么。我能够找到几个类似的项目,主要集中在闹钟功能上。他们通常只计算下一次唤醒广告进入睡眠状态的时间,计算出的秒数。 请参阅herehere

我的问题是,我还实现了一个普通时钟并显示时间。因此我必须每秒更新时钟。在此循环中,我检查是否不应该关闭警报。出于这个原因,我正在寻找简单有效的闹钟功能实现。

受到第一个例子的启发,我最终得到了这个:

#!/usr/bin/python

import time
import datetime

class Clock:

    def __init__(self):

        # set the initial time
        self.hour = 0
        self.minute = 0
        self.second = 0
        # the update interval in seconds
        self.update_interval = 1
        self.keep_running = True
        # the instance of the alarm
        self.alarm = AlarmClock()

    def run(self):
        while self.keep_running:
            # update the clock time
            now = datetime.datetime.now()
            self.hour = now.hour
            self.minute = now.minute
            self.second = now.second

            # now check if the alarm should not be started
            if self.alarm.is_active():
                if self.alarm.time_till_next_alarm() < 1:
                    # has to be done in separate thread
                    self.alarm.on_wake_up()

            time.sleep(self.update_interval)

    def get_alarm(self):
        return self.alarm


class AlarmClock:
    def __init__(self, hour=8, minute=0):
        # We start with predefined alarm at 8:00 which is not active
        self.hour = hour
        self.minute = minute
        self.active = False
        # the alarm should be stopped after some time (1h 00min)
        self.duration = datetime.timedelta(hours=1, minutes=0)

    def time_till_next_alarm(self):
        now = datetime.datetime.now()  # get current date & time

        # separate date and time from each other:
        currdate = datetime.date(now.year, now.month, now.day)
        currtime = datetime.time(now.hour, now.minute)
        alarmtime = self.get_wake_up_time()
        # add today's date onto the alarm time entered
        alarmdatetime = datetime.datetime.combine(currdate, alarmtime)
        if alarmtime <= currtime:  # if the alarm time is less than the current time set clock for tomorrow
            alarmdatetime += datetime.timedelta(hours=24)

        return alarmdatetime - now

    def set_time(self, hour, minute):
        self.hour = hour
        self.minute = minute

    def activate(self):
        self.active = True

    def deactivate(self):
        self.active = False

    def is_active(self):
        return self.active

    def on_wake_up(self):
        # start the wake up
        print 'Wake up!'


#Execution starts here
if __name__ == '__main__':

    clock = Clock()
    clock.get_alarm().activate()
    clock.get_alarm().set_time(8,0)
    clock.run()

是否有更好或更少计算要求的实施?

编辑:

我想在7段LCD显示屏上显示时间,here are some details about the part.因此,我在 run()方法中每次更新时都会将数字写入LCD显示屏

# set the tens and ones of hours and minutes
self.display.set_digit(0, int(self.hour / 10))     # Tens
self.display.set_digit(1, self.hour % 10)          # Ones
self.display.set_digit(2, int(self.minute / 10))   # Tens
self.display.set_digit(3, self.minute % 10)        # Ones

EDIT2:

虽然Adafruit提供的python库允许你设置整个显示器的闪烁率,我想以1Hz的频率闪烁冒号 - 暗示秒的速率。

 # Toggle colon at 1Hz
 self.display.set_colon(self.second % 2)

2 个答案:

答案 0 :(得分:1)

查看sched模块。包含在Python标准库中!

文档:https://docs.python.org/2/library/sched.html

答案 1 :(得分:1)

您可以完全消除AlarmClock类,只需使用threading.Timer即可。大多数其他类似乎也是多余的 - 日期时间对象已经有小时,分钟,秒,所以不需要保留自己的版本。

import datetime
import threading
import sys

def ring_ring():
    sys.stdout.write('ring ring\n')
    sys.stdout.flush()

class Clock:

    def __init__(self):
        self.alarm_time = None
        self._alarm_thread = None
        self.update_interval = 1
        self.event = threading.Event()

    def run(self):
        while True:
            self.event.wait(self.update_interval)
            if self.event.isSet():
                break
            now = datetime.datetime.now()
            if self._alarm_thread and self._alarm_thread.is_alive():
                alarm_symbol = '+'
            else:
                alarm_symbol = ' '
            sys.stdout.write("\r%02d:%02d:%02d %s" 
                % (now.hour, now.minute, now.second, alarm_symbol))
            sys.stdout.flush()

    def set_alarm(self, hour, minute):
        now = datetime.datetime.now()
        alarm = now.replace(hour=int(hour), minute=int(minute))
        delta = int((alarm - now).total_seconds())
        if delta <= 0:
            alarm = alarm.replace(day=alarm.day + 1)
            delta = int((alarm - now).total_seconds())
        if self._alarm_thread:
            self._alarm_thread.cancel()
        self._alarm_thread = threading.Timer(delta, ring_ring)
        self._alarm_thread.daemon = True
        self._alarm_thread.start()

clock = Clock()
clock.set_alarm(sys.argv[1], sys.argv[2])
clock.run()