예제 #1
0
    def __init__(self, weatherFetcher):
        threading.Thread.__init__(self)
        self.stopping = False
        self.nextAlarm = None
        self.alarmTimeout = None
        self.snoozing = False

        self.settings = Settings.Settings()
        self.media = MediaPlayer.MediaPlayer()
        self.alarmGatherer = AlarmGatherer.AlarmGatherer()
        self.weather = weatherFetcher

        self.fromEvent = False  # False if auto or manual, True if from an event

        self.travel = TravelCalculator(self.settings.get('location_home'))
        self.travelTime = 0  # The travel time we last fetched
        self.travelCalculated = False  # Have we re-calculated travel for this alarm cycle?
예제 #2
0
    def __init__(self, settings, media, weather, wink):
        threading.Thread.__init__(self)
        self.stopping = False
        self.nextAlarm = None
        self.alarmTimeout = None
        self.snoozing = False
        self.alarmMediaState = False

        self.settings = settings
        self.alarm_media = settings.get("alarm_media")
        self.media = media

        log.debug("Loading AlarmGatherer")
        self.alarmGatherer = AlarmGatherer.AlarmGatherer(settings)

        self.weatherFetcher = weather
        self.use_wink = self.settings.getInt("use_wink")
        self.wink = wink
        self.fromEvent = False  # False if auto or manual, True if from an event

        log.debug("Loading Travel Calculator")
        self.travel = TravelCalculator(self.settings.get('location_home'))
        self.travelTime = 0  # The travel time we last fetched
        self.travelCalculated = False  # Have we re-calculated travel for this alarm cycle?
예제 #3
0
   def __init__(self, weatherFetcher):
      threading.Thread.__init__(self)
      self.stopping=False
      self.nextAlarm=None
      self.alarmTimeout=None
      self.snoozing = False

      self.settings = Settings.Settings()
      self.media = MediaPlayer.MediaPlayer()
      self.alarmGatherer = AlarmGatherer.AlarmGatherer()
      self.weather = weatherFetcher

      self.fromEvent = False # False if auto or manual, True if from an event

      self.travel = TravelCalculator(self.settings.get('location_home'))
      self.travelTime = 0 # The travel time we last fetched
      self.travelCalculated = False # Have we re-calculated travel for this alarm cycle?
예제 #4
0
class AlarmThread(threading.Thread):
    def __init__(self, weatherFetcher):
        threading.Thread.__init__(self)
        self.stopping = False
        self.nextAlarm = None
        self.alarmTimeout = None
        self.snoozing = False

        self.settings = Settings.Settings()
        self.media = MediaPlayer.MediaPlayer()
        self.alarmGatherer = AlarmGatherer.AlarmGatherer()
        self.weather = weatherFetcher

        self.fromEvent = False  # False if auto or manual, True if from an event

        self.travel = TravelCalculator(self.settings.get('location_home'))
        self.travelTime = 0  # The travel time we last fetched
        self.travelCalculated = False  # Have we re-calculated travel for this alarm cycle?

    def stop(self):
        log.info("Stopping alarm thread")
        if (self.media.playerActive()):
            self.stopAlarm()
        self.stopping = True

    def isAlarmSounding(self):
        return (self.media.playerActive() and self.nextAlarm is not None
                and self.nextAlarm < datetime.datetime.now(
                    pytz.timezone('Europe/London')))

    def isSnoozing(self):
        return self.snoozing

    def getNextAlarm(self):
        return self.nextAlarm

    def snooze(self):
        log.info("Snoozing alarm for %s minutes",
                 self.settings.getInt('snooze_length'))
        self.silenceAlarm()

        alarmTime = datetime.datetime.now(pytz.timezone('Europe/London'))
        alarmTime += datetime.timedelta(
            minutes=self.settings.getInt('snooze_length'))
        self.setAlarmTime(alarmTime)
        self.snoozing = True
        self.alarmTimeout = None
        self.fromEvent = False

    def soundAlarm(self):
        log.info("Alarm triggered")
        self.media.soundAlarm()
        timeout = datetime.datetime.now(pytz.timezone('Europe/London'))
        timeout += datetime.timedelta(
            minutes=self.settings.getInt('alarm_timeout'))
        self.alarmTimeout = timeout

    # Only to be called if we're stopping this alarm cycle - see silenceAlarm() for shutting off the player
    def stopAlarm(self):
        log.info("Stopping alarm")
        self.silenceAlarm()

        self.clearAlarm()

        if self.settings.getInt('weather_on_alarm') == 1:
            log.debug("Playing weather information")

            now = datetime.datetime.now(pytz.timezone('Europe/London'))

            weather = ""
            try:
                weather = self.weather.getWeather().speech()
            except Exception:
                log.exception("Failed to get weather information")

            day = now.strftime("%d").lstrip("0")
            day += suffix(now.day)

            hour = now.strftime("%I").lstrip("0")

            salutation = "morning" if now.strftime(
                "%p") == "AM" else "afternoon" if int(hour) < 18 else "evening"

            # Today is Monday 31st of October, the time is 9 56 AM
            speech = "Good %s Matt. Today is %s %s %s, the time is %s %s %s. " % (
                salutation, now.strftime("%A"), day, now.strftime("%B"), hour,
                now.strftime("%M"), now.strftime("%p"))
            speech += weather

            self.media.playSpeech(speech)

        # Send a notification to HomeControl (OpenHAB) that we're now awake
        try:
            log.debug("Sending wake notification to HomeControl")
            urllib2.urlopen(
                "http://homecontrol:9090/CMD?isSleeping=OFF").read()
        except Exception:
            log.exception("Failed to send wake state to HomeControl")

        # Automatically set up our next alarm.
        self.autoSetAlarm()

    # Stop whatever is playing
    def silenceAlarm(self):
        log.info("Silencing alarm")
        self.media.stopPlayer()

    def autoSetAlarm(self):
        if self.settings.getInt('holiday_mode') == 1:
            log.debug(
                "Holiday mode enabled, won't auto-set alarm as requested")
            return

        log.debug("Automatically setting next alarm")
        try:
            event = self.alarmGatherer.getNextEventTime(
            )  # The time of the next event on our calendar.
            default = self.alarmGatherer.getDefaultAlarmTime()

            diff = datetime.timedelta(minutes=self.settings.getInt(
                'wakeup_time'))  # How long before event do we want alarm
            event -= diff

            # Adjust for travel time
            self.travelTime = self.fetchTravelTime()
            travelDelta = datetime.timedelta(minutes=self.travelTime)
            event -= travelDelta

            if event > default:  # Is the event time calculated greater than our default wake time
                log.debug(
                    "Calculated wake time of %s is after our default of %s, reverting to default",
                    event, default)
                event = default
                self.fromEvent = False
            else:
                self.fromEvent = True

            self.setAlarmTime(event)
            self.settings.set(
                'manual_alarm',
                '')  # We've just auto-set an alarm, so clear any manual ones

            # Read out the time we've just set
            hour = event.strftime("%I").lstrip("0")
            readTime = "%s %s %s" % (hour, event.strftime("%M"),
                                     event.strftime("%p"))
            self.media.playVoice('Automatic alarm has been set for %s' %
                                 (readTime))

        except Exception as e:
            log.exception("Could not automatically set alarm")
            self.media.playVoice('Error setting alarm')
            self.nextAlarm = None

    # Find out where our next event is, and then calculate travel time to there
    def fetchTravelTime(self, update=False):
        destination = self.alarmGatherer.getNextEventLocation(
            includeToday=update)
        if (destination is None):
            destination = self.settings.get('location_work')
        travelTime = self.travel.getTravelTime(destination)

        return travelTime

    def travelAdjustAlarm(self):
        log.info("Adjusting alarm for current travel time")
        newTravelTime = self.fetchTravelTime(update=True)
        travelDiff = newTravelTime - self.travelTime
        log.debug("Old travel time: %s, new travel time: %s, diff: %s" %
                  (self.travelTime, newTravelTime, travelDiff))

        adjustDelta = datetime.timedelta(minutes=travelDiff)
        newTime = self.nextAlarm - adjustDelta
        self.setAlarmTime(newTime)
        self.travelCalculated = True

    def manualSetAlarm(self, alarmTime):
        log.info("Manually setting next alarm to %s", alarmTime)
        self.fromEvent = False
        self.settings.set('manual_alarm',
                          calendar.timegm(alarmTime.utctimetuple()))
        self.setAlarmTime(alarmTime)
        self.media.playVoice('Manual alarm has been set')

    def setAlarmTime(self, alarmTime):
        self.nextAlarm = alarmTime
        log.info("Alarm set for %s", alarmTime)

    def clearAlarm(self):
        self.snoozing = False
        self.nextAlarm = None
        self.alarmTimeout = None
        self.settings.set(
            'manual_alarm', ''
        )  # If we've just stopped an alarm, we can't have a manual one set yet
        self.travelTime = 0
        self.travelCalculated = False
        self.fromEvent = False

    # Number of seconds until alarm is triggered
    def alarmInSeconds(self):
        now = datetime.datetime.now(pytz.timezone('Europe/London'))
        if self.nextAlarm is None:
            return -1

        if self.isSnoozing() or self.isAlarmSounding():
            return 0

        diff = self.nextAlarm - now
        return diff.seconds

    # Return a line of text describing the alarm state
    def getMenuLine(self):
        now = datetime.datetime.now(pytz.timezone('Europe/London'))
        message = ""

        if self.nextAlarm is not None:
            diff = self.nextAlarm - now
            if diff.days < 1:
                if self.snoozing:
                    message += "Snoozing"
                else:
                    message += "Alarm"

                if diff.seconds < (2 * 60 * 60):  # 2 hours
                    if self.snoozing:
                        message += " for "
                    else:
                        message += " in "
                    message += "%s min" % ((diff.seconds // 60) + 1)
                    if diff.seconds // 60 != 0:
                        message += "s"
                else:
                    if self.snoozing:
                        message += " until "
                    else:
                        message += " at "
                    message += self.nextAlarm.strftime("%H:%M")

        return message

    def run(self):
        while (not self.stopping):
            now = datetime.datetime.now(pytz.timezone('Europe/London'))

            if (self.nextAlarm is not None and self.fromEvent
                    and self.alarmInSeconds() < 3600
                    and not self.travelCalculated):
                # We're inside 1hr of an event alarm being triggered, and we've not taken into account the current traffic situation
                self.travelAdjustAlarm()

            if (self.nextAlarm is not None and self.nextAlarm < now
                    and not self.media.playerActive()):
                self.soundAlarm()

            if (self.alarmTimeout is not None and self.alarmTimeout < now):
                log.info("Alarm timeout reached, stopping alarm")
                self.stopAlarm()

            time.sleep(1)
예제 #5
0
class AlarmThread(threading.Thread):
    def __init__(self, settings, media, weather, wink):
        threading.Thread.__init__(self)
        self.stopping = False
        self.nextAlarm = None
        self.alarmTimeout = None
        self.snoozing = False
        self.alarmMediaState = False

        self.settings = settings
        self.alarm_media = settings.get("alarm_media")
        self.media = media

        log.debug("Loading AlarmGatherer")
        self.alarmGatherer = AlarmGatherer.AlarmGatherer(settings)

        self.weatherFetcher = weather
        self.use_wink = self.settings.getInt("use_wink")
        self.wink = wink
        self.fromEvent = False  # False if auto or manual, True if from an event

        log.debug("Loading Travel Calculator")
        self.travel = TravelCalculator(self.settings.get('location_home'))
        self.travelTime = 0  # The travel time we last fetched
        self.travelCalculated = False  # Have we re-calculated travel for this alarm cycle?

    def isAlarmSounding(self):
        sounding = (self.media.playerActive() and self.nextAlarm is not None)
        # log.debug("isAlarmSounding: {0}".format(sounding))
        return sounding

    def isSnoozing(self):
        # log.debug("isSnoozing: {0}".format(self.snoozing))
        return self.snoozing

    def getNextAlarm(self):
        log.debug("getNextAlarm: {0}".format(self.nextAlarm))
        return self.nextAlarm

    def snooze(self):
        message = "Snoozing alarm for {0} minutes".format(self.settings.getInt('snooze_length'))
        log.info(message)
        log.debug("snooze: {0}".format(self.settings.getInt('snooze_length')))

        self.snoozing = True

        if self.use_wink == 1:
            log.debug("turning off Wink")
            self.wink.activate(self.settings.get('wink_group_id'),bool(),0)

        alarmTime = datetime.datetime.now(pytz.timezone(self.settings.get('timezone')))
        alarmTime += datetime.timedelta(minutes=self.settings.getInt('snooze_length'))
        self.setAlarmTime(alarmTime)
        self.alarmTimeout = None
        self.fromEvent = False

        self.silenceAlarm(self.snoozing)

    # Only to be called if we're stopping this alarm cycle - see silenceAlarm() for shutting off the player
    def stopAlarm(self):
        log.debug("stopAlarm")
        self.silenceAlarm()
        self.alarmMediaState = False

        if self.use_wink == 1:
            log.debug("turning on Wink")
            self.wink.activate(self.settings.get('wink_group_id'),bool(1),0.25)

        self.clearAlarm()

        if self.settings.getInt('weather_on_alarm') == 1:
            log.debug("Playing weather information")

            now = datetime.datetime.now(pytz.timezone(self.settings.get('timezone')))

            weather = ""
            try:
                weather = self.weatherFetcher.getWeather().speech()
            except Exception:
                log.exception("Failed to get weather information")

            day = now.strftime("%d").lstrip("0")
            day += suffix(now.day)

            hour = now.strftime("%I").lstrip("0")

            salutation = "morning" if now.strftime("%p") == "AM" else "afternoon" if int(hour) < 18 else "evening"

            # Today is Monday 31st of October, the time is 9 56 AM
            speech = "Good {0} {1}. Today is {2} {3} {4}, the time is {5} {6} {7}. ".format(
            salutation, self.settings.get("name"), now.strftime("%A"), day, now.strftime("%B"), hour, now.strftime("%M"), now.strftime("%p"))
            speech += weather

            # blocking stopped working somewhere before revision 300
            self.media.playVoice(speech)

        # Send a notification to HomeControl (OpenHAB) that we're now awake
        if self.settings.getInt('use_openhab') == 1:
            try:
                log.debug("Sending wake notification to HomeControl")
                urllib2.urlopen("http://homecontrol:9090/CMD?isSleeping=OFF").read()
            except Exception:
                log.exception("Failed to send wake state to HomeControl")


        # Automatically set up our next alarm.
        self.autoSetAlarm()

    def soundAlarm(self):
        log.debug("soundAlarm")
        if self.use_wink == 1:
            log.debug("turning on Wink")
            self.wink.activate(self.settings.get('wink_group_id'),bool(1),0.25)
        self.media.soundAlarm(self.snoozing)
        self.alarmMediaState = True
        timeout = datetime.datetime.now(pytz.timezone(self.settings.get('timezone')))
        timeout += datetime.timedelta(minutes=self.settings.getInt('alarm_timeout'))
        self.alarmTimeout = timeout

    # Stop whatever is playing
    def silenceAlarm(self, snoozing=False):
        log.debug("silenceAlarm")
        if self.alarm_media == 'Spotify':
            if snoozing:
                self.media.spotify.pause()
            else:
                self.media.spotify.stop()
        else:
            self.media.stopPlayer()

    # Called by InputWorker on press of the cancel button
    def cancel(self):
        log.debug("cancel: Cancel button pressed")
        if self.isAlarmSounding():
            # Lets snooze for a while
            self.snooze()
            return

        if self.isSnoozing():
            # Stop the alarm!
            self.stopAlarm()
            return

        if self.alarmInSeconds() < self.settings.getInt('preempt_cancel'):
            # We're in the allowable window for pre-empting a cancel alarm, and we're not in the menu
            log.info("Preempt cancel triggered")
            self.stopAlarm()
            return

    def autoSetAlarm(self):
        log.debug("autoSetAlarm")
        if self.settings.getInt('holiday_mode') == 1:
            log.debug("Holiday mode enabled, won't auto-set alarm as requested")
            return

        log.debug("Automatically setting next alarm")
        log.debug("entering very large try: clause")
        try:

            event = self.alarmGatherer.getNextEventTime()  # The time of the next event on our calendar.
            default = self.alarmGatherer.getDefaultAlarmTime()

            diff = datetime.timedelta(
                minutes=self.settings.getInt('wakeup_time'))  # How long before event do we want alarm
            event -= diff

            # Adjust for travel time
            self.travelTime = self.fetchTravelTime()
            travelDelta = datetime.timedelta(minutes=self.travelTime)
            event -= travelDelta

            if event > default:  # Is the event time calculated greater than our default wake time
                log.debug("Calculated wake time of %s is after our default of %s, reverting to default", event, default)
                event = default
                self.fromEvent = False
            else:
                self.fromEvent = True

            self.setAlarmTime(event)
            self.settings.set('manual_alarm', '')  # We've just auto-set an alarm, so clear any manual ones

            # Read out the time we've just set
            hour = event.strftime("%I").lstrip("0")
            readTime = "%s %s %s" % (hour, event.strftime("%M"), event.strftime("%p"))
            self.media.playVoice('Automatic alarm has been set for %s' % (readTime))

        except Exception as e:
            log.exception("Could not automatically set alarm")
            self.media.playVoice('Error setting alarm')
            self.nextAlarm = None

    # Find out where our next event is, and then calculate travel time to there
    def fetchTravelTime(self, update=False):
        log.debug("fetchTravelTime: {0}".format(update))
        destination = self.alarmGatherer.getNextEventLocation(includeToday=update)
        if (destination is None):
            destination = self.settings.get('location_work')
        travelTime = self.travel.getTravelTime(destination)

        return travelTime

    def travelAdjustAlarm(self):
        log.info("travelAdjustAlarm: Adjusting alarm for current travel time")
        newTravelTime = self.fetchTravelTime(update=True)
        travelDiff = newTravelTime - self.travelTime
        log.debug("Old travel time: %s, new travel time: %s, diff: %s" % (self.travelTime, newTravelTime, travelDiff))

        adjustDelta = datetime.timedelta(minutes=travelDiff)
        newTime = self.nextAlarm - adjustDelta
        self.setAlarmTime(newTime)
        self.travelCalculated = True

    def manualSetAlarm(self, alarmTime):
        log.info("manualSetAlarm: Manually setting next alarm to %s", alarmTime)
        self.fromEvent = False
        self.settings.set('manual_alarm', calendar.timegm(alarmTime.utctimetuple()))
        self.setAlarmTime(alarmTime)
        self.media.playVoice('Manual alarm has been set')

    def setAlarmTime(self, alarmTime):
        log.debug("setAlarmTime: {0}".format(alarmTime))
        self.nextAlarm = alarmTime

    def clearAlarm(self):
        log.debug("clearAlarm")
        self.snoozing = False
        self.nextAlarm = None
        self.alarmTimeout = None
        self.settings.set('manual_alarm', '')  # If we've just stopped an alarm, we can't have a manual one set yet
        self.travelTime = 0
        self.travelCalculated = False
        self.fromEvent = False

    # Number of seconds until alarm is triggered
    def alarmInSeconds(self):
        now = datetime.datetime.now(pytz.timezone(self.settings.get('timezone')))
        if self.nextAlarm is None:
            return -1

        if self.isSnoozing() or self.isAlarmSounding():
            return 0

        diff = self.nextAlarm - now
        # log.debug("alarmInSeconds: {0}".format(diff.seconds))
        return diff.seconds

    # Return a line of text describing the alarm state
    def getMenuLine(self):
        now = datetime.datetime.now(pytz.timezone(self.settings.get('timezone')))
        message = ""

        if self.nextAlarm is not None:
            diff = self.nextAlarm - now
            if diff.days < 1:
                if self.snoozing:
                    message += "Snoozing"
                else:
                    message += "Alarm"

                if diff.seconds < (2 * 60 * 60):  # 2 hours
                    if self.snoozing:
                        message += " for "
                    else:
                        message += " in "
                    message += "%s min" % ((diff.seconds // 60) + 1)
                    if diff.seconds // 60 != 0:
                        message += "s"
                else:
                    if self.snoozing:
                        message += " until "
                    else:
                        message += " at "
                    message += self.nextAlarm.strftime("%H:%M")

        log.debug("getMenuLine: {0}".format(message))
        return message

    def run(self):
        log.debug("starting alarm thread loop")
        while (not self.stopping):
            now = datetime.datetime.now(pytz.timezone(self.settings.get('timezone')))

            # log.info("now: %s", now)
            #log.info("nextAlarm: %s", self.nextAlarm)

            if (self.nextAlarm is not None and self.fromEvent and self.alarmInSeconds() < 3600 and not self.travelCalculated):
                # We're inside 1hr of an event alarm being triggered, and we've not taken into account the current traffic situation
                self.travelAdjustAlarm()

            if (self.nextAlarm is not None and self.nextAlarm < now and not self.alarmMediaState):
                self.soundAlarm()

            if (self.alarmTimeout is not None and self.alarmTimeout < now):
                log.info("Alarm timeout reached, stopping alarm")
                self.stopAlarm()

            time.sleep(1)
        log.debug("ending alarm thread loop")

    def stop(self):
        log.info("Stopping alarm thread")
        if (self.media.playerActive()):
            self.stopAlarm()
        if self.alarm_media == 'Spotify':
            self.media.spotify.stop()
        self.stopping = True
예제 #6
0
class AlarmThread(threading.Thread):

   def __init__(self, weatherFetcher):
      threading.Thread.__init__(self)
      self.stopping=False
      self.nextAlarm=None
      self.alarmTimeout=None
      self.snoozing = False

      self.settings = Settings.Settings()
      self.media = MediaPlayer.MediaPlayer()
      self.alarmGatherer = AlarmGatherer.AlarmGatherer()
      self.weather = weatherFetcher

      self.fromEvent = False # False if auto or manual, True if from an event

      self.travel = TravelCalculator(self.settings.get('location_home'))
      self.travelTime = 0 # The travel time we last fetched
      self.travelCalculated = False # Have we re-calculated travel for this alarm cycle?

   def stop(self):
      log.info("Stopping alarm thread")
      if(self.media.playerActive()):
         self.stopAlarm()
      self.stopping=True

   def isAlarmSounding(self):
      return (self.media.playerActive() and self.nextAlarm is not None and self.nextAlarm < datetime.datetime.now(pytz.timezone('America/Los_Angeles')))

   def isSnoozing(self):
      return self.snoozing

   def getNextAlarm(self):
      return self.nextAlarm

   def snooze(self):
      log.info("Snoozing alarm for %s minutes", self.settings.getInt('snooze_length'))
      self.silenceAlarm()

      alarmTime = datetime.datetime.now(pytz.timezone('America/Los_Angeles'))
      alarmTime += datetime.timedelta(minutes=self.settings.getInt('snooze_length'))
      self.setAlarmTime(alarmTime)
      self.snoozing = True
      self.alarmTimeout = None
      self.fromEvent = False

   def soundAlarm(self):
      log.info("Alarm triggered")
      self.media.soundAlarm(self)
      timeout = datetime.datetime.now(pytz.timezone('America/Los_Angeles'))
      timeout += datetime.timedelta(minutes=self.settings.getInt('alarm_timeout'))
      self.alarmTimeout = timeout

   # Only to be called if we're stopping this alarm cycle - see silenceAlarm() for shutting off the player
   def stopAlarm(self):
      log.info("Stopping alarm")
      self.silenceAlarm()

      self.clearAlarm()

      if self.settings.getInt('weather_on_alarm')==1:
         log.debug("Playing weather information")

         now = datetime.datetime.now(pytz.timezone('America/Los_Angeles'))

         weather = ""
         try:
            weather = self.weather.getWeather().speech()
         except Exception:
            log.exception("Failed to get weather information")

         day = now.strftime("%d").lstrip("0")
         day += suffix(now.day)

         hour = now.strftime("%I").lstrip("0")

         salutation = "morning" if now.strftime("%p")=="AM" else "afternoon" if int(hour) < 18 else "evening"

         # Today is Monday 31st of October, the time is 9 56 AM
         speech = "Good %s Kate. Today is %s %s %s, the time is %s %s %s. " % (salutation, now.strftime("%A"), day, now.strftime("%B"), hour, now.strftime("%M"), now.strftime("%p"))
         speech += weather

         self.media.playSpeech(speech)

      # Send a notification to HomeControl (OpenHAB) that we're now awake
#      try:
#         log.debug("Sending wake notification to HomeControl")
#         urllib2.urlopen("http://homecontrol:9090/CMD?isSleeping=OFF").read()
#      except Exception:
#         log.exception("Failed to send wake state to HomeControl")
      

      # Automatically set up our next alarm.
      self.autoSetAlarm()

   # Stop whatever is playing
   def silenceAlarm(self):
      log.info("Silencing alarm")
      self.media.stopPlayer()

   def autoSetAlarm(self):
      if self.settings.getInt('holiday_mode')==1:
         log.debug("Holiday mode enabled, won't auto-set alarm as requested")
         return

      log.debug("Automatically setting next alarm")
      try:
         event = self.alarmGatherer.getNextEventTime() # The time of the next event on our calendar.
         default = self.alarmGatherer.getDefaultAlarmTime()

         diff = datetime.timedelta(minutes=self.settings.getInt('wakeup_time')) # How long before event do we want alarm
         event -= diff

         # Adjust for travel time
         self.travelTime = self.fetchTravelTime()
         travelDelta = datetime.timedelta(minutes=self.travelTime)
         event -= travelDelta
         
         if event > default: # Is the event time calculated greater than our default wake time
            log.debug("Calculated wake time of %s is after our default of %s, reverting to default",event,default)
            event = default
            self.fromEvent = False
         else:
            self.fromEvent = True

         self.setAlarmTime(event)
         self.settings.set('manual_alarm','') # We've just auto-set an alarm, so clear any manual ones

         # Read out the time we've just set
         hour = event.strftime("%I").lstrip("0")
         readTime = "%s %s %s" % (hour, event.strftime("%M"), event.strftime("%p"))
         self.media.playVoice('Automatic alarm has been set for %s' % (readTime))

      except Exception as e:
         log.exception("Could not automatically set alarm")
         self.media.playVoice('Error setting alarm')
         self.nextAlarm = None

   # Find out where our next event is, and then calculate travel time to there
   def fetchTravelTime(self, update=False):
      destination = self.alarmGatherer.getNextEventLocation(includeToday=update)
      if(destination is None):
         destination = self.settings.get('location_work')
      travelTime = self.travel.getTravelTime(destination)

      return travelTime

   def travelAdjustAlarm(self):
      log.info("Adjusting alarm for current travel time")
      newTravelTime = self.fetchTravelTime(update=True)
      travelDiff = newTravelTime - self.travelTime
      log.debug("Old travel time: %s, new travel time: %s, diff: %s" % (self.travelTime, newTravelTime, travelDiff))
      
      adjustDelta = datetime.timedelta(minutes=travelDiff)
      newTime = self.nextAlarm - adjustDelta
      self.setAlarmTime(newTime)
      self.travelCalculated = True

   def manualSetAlarm(self,alarmTime):
      log.info("Manually setting next alarm to %s",alarmTime)
      self.fromEvent = False
      self.settings.set('manual_alarm',calendar.timegm(alarmTime.utctimetuple()))
      self.setAlarmTime(alarmTime)
      self.media.playVoice('Manual alarm has been set')

   def setAlarmTime(self,alarmTime):
      self.nextAlarm = alarmTime
      log.info("Alarm set for %s", alarmTime)

   def clearAlarm(self):
      self.snoozing = False
      self.nextAlarm = None
      self.alarmTimeout = None
      self.settings.set('manual_alarm','') # If we've just stopped an alarm, we can't have a manual one set yet
      self.travelTime = 0
      self.travelCalculated = False
      self.fromEvent = False

   # Number of seconds until alarm is triggered
   def alarmInSeconds(self):
      now = datetime.datetime.now(pytz.timezone('America/Los_Angeles'))
      if self.nextAlarm is None:
         return -1

      if self.isSnoozing() or self.isAlarmSounding():
         return 0

      diff = self.nextAlarm - now
      return diff.seconds

   # Return a line of text describing the alarm state
   def getMenuLine(self):
      now = datetime.datetime.now(pytz.timezone('America/Los_Angeles'))
      message = ""

      if self.nextAlarm is not None:
         diff = self.nextAlarm - now
         if diff.days < 1:
            if self.snoozing:
               message+="Snoozing"
            else:
               message+="Alarm"
            
            if diff.seconds < (2 * 60 * 60): # 2 hours
               if self.snoozing:
                  message+=" for "
               else:
                  message+=" in "
               message+="%s min" % ((diff.seconds//60)+1)
               if diff.seconds//60 != 0:
                  message+="s"
            else:
               if self.snoozing:
                  message+=" until "
               else:
                  message+=" at "
               message+=self.nextAlarm.strftime("%H:%M")   

      return message

   def run(self):
      while(not self.stopping):
          now = datetime.datetime.now(pytz.timezone('America/Los_Angeles'))

          if(self.nextAlarm is not None and self.fromEvent and self.alarmInSeconds() < 3600 and not self.travelCalculated):
             # We're inside 1hr of an event alarm being triggered, and we've not taken into account the current traffic situation
             self.travelAdjustAlarm()

          if(self.nextAlarm is not None):
             self.nextAlarm = self.nextAlarm.replace(tzinfo=timezone('America/Los_Angeles'))

          if(self.nextAlarm is not None and self.nextAlarm < now and not self.media.playerActive()):
             self.soundAlarm()

          if(self.alarmTimeout is not None and self.alarmTimeout < now):
             log.info("Alarm timeout reached, stopping alarm")
             self.stopAlarm()

          time.sleep(1)