Пример #1
0
    def _create_recurring_alarm(self, when, recur):
        # 'recur' is a set of day index strings, e.g. {"3", "4"}
        # convert rule into an iCal rrule
        # TODO: Support more complex alarms, e.g. first monday, monthly, etc
        rule = ""
        abbr = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"]
        days = []
        for day in recur:
            days.append(abbr[int(day)])
        if days:
            rule = "FREQ=WEEKLY;INTERVAL=1;BYDAY=" + ",".join(days)

        if when and rule:
            when = to_utc(when)

            # Create a repeating rule that starts in the past, enough days
            # back that it encompasses any repeat.
            past = when + timedelta(days=-45)
            rr = rrulestr("RRULE:" + rule, dtstart=past)
            now = to_utc(now_utc())
            # Get the first repeat that happens after right now
            next = rr.after(now)
            return {
                "timestamp": to_utc(next).timestamp(),
                "repeat_rule": rule,
            }
        else:
            return {
                "timestamp": None,
                "repeat_rule": rule,
            }
    def get_local_datetime(self, location, dtUTC=None):
        print("get_local_datetime")
        #print("6")
        if not dtUTC:
            #print("6.1")
            print("dtUTC not set")
            dtUTC = now_utc()
        if self.display_tz:
            #print("6.2")
            print("display timezone available")
            # montre les dates demandées par l'utilisateur dans certaines timeezone
            tz = self.display_tz
        else:
            #print("6.3")
            print("display timezone not available")
            tz = self.get_timezone(self.location_timezone)

        if location:
            print("location available")
            tz = self.get_timezone(location)
        if not tz:
            self.speak_dialog("timezone.pas.trouve", {"location": location})
            return None
        #print("6.4")
        print("return from get_local_datetime")
        return dtUTC.astimezone(tz)
Пример #3
0
    def _curate_alarms(self, curation_limit=1):
        """[summary]
            curation_limit (int, optional): Seconds past expired at which to
                                            remove the alarm
        """
        alarms = []
        now_ts = to_utc(now_utc()).timestamp()

        for alarm in self.settings["alarm"]:
            # Alarm format == [timestamp, repeat_rule[, orig_alarm_timestamp]]
            if alarm["timestamp"] < now_ts:
                if alarm["timestamp"] < (now_ts - curation_limit):
                    # skip playing an old alarm
                    if alarm["repeat_rule"]:
                        # reschedule in future if repeat rule exists
                        alarms.append(self._next_repeat(alarm))
                else:
                    # schedule for right now, with the
                    # third entry as the original base time
                    base = alarm["name"] if alarm["name"] == ''\
                                         else alarm["timestamp"]
                    alarms.append({
                        "timestamp": now_ts+1,
                        "repeat_rule": alarm["repeat_rule"],
                        "name": alarm["name"],
                        "snooze": base
                    })
            else:
                alarms.append(alarm)

        alarms = sorted(alarms, key=lambda a: a["timestamp"])
        self.settings["alarm"] = alarms
Пример #4
0
    def dump_alarms(self, tag=""):
        # Useful when debugging
        dump = "\n" + "="*30 + " ALARMS " + tag + " " + "="*30 + "\n"
        dump += "raw = " + str(self.settings["alarm"]) + "\n\n"

        now_ts = to_utc(now_utc()).timestamp()
        dt = datetime.fromtimestamp(now_ts)
        dump += "now = {} ({})\n".format(
            nice_time(self.get_alarm_local(timestamp=now_ts),
                      speech=False, use_ampm=not self.use_24hour, use_24hour = self.use_24hour),
            now_ts)
        dump += "      U{} L{}\n".format(to_utc(dt), to_local(dt))
        dump += "\n\n"

        idx = 0
        for alarm in self.settings["alarm"]:
            dt = self.get_alarm_local(alarm)
            dump += "alarm[{}] - {} \n".format(idx, alarm)
            dump += "           Next: {} {}\n".format(
                nice_time(dt, speech=False, use_ampm= not self.use_24hour, use_24hour = self.use_24hour),
                nice_date(dt, now=now_local()))
            dump += "                 U{} L{}\n".format(dt, to_local(dt))
            if 'snooze' in alarm:
                dtOrig = self.get_alarm_local(timestamp=alarm['snooze'])
                dump += "           Orig: {} {}\n".format(
                    nice_time(dtOrig, speech=False, use_ampm= not self.use_24hour, use_24hour = self.use_24hour),
                    nice_date(dtOrig, now=now_local()))
            idx += 1

        dump += "="*75

        self.log.info(dump)
Пример #5
0
    def test_now_utc(self, mock_dt, mock_conf):
        dt_test = datetime(year=1985, month=10, day=25, hour=8, minute=18)
        mock_dt.utcnow.return_value = dt_test
        mock_conf.get.return_value = test_config

        self.assertEqual(now_utc(), dt_test.replace(tzinfo=gettz('UTC')))
        mock_dt.utcnow.assert_called_with()
Пример #6
0
    def has_expired_alarm(self):
        # True is an alarm should be 'going off' now.  Snoozed alarms don't
        # count until they are triggered again.
        if not self.settings["alarm"]:
            return False

        now_ts = to_utc(now_utc()).timestamp()
        for alarm in self.settings["alarm"]:
            if alarm['timestamp'] <= now_ts:
                return True

        return False
Пример #7
0
    def waqi_query_and_report(self, city, pollutant):
        if self.settings.get('APIKey') is not None:
            reqAQI = requests.get('https://api.waqi.info/feed/' + city +
                                  '/?token=' + self.settings.get('APIKey'))
            objAQI = json.loads(reqAQI.text)
            if objAQI['status'] == 'ok':
                try:
                    value = objAQI['data']['iaqi'][lookup[pollutant]]['v']
                except:
                    self.speak_dialog('pollutant.not.reported', {
                        'pollutant': nice_name[pollutant],
                        'city': city
                    })
                else:
                    config = Configuration.get()
                    station_string = objAQI["data"]["city"]["name"]
                    station = station_string.split(',')[0].split('(')[0]
                    utc_time = now_utc(
                    )  # alternatively, set utc_time to datetime.now(timezone.utc)
                    rec_time = datetime.strptime(
                        objAQI["data"]["time"]["s"] +
                        objAQI["data"]["time"]["tz"].split(':')[0] +
                        objAQI["data"]["time"]["tz"].split(':')[1],
                        "%Y-%m-%d %H:%M:%S%z")
                    rec_time = to_utc(rec_time)
                    timediff = (utc_time - rec_time).total_seconds()
                    if timediff // 3600 >= 3:  # reading is more than 3 hours old
                        self.dialog(
                            'Current readings for this location are not available. Please check back another time.'
                        )
                    else:
                        if city in station:
                            incity = ''
                        else:
                            incity = 'in ' + city
                        self.speak_dialog(
                            'pollutant.level.is', {
                                'pollutant': nice_name[pollutant],
                                'incity': incity,
                                'value': value,
                                'station': station
                            })
                    if nice_name[pollutant] == 'pm 2.5':
                        self.health_advisory(value)

            elif objAQI['data'] == 'Unknown station':
                self.speak_dialog('city.not.reported', {'city': city})
            elif objAQI['data'] == 'Invalid key':
                self.speak_dialog('invalid.key', {'city': city})
        else:
            self.speak_dialog('key.not.found')
Пример #8
0
    def on_user_activity(self, message):
        # When the unit speaks, consider the user active.  Queue up a
        # notice of available update in 30 seconds.
        self.cancel_scheduled_event('QueueNotice')
        pause = now_utc() + timedelta(seconds=30)
        self.schedule_event(self._queue_notice, pause, name='QueueNotice')

        # Queued to notify now, don't bug again until at least the next day
        self.remove_event('recognizer_loop:audio_output_end')
        self.cancel_scheduled_event('DailyVersionCheck')
        self.schedule_repeating_event(
            self.daily_version_check,
            None,  # wait to run
            60 * 60 * 24,  # seconds in a day
            name='DailyVersionCheck')
Пример #9
0
    def get_local_datetime(self, location, dtUTC=None):
        if not dtUTC:
            dtUTC = now_utc()
        if self.display_tz:
            # User requested times be shown in some timezone
            tz = self.display_tz
        else:
            tz = self.get_timezone(self.location_timezone)

        if location:
            tz = self.get_timezone(location)
        if not tz:
            self.speak_dialog("time.tz.not.found", {"location": location})
            return None

        return dtUTC.astimezone(tz)
Пример #10
0
    def initialize(self):
        # Update allowed version to current version if lower or incorrect
        current_allowed = self.config_core.get("max_allowed_core_version", 0)
        core_version_float = CORE_VERSION_MAJOR + CORE_VERSION_MINOR / 10
        if (not isinstance(current_allowed, float)
                or current_allowed < core_version_float):
            self.save_upgrade_permission(
                [CORE_VERSION_MAJOR, CORE_VERSION_MINOR])

        # Start repeating event once aday to inform of new major version
        daily = 60 * 60 * 24  # seconds in a day
        self.schedule_repeating_event(
            self.daily_version_check,
            now_utc(),  # run asap
            60 * 60 * 24,  # repeat daily
            daily,
            name='DailyVersionCheck')
Пример #11
0
    def _next_repeat(self, alarm):
        # evaluate recurrence to the next instance
        if 'snooze' in alarm:
            # repeat from original time (it was snoozed)
            ref = datetime.fromtimestamp(alarm["repeat_rule"])
        else:
            ref = datetime.fromtimestamp(alarm["timestamp"])

        # Create a repeat rule and get the next alarm occurrance after that
        start = to_utc(ref)
        rr = rrulestr("RRULE:" + alarm["repeat_rule"], dtstart=start)
        now = to_utc(now_utc())
        next = rr.after(now)

        self.log.debug("     Now={}".format(now))
        self.log.debug("Original={}".format(start))
        self.log.debug("    Next={}".format(next))

        return {
            "timestamp": to_utc(next).timestamp(),
            "repeat_rule": alarm["repeat_rule"],
            "name": alarm["name"],
        }
Пример #12
0
    def handle_query_date(self, message, response_type="simple"):
        utt = message.data.get('utterance', "").lower()
        try:
            extract = extract_datetime(utt)
        except Exception:
            self.speak_dialog('date.not.found')
            return
        day = extract[0] if extract else now_local()

        # check if a Holiday was requested, e.g. "What day is Christmas?"
        year = extract_number(utt)
        if not year or year < 1500 or year > 3000:  # filter out non-years
            year = day.year
        all_holidays = {}
        # TODO: How to pick a location for holidays?
        for st in holidays.US.STATES:
            holiday_dict = holidays.US(years=[year], state=st)
            for d, name in holiday_dict.items():
                if name not in all_holidays:
                    all_holidays[name] = d
        for name in all_holidays:
            d = all_holidays[name]
            # Uncomment to display all holidays in the database
            # self.log.info("Day, name: " +str(d) + " " + str(name))
            if name.replace(" Day", "").lower() in utt:
                day = d
                break

        location = self._extract_location(utt)
        today = to_local(now_utc())
        if location:
            # TODO: Timezone math!
            if (day.year == today.year and day.month == today.month
                    and day.day == today.day):
                day = now_utc()  # for questions ~ "what is the day in sydney"
            day = self.get_local_datetime(location, dtUTC=day)
        if not day:
            return  # failed in timezone lookup

        speak_date = nice_date(day, lang=self.lang)
        # speak it
        if response_type == "simple":
            self.speak_dialog("date", {"date": speak_date})
        elif response_type == "relative":
            # remove time data to get clean dates
            day_date = day.replace(hour=0, minute=0, second=0, microsecond=0)
            today_date = today.replace(hour=0,
                                       minute=0,
                                       second=0,
                                       microsecond=0)
            num_days = (day_date - today_date).days
            if num_days >= 0:
                speak_num_days = nice_duration(num_days * 86400)
                self.speak_dialog("date.relative.future", {
                    "date": speak_date,
                    "num_days": speak_num_days
                })
            else:
                # if in the past, make positive before getting duration
                speak_num_days = nice_duration(num_days * -86400)
                self.speak_dialog("date.relative.past", {
                    "date": speak_date,
                    "num_days": speak_num_days
                })

        # and briefly show the date
        self.answering_query = True
        self.show_date(location, day=day)
        time.sleep(10)
        mycroft.audio.wait_while_speaking()
        if self.platform == "mycroft_mark_1":
            self.enclosure.mouth_reset()
            self.enclosure.activate_mouth_events()
        self.answering_query = False
        self.displayed_time = None
Пример #13
0
    def handle_set_alarm(self, message):
        """Handler for "set an alarm for..."""
        utt = message.data.get('utterance').lower()
        recur = None

        if message.data.get('Recurring'):
            # Just ignoring the 'Recurrence' now, we support more complex stuff
            # recurrence = message.data.get('Recurrence')
            recur = self._create_day_set(utt)
            # TODO: remove days following an "except" in the utt

            while not recur:
                r = self.get_response('query.recurrence', num_retries=1)
                if not r:
                    return
                recur = self._create_day_set(r)

            if self.voc_match(utt, "Except"):
                # TODO: Support exceptions
                self.speak_dialog("no.exceptions.yet")
                return

        # Get the time
        when, utt_no_datetime = extract_datetime(utt, lang=self.lang) or (None, utt)

        # Get name from leftover string from extract_datetime
        name = self._get_alarm_name(utt_no_datetime)

        # Will return dt of unmatched string
        today = extract_datetime(self.texts.get('today'), lang=self.lang)
        today = today[0]

        # Check the time if it's midnight. This is to check if the user
        # said a recurring alarm with only the Day or if the user did
        # specify to set an alarm on midnight. If it's confirmed that
        # it's for a day only, then get another response from the user
        # to clarify what time on that day the recurring alarm is.
        is_midnight = self._check_if_utt_has_midnight(utt,
                                                      when,
                                                      self.threshold)

        if (when is None or when.time() == today.time()) and not is_midnight:
            r = self.get_response('query.for.when', validator=extract_datetime)
            if not r:
                self.speak_dialog("alarm.schedule.cancelled")
                return
            when_temp = extract_datetime(r, lang=self.lang)
            if when_temp is not None:
                when_temp = when_temp[0]
                # TODO add check for midnight
                # is_midnight = self._check_if_utt_has_midnight(r, when_temp,
                #                                               self.threshold)
                when = when_temp if when is None \
                                 else datetime(tzinfo=when.tzinfo,
                                               year=when.year,
                                               month=when.month,
                                               day=when.day,
                                               hour=when_temp.hour,
                                               minute=when_temp.minute)
            else:
                when = None

        # Verify time
        alarm_time = when
        confirmed_time = False
        while (not when or when == today) and not confirmed_time:
            if recur:
                t = nice_time(alarm_time, use_ampm=not self.use_24hour, use_24hour = self.use_24hour)
                conf = self.ask_yesno('confirm.recurring.alarm',
                                      data={
                                          'time': t,
                                          'recurrence': self._recur_desc(recur)
                                      })
            else:
                t = nice_date_time(alarm_time, now=today, use_ampm= not self.use_24hour, use_24hour = self.use_24hour, lang=self.lang)
                conf = self.ask_yesno('confirm.alarm', data={'time': t})
            if not conf:
                return
            if conf == 'yes':
                when = [alarm_time]
                confirmed_time = True
            else:
                # check if a new (corrected) time was given
                when = extract_datetime(conf, lang=self.lang)
                if when is not None:
                    when = when[0]
                if not when or when == today:
                    # Not a confirmation and no date/time in statement, quit
                    return
                alarm_time = when
                when = None  # reverify

        alarm = {}
        if not recur:
            alarm_time_ts = to_utc(alarm_time).timestamp()
            now_ts = now_utc().timestamp()
            if alarm_time_ts > now_ts:
                alarm = self.set_alarm(alarm_time, name)
            else:
                if (self.texts.get('today') in utt) or (self.texts.get('tonight') in utt):
                    self.speak_dialog('alarm.past')
                    return
                else:
                    # Set the alarm to find the next 24 hour time slot
                    while alarm_time_ts < now_ts:
                        alarm_time_ts += 86400.0
                    alarm_time = datetime.utcfromtimestamp(alarm_time_ts)
                    alarm = self.set_alarm(alarm_time, name)
        else:
            alarm = self.set_alarm(alarm_time, name, repeat=recur)

        if not alarm:
            # none set, it was a duplicate
            return

        # Don't want to hide the animation
        self.enclosure.deactivate_mouth_events()
        if confirmed_time:
            self.speak_dialog("alarm.scheduled")
        else:
            t = self._describe(alarm)
            reltime = nice_relative_time(self.get_alarm_local(alarm), lang=self.lang)
            if recur:
                self.speak_dialog("recurring.alarm.scheduled.for.time",
                                  data={"time": t, "rel": reltime})
            else:
                self.speak_dialog("alarm.scheduled.for.time",
                                  data={"time": t, "rel": reltime})

        self._show_alarm_anim(alarm_time)
        self.enclosure.activate_mouth_events()