diff --git a/__init__.py b/__init__.py index 55d77cd..b6c50e0 100644 --- a/__init__.py +++ b/__init__.py @@ -12,19 +12,17 @@ # See the License for the specific language governing permissions and # limitations under the License. +import pytz from datetime import datetime, timedelta from os.path import join, abspath, dirname, isfile import re import time - from alsaaudio import Mixer - from adapt.intent import IntentBuilder from mycroft import MycroftSkill, intent_handler -from mycroft.configuration.config import LocalConf, USER_CONFIG from mycroft.messagebus.message import Message from mycroft.util import play_mp3 -from mycroft.util.format import nice_date_time, nice_time, nice_date, join_list +from mycroft.util.format import nice_date_time, nice_time, nice_date, join_list, date_time_format from mycroft.util.parse import extract_datetime, extract_number from mycroft.util.time import to_utc, now_local, now_utc @@ -46,31 +44,13 @@ describe_repeat_rule, ) - # WORKING PHRASES/SEQUENCES: -# Set an alarm -# for 9 -# no for 9 am -# Set an alarm for tomorrow evening at 8:20 -# Set an alarm for monday morning at 8 -# create an alarm for monday morning at 8 -# snooze -# stop -# turn off the alarm -# create a repeating alarm for tuesdays at 7 am -# Set a recurring alarm -# Set a recurring alarm for weekdays at 7 -# snooze for 15 minutes -# set an alarm for 20 seconds from now -# Set an alarm every monday at 7 -# "Set a recurring alarm for mondays and wednesdays at 7" -# "Set an alarm for 10 am every weekday" +# See VK Tests for requirements/usage. # TODO: Context - save the alarm found in queries as context # When is the next alarm # > 7pm tomorrow # Cancel it - class AlarmSkill(MycroftSkill): """The official Alarm Skill for Mycroft AI.""" @@ -110,7 +90,7 @@ def __init__(self): try: self.mixer = Mixer() except Exception as err: - self.log.error("Couldn't allocate mixer, {}".format(repr(err))) + self.log.warning("Couldn't allocate mixer, {}".format(repr(err))) self.mixer = None self.saved_volume = None @@ -163,6 +143,20 @@ def initialize(self): # Support query for active alarms from other skills self.add_event("private.mycroftai.has_alarm", self.on_has_alarm) + # establish local timezone from config + self.local_tz = self.location_timezone + self.log.info("Local timezone configured for %s" % (self.local_tz,)) + + self.weekdays = None + self.months = None + date_time_format.cache(self.lang) + if self.lang in date_time_format.lang_config.keys(): + self.weekdays = list(date_time_format.lang_config[self.lang]['weekday'].values()) + self.months = list(date_time_format.lang_config[self.lang]['month'].values()) + if self.weekdays is None or self.months is None: + self.log.error("Error! weekdays:%s, months:%s" % (self.weekdays, self.months)) + + def on_has_alarm(self, message): """Reply to requests for alarm on/off status.""" total = len(self.settings["alarm"]) @@ -270,7 +264,6 @@ def handle_wake_me(self, message): @intent_handler( IntentBuilder("") - .require("Set") .require("Alarm") .optionally("Recurring") .optionally("Recurrence") @@ -525,7 +518,7 @@ def _get_alarm_matches( # No alarms if alarms is None or len(alarms) == 0: - self.log.error("Cannot get match. No active alarms.") + self.log.info("Cannot get match. No active alarms.") return (status[2], None) # Extract Alarm Time @@ -552,8 +545,29 @@ def _get_alarm_matches( time_alarm = to_utc(when).timestamp() if is_midnight: time_alarm = time_alarm + 86400.0 + time_matches = [a for a in alarms if abs(a["timestamp"] - time_alarm) <= 60] + # add other categories of alarm matches here + utt = self.workaround_lingua_franca(utt) + when, utt_no_datetime = extract_datetime(utt) or (None, utt) + + when_utc = None + if when is not None: + when_utc = to_utc(when) + + have_time = False + if when_utc: + user_time = when.strftime("%H:%M:%S") + if user_time == "00:00:00" and self.voc_match(utt, "Midnight"): + have_time = True + if user_time != "00:00:00": + have_time = True + + user_dow = self.get_dow_from_utterance(utt) + + advanced_matches = self.get_advanced_matches(utt, have_time, when, when_utc, user_dow, alarms) + # Extract Recurrence recur = None recurrence_matches = None @@ -593,6 +607,8 @@ def _get_alarm_matches( # Find the Intersection of the Alarms list and all the matched alarms orig_count = len(alarms) + if len(advanced_matches) > 0: + alarms = advanced_matches if when and time_matches: alarms = [a for a in alarms if a in time_matches] if recur and recurrence_matches: @@ -607,6 +623,11 @@ def _get_alarm_matches( elif utt and any(fuzzy_match(i, utt, 1) for i in next_words): return (status[4], [alarms[0]]) + if max_results < orig_count and len(alarms) == max_results: + # if we started with more than we have + # and that's how many we asked for + return (status[1], alarms) + # Given something to match but no match found if ( (number and number > len(alarms)) @@ -614,8 +635,8 @@ def _get_alarm_matches( or (when and not time_matches) ): return (status[2], None) - # If number of alarms filtered were the same, assume user asked for - # All alarms + # If number of alarms filtered were the same, + # assume user asked for ALL alarms if ( len(alarms) == orig_count and max_results > 1 @@ -624,6 +645,7 @@ def _get_alarm_matches( and not recur ): return (status[0], alarms) + # Return immediately if there is ordinal if number and number <= len(alarms): return (status[1], [alarms[number - 1]]) @@ -640,6 +662,7 @@ def _get_alarm_matches( if desc: items_string = join_list(desc, self.translate("and")) + self.log.debug("Too many alarms, ask for clarification") reply = self.get_response( dialog, data={ @@ -648,7 +671,15 @@ def _get_alarm_matches( }, num_retries=1, ) + if reply: + # if user wants to bail, bail! + # TODO - consider use of global "cancel.voc" to make + # cancelling experience consistent across Mycroft. + if self.voc_match(utt, "Terminate"): + self.log.debug("user cancels the select request") + return (status[3], None) + return self._get_alarm_matches( reply, alarm=alarms, @@ -662,6 +693,143 @@ def _get_alarm_matches( # No matches found return (status[2], None) + # sometimes LF returns a roman numeral for + # a number so the 26th will return xxvi + def roman_to_int(self, s): + rom_val = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000} + int_val = 0 + for i in range(len(s)): + if i > 0 and rom_val[s[i]] > rom_val[s[i - 1]]: + int_val += rom_val[s[i]] - 2 * rom_val[s[i - 1]] + else: + int_val += rom_val[s[i]] + return int_val + + def get_advanced_matches(self, utt, have_time, when, when_utc, user_dow, alarm_list): + '''see if we have any of the following + in order of preference + exact matches + date matches + time of day matches (tod) + day of week matches (dow) + day of month matches (dom) + ''' + # holds exact date and time matches + exact_matches = [] + dom = None + try: + dom = self.roman_to_int(utt) + except: + self.log.debug("Not a roman numeral") + + if dom is None: + dom = extract_number(utt) + + # if the user says a day of the week (mon-sun) we + # keep them in a separate list of day of week matches + dow_matches = [] + + # we also look for specific time matches like 9am + tod_matches = [] + if when_utc: + tod_matches = self.get_tod_matches(when.time(), alarm_list) + + # these alarms match our when_utc date only + date_matches = [] + + # these alarms match any numbers passed in like + # the 25th, 5 etc which we assume are dom + # hopefully this won't muss up ordinals + dom_matches = [] + + for alm in alarm_list: + self.log.debug(" Loop: %s" % (alm,)) + + # get utc time from alarm timestamp + dt_obj = datetime.fromtimestamp( alm['timestamp'] ) + dt_obj = dt_obj.astimezone(pytz.utc) + + # we also need a local version of our utc time + cfg_tz = pytz.timezone(self.local_tz) + dt_local = dt_obj.astimezone(cfg_tz) + + if user_dow == dt_local.weekday(): + dow_matches.append(alm) + + if dom == dt_local.day: + dom_matches.append(alm) + + if have_time: + # unambiguous + if when_utc == dt_obj: + exact_matches.append(alm) + else: + self.log.debug(" Loop: when:%s, dt_obj:%s" % (when_utc, dt_obj)) + if when_utc is not None and dt_obj is not None: + # do dates match ? + if when_utc.strftime("%y-%m-%d") == dt_obj.strftime("%y-%m-%d"): + date_matches.append(alm) + + if len(exact_matches) > 0: + return exact_matches + + if len(date_matches) > 0: + return date_matches + + if len(tod_matches) > 0: + return tod_matches + + if len(dow_matches) > 0: + return dow_matches + + return dom_matches + + def get_tod_matches(self, alarm_time, alarm_list): + ''' find alarms where the time matches''' + tod_matches = [] + + for alarm in alarm_list: + # get utc time from alarm timestamp + dt_obj = datetime.fromtimestamp( alarm['timestamp'] ) + dt_obj = dt_obj.astimezone(pytz.utc) + + # we also need a local version of our utc time + cfg_tz = pytz.timezone(self.local_tz) + dt_local = dt_obj.astimezone(cfg_tz) + + self.log.debug("Check for TOD matches, dt_local.time()=%s" % (dt_local.time(),)) + if dt_local.time() == alarm_time: + tod_matches.append(alarm) + + return tod_matches + + def get_dow_from_utterance(self, utt): + user_dow = None + result = re.findall('(mon|tues|wed|thurs|fri|sat|sun)day', utt) + if result: + utt_dow = result[0] + 'day' + user_dow = self.weekdays.index(utt_dow) if utt_dow in self.weekdays else None + return user_dow + + def workaround_lingua_franca(self, utt): + # Lingua-franca workaround - day of + # week and date confuses LF terribly. + # if a day of the week (monday, friday, + # etc) is included with a valid date + # like "monday april 5th" LF will + # return bad data so we make sure + # we never include both. "monday + # april 5th" becomes "april 5th". + + for month in self.months: + if utt.find(month) > -1 and re.search(r'\d+', utt): + # if we have a month and a number/day + # whack any days of week terms + for day in self.weekdays: + utt = utt.replace(day,'') + + return utt + @intent_handler( IntentBuilder("") .require("Delete") @@ -690,6 +858,10 @@ def handle_delete(self, message): is_response=False, ) + if status == "User Cancelled": + self.speak_dialog("alarm.delete.cancelled") + return + if alarms: total = len(alarms) else: @@ -698,6 +870,7 @@ def handle_delete(self, message): if total == 1: desc = self._describe(alarms[0]) recurring = ".recurring" if alarms[0]["repeat_rule"] else "" + if ( self.ask_yesno("ask.cancel.desc.alarm" + recurring, data={"desc": desc}) == "yes" @@ -739,11 +912,14 @@ def snooze_alarm(self, message): if not has_expired_alarm(self.settings["alarm"]): return + self.cancel_scheduled_event("Beep") + self.cancel_scheduled_event("NextAlarm") + self.__end_beep() self.__end_flash() utt = message.data.get("utterance") or "" - snooze_for = extract_number(utt) + snooze_for = extract_number(utt[0]) if not snooze_for or snooze_for < 1: snooze_for = 9 # default to 9 minutes @@ -784,8 +960,18 @@ def converse(self, utterances, lang="en-us"): """While an alarm is expired, check all utterances for Stop vocab.""" if has_expired_alarm(self.settings["alarm"]): if utterances and self.voc_match(utterances[0], "StopBeeping"): - self._stop_expired_alarm() - return True # and consume this phrase + self._stop_expired_alarm() + elif self.voc_match(utterances[0], "Snooze"): + message = Message( + "internal.snooze", + data=dict(utterance=utterances) + ) + self.snooze_alarm(message) + else: + # TODO deal with this + self.log.info("AlarmSkill:Converse confused by %s" % (utterances[0],)) + + return True # and consume this phrase def stop(self, _=None): """Respond to system stop commands.""" @@ -799,6 +985,8 @@ def _play_beep(self, _=None): """ Play alarm sound file """ now = now_local() + self.bus.emit(Message("mycroft.alarm.beeping", data=dict(time=now.strftime("%m/%d/%Y, %H:%M:%S")))) + if not self.beep_start_time: self.beep_start_time = now elif (now - self.beep_start_time).total_seconds() > self.settings[ @@ -868,28 +1056,6 @@ def __end_beep(self): pass self.beep_process = None self._restore_volume() - self._restore_listen_beep() - - def _restore_listen_beep(self): - if "user_beep_setting" in self.settings: - # Wipe from local config - new_conf_values = {"confirm_listening": False} - user_config = LocalConf(USER_CONFIG) - - if ( - self.settings["user_beep_setting"] is None - and "confirm_listening" in user_config - ): - del user_config["confirm_listening"] - else: - user_config.merge( - {"confirm_listening": self.settings["user_beep_setting"]} - ) - user_config.store() - - # Notify all processes to update their loaded configs - self.bus.emit(Message("configuration.updated")) - del self.settings["user_beep_setting"] def _stop_expired_alarm(self): if has_expired_alarm(self.settings["alarm"]): diff --git a/test/behave/skill-alarm.feature b/test/behave/skill-alarm.feature index e4f6bce..a6edc89 100644 --- a/test/behave/skill-alarm.feature +++ b/test/behave/skill-alarm.feature @@ -10,12 +10,11 @@ Feature: Alarm skill functionality | set alarm for a time | | set alarm for 8 am | | set an alarm for 7:30 am | - | create an alarm for 7:30 am | + | create an alarm for 7:30 pm | | start an alarm for 6:30 am | | let me know when it's 8:30 pm | | wake me up at 7 tomorrow morning | - @xfail # MS-64 https://mycroft.atlassian.net/browse/MS-64 Scenario Outline: user sets an alarm for a time Given an english speaking user @@ -25,8 +24,8 @@ Feature: Alarm skill functionality Examples: user sets an alarm for a time | set alarm for a time | - | alarm 6 pm | - | alarm for 8 tonight | + | set alarm 6:01 pm | + | alarm for 8:02 tonight | Scenario Outline: user sets an alarm without saying a time Given an english speaking user @@ -39,12 +38,11 @@ Feature: Alarm skill functionality Examples: set alarm withot saying a time | set alarm without saying a time | | set alarm | - | set an alarm | + | new alarm | | create an alarm | - @xfail # Jira MS-65 https://mycroft.atlassian.net/browse/MS-65 - Scenario Outline: Failing user sets an alarm without saying a time + Scenario Outline: user sets an alarm without saying a time Given an english speaking user And there are no previous alarms set When the user says "" @@ -54,10 +52,9 @@ Feature: Alarm skill functionality Examples: set alarm withot saying a time | set alarm without saying a time | - | set an alarm for tomorrow morning | + | set an alarm for tomorrow | | wake me up tomorrow | - | alarm tonight | - | alarm | + | create alarm | Scenario Outline: User sets an alarm without saying a time but then cancels Given an english speaking user @@ -71,7 +68,6 @@ Feature: Alarm skill functionality | set an alarm | nevermind | | create an alarm | cancel | - @xfail # Jira MS-109 https://mycroft.atlassian.net/browse/MS-109 Scenario Outline: User sets an alarm without saying a time but then cancels Given an english speaking user @@ -94,10 +90,10 @@ Feature: Alarm skill functionality | set a named alarm for a time | | set an alarm named sandwich for 12 pm | | set an alarm for 10 am for stretching | - | set an alarm for stretching 10 am | + | set an alarm for stretching 10 pm | | set an alarm named brunch for 11 am | - | set an alarm called brunch for 11 am | - | set an alarm named workout for 11 am | + | set an alarm called brunch for 11:30 am | + | set an alarm named workout for 11 pm | Scenario Outline: user sets an alarm without specifiying am or pm Given an english speaking user @@ -109,10 +105,9 @@ Feature: Alarm skill functionality | set an alarm for a time without am or pm | | set an alarm for 6:30 | | set an alarm for 7 | - | wake me up at 6:30 | + | wake me up at 5:30 | | let me know when it's 6 | - @xfail # Jira MS-66 https://mycroft.atlassian.net/browse/MS-66 Scenario Outline: user sets an alarm without specifiying am or pm Given an english speaking user @@ -122,11 +117,10 @@ Feature: Alarm skill functionality Examples: user sets an alarm without specifiying am or pm | set an alarm for a time without am or pm | - | alarm for 12 | + | set alarm for 12 | - @xfail # Jira MS-67 https://mycroft.atlassian.net/browse/MS-67 - Scenario Outline: Failing set an alarm for a duration instead of a time + Scenario Outline: set an alarm for a duration instead of a time Given an english speaking user And there are no previous alarms set When the user says "" @@ -134,9 +128,9 @@ Feature: Alarm skill functionality Examples: | set an alarm for a duration | - | set an alarm for 30 minutes | - | alarm in 5 minutes | - | alarm in 5 minutes and 30 seconds | + | create an alarm for 30 minutes | + | set alarm in 5 minutes | + | new alarm in 5 minutes and 30 seconds | | set an alarm 8 hours from now | | set an alarm 8 hours and 30 minutes from now | @@ -163,24 +157,24 @@ Feature: Alarm skill functionality Examples: set a recurring alarm | set a recurring alarm for a time | | set alarm every weekday at 7:30 am | - | wake me up every weekday at 7:30 am | + | wake me up every weekday at 4:30 am | | set an alarm every wednesday at 11 am | | set an alarm for weekends at 3 pm | - | set an alarm for 3 pm every weekend | + | set an alarm for 1 pm every weekend | - @xfail # Jira 68 https://mycroft.atlassian.net/browse/MS-68 - Scenario Outline: Failing user sets a recurring alarm + Scenario Outline: user sets a recurring alarm Given an english speaking user And there are no previous alarms set When the user says "" Then "mycroft-alarm" should reply with dialog from "recurring.alarm.scheduled.for.time.dialog" + # removed because not currently supported + # | wake me up every day at 5:30 am except on the weekends | Examples: set a recurring alarm | set a recurring alarm for a time | | set alarm every weekday at 7:30 am | - | alarm every weekday at 7:30 am | - | wake me up every day at 7:30 am except on the weekends | + | alarm every weekday at 6:30 am | Scenario Outline: user sets a recurring alarm without saying a time Given an english speaking user @@ -251,9 +245,8 @@ Feature: Alarm skill functionality | when will my alarm go off | | when's my alarm | - @xfail # Jira 69 https://mycroft.atlassian.net/browse/MS-69 - Scenario Outline: Failing user asks for alarm status of a single alarm + Scenario Outline: user asks for alarm status of a single alarm Given an english speaking user And there are no previous alarms set And an alarm is set for 9:00 am on weekdays @@ -285,9 +278,8 @@ Feature: Alarm skill functionality | when will my alarm go off | | when's my alarm | - @xfail # Jira 70 https://mycroft.atlassian.net/browse/MS-70 - Scenario Outline: Failing user asks for alarm status of multiple alarms + Scenario Outline: user asks for alarm status of multiple alarms Given an english speaking user And there are no previous alarms set And an alarm is set for 9:00 am on weekdays @@ -318,9 +310,8 @@ Feature: Alarm skill functionality | when will my alarm go off | | when's my alarm | - @xfail # Jira MS-71 https://mycroft.atlassian.net/browse/MS-71 - Scenario Outline: Failing user asks for alarm status when no alarms are sets + Scenario Outline: user asks for alarm status when no alarms are sets Given an english speaking user And there are no previous alarms set When the user says "" @@ -344,6 +335,7 @@ Feature: Alarm skill functionality Examples: stop beeping | stop | | stop | + | kill | | stop alarm | | disable alarm | | cancel | @@ -355,42 +347,6 @@ Feature: Alarm skill functionality | abort | | kill alarm | - @xfail - # Jira MS-72 https://mycroft.atlassian.net/browse/MS-72 - Scenario Outline: user snoozes a beeping alarm - Given an english speaking user - And there are no previous alarms set - And an alarm is expired and beeping - When the user says "" - Then "mycroft-alarm" should stop beeping and start beeping again 10 minutes - - Examples: snooze a beeping alarm - | snooze | - | snooze | - | snooze alarm | - | not yet | - | 10 more minutes | - | 10 minutes | - | snooze for 10 minutes | - | give me 10 minutes | - | wake me up in 10 minutes | - | remind me in 10 minutes | - | let me sleep | - - @xfail - # Jira MS-73 https://mycroft.atlassian.net/browse/MS-73 - Scenario Outline: user snoozes an beeping alarm for a specific time - Given an english speaking user - And there are no previous alarms set - And an alarm is expired and beeping - When the user says "" - Then "mycroft-alarm" should stop beeping and start beeping again 5 minutes - - Examples: snooze a beeping alarm for a specific time - | snooze for a time | - | snooze for 5 minutes | - | give me 10 minutes | - Scenario Outline: user deletes an alarm when a single alarm is active Given an english speaking user And there are no previous alarms set @@ -427,7 +383,6 @@ Feature: Alarm skill functionality | cancel | - @xfail # Jira MS-74 https://mycroft.atlassian.net/browse/MS-74 Scenario Outline: user deletes an alarm when multiple alarms are active Given an english speaking user @@ -451,7 +406,6 @@ Feature: Alarm skill functionality | abort alarm | | remove alarm | - @xfail # Jira MS-75 https://mycroft.atlassian.net/browse/MS-75 Scenario Outline: user deletes a specific alarm Given an english speaking user @@ -494,3 +448,40 @@ Feature: Alarm skill functionality | remove all alarms | | remove every alarm | | delete every alarm | + +# Jira MS-72 https://mycroft.atlassian.net/browse/MS-72 + Scenario Outline: user snoozes a beeping alarm + Given an english speaking user + And there are no previous alarms set + And an alarm is expired and beeping + When the user says "" + Then "mycroft-alarm" should stop beeping and start beeping again in 10 minutes + + Examples: snooze a beeping alarm + | snooze | + | snooze | + | snooze alarm | + | not yet | + | 10 more minutes | + | 10 minutes | + | snooze for 10 minutes | + | give me 10 minutes | + | wake me up in 10 minutes | + | remind me in 10 minutes | + | let me sleep | + + # Jira MS-73 https://mycroft.atlassian.net/browse/MS-73 + Scenario Outline: user snoozes an beeping alarm for a specific time + Given an english speaking user + And there are no previous alarms set + And an alarm is expired and beeping + When the user says "" + Then "mycroft-alarm" should stop beeping and start beeping again in 5 minutes + + Examples: snooze a beeping alarm for a specific time + | snooze for a time | + | snooze for 5 minutes | + | give me 5 minutes | + | snooze 5 | + | snooze for 5 | + diff --git a/test/behave/steps/alarms.py b/test/behave/steps/alarms.py index 44327d1..8866505 100644 --- a/test/behave/steps/alarms.py +++ b/test/behave/steps/alarms.py @@ -10,6 +10,7 @@ @given('an alarm is set for {alarm_time}') def given_set_alarm(context, alarm_time): emit_utterance(context.bus, 'set an alarm for {}'.format(alarm_time)) + time.sleep(3) wait_for_dialog(context.bus, ['alarm.scheduled.for.time']) context.bus.clear_messages() @@ -25,16 +26,17 @@ def given_no_alarms(context): 'alarm.cancelled.multi', 'alarm.cancelled.recurring'] - print('ASKING QUESTION') + #print('\nASKING QUESTION') emit_utterance(context.bus, 'cancel all alarms') for i in range(10): + wait_while_speaking() for message in context.bus.get_messages('speak'): if message.data.get('meta', {}).get('dialog') in followups: - print('Answering yes!') - time.sleep(1) - wait_while_speaking() + #print("\nWaiting before saying yes ...") + time.sleep(2) emit_utterance(context.bus, 'yes') - wait_for_dialog(context.bus, cancelled) + rc = wait_for_dialog(context.bus, cancelled) + #print('\nWere we understood--->rc= %s' % (rc,)) context.bus.clear_messages() return elif message.data.get('meta', {}).get('dialog') in no_alarms: @@ -46,11 +48,82 @@ def given_no_alarms(context): @given('an alarm is expired and beeping') def given_expired_alarm(context): - emit_utterance(context.bus, 'set an alarm in 30 seconds') - time.sleep(30) + got_msg = False + emit_utterance(context.bus, 'set an alarm for 1 minute from now') + + # drain any existing messages + for message in context.bus.get_messages('mycroft.alarm.beeping'): + pass + + ctr = 0 + while ctr < 60 and not got_msg: + time.sleep(1) + + # wait for msg = beeping + for message in context.bus.get_messages('mycroft.alarm.beeping'): + #print("\n\nDETECT BEEPING MSG !!!\n\n") + got_msg = True + + ctr += 1 + + context.bus.clear_messages() + assert got_msg, "Error, did not get beeping message!" @then('"mycroft-alarm" should stop beeping') def then_stop_beeping(context): # TODO Implement pass + + +@then('"mycroft-alarm" should stop beeping and start beeping again in 10 minutes') +def then_stop_and_start_beeping(context): + start_time = time.time() + got_msg = False + + # drain any existing messages + for message in context.bus.get_messages('mycroft.alarm.beeping'): + pass + + ctr = 0 + while ctr < 3 and not got_msg: + time.sleep(60) + + # wait for msg = beeping + for message in context.bus.get_messages('mycroft.alarm.beeping'): + got_msg = True + + ctr += 1 + + elapsed = time.time() - start_time + context.bus.clear_messages() + #assert got_msg and elapsed > 5*60, "Error, did not get beeping message!" + assert got_msg, "Error, did not get beeping message!" + + +@then('"mycroft-alarm" should stop beeping and start beeping again in 5 minutes') +def then_stop_and_start_beeping(context): + start_time = time.time() + got_msg = False + + # drain any existing messages + for message in context.bus.get_messages('mycroft.alarm.beeping'): + pass + + ctr = 0 + while ctr < 7 and not got_msg: + time.sleep(60) + + # wait for msg = beeping + for message in context.bus.get_messages('mycroft.alarm.beeping'): + got_msg = True + + ctr += 1 + + elapsed = time.time() - start_time + context.bus.clear_messages() + # TODO assert got msg and > 3 minutes! + #assert got_msg and elapsed > 3*60, "Error, did not get beeping message!" + assert got_msg, "Error, did not get beeping message!" + + diff --git a/vocab/en-us/Midnight.voc b/vocab/en-us/Midnight.voc new file mode 100644 index 0000000..4b4143e --- /dev/null +++ b/vocab/en-us/Midnight.voc @@ -0,0 +1 @@ +midnight diff --git a/vocab/en-us/Query.voc b/vocab/en-us/Query.voc index 33355e0..29fe2e8 100644 --- a/vocab/en-us/Query.voc +++ b/vocab/en-us/Query.voc @@ -13,6 +13,10 @@ when will what time what day show +show me +tell +tell me give +give me how is -how are \ No newline at end of file +how are diff --git a/vocab/en-us/Set.voc b/vocab/en-us/Set.voc index c2c20b0..748dc48 100644 --- a/vocab/en-us/Set.voc +++ b/vocab/en-us/Set.voc @@ -2,3 +2,4 @@ add set start create +new diff --git a/vocab/en-us/Snooze.voc b/vocab/en-us/Snooze.voc new file mode 100644 index 0000000..0952a0e --- /dev/null +++ b/vocab/en-us/Snooze.voc @@ -0,0 +1,2 @@ +snooze + diff --git a/vocab/en-us/StopBeeping.voc b/vocab/en-us/StopBeeping.voc index 00e4496..f7b89c1 100644 --- a/vocab/en-us/StopBeeping.voc +++ b/vocab/en-us/StopBeeping.voc @@ -11,4 +11,4 @@ off disable ok okay -alright \ No newline at end of file +alright diff --git a/vocab/en-us/Terminate.voc b/vocab/en-us/Terminate.voc new file mode 100644 index 0000000..4d0b551 --- /dev/null +++ b/vocab/en-us/Terminate.voc @@ -0,0 +1,11 @@ +terminate +no +none +neither +never +nevermind +forget +cancel +exit +stop +abort