def test_ordered_transitions(self): states = ['beginning', 'middle', 'end'] m = Machine('self', states) m.add_ordered_transitions() self.assertEqual(m.state, 'initial') m.next_state() self.assertEqual(m.state, 'beginning') m.next_state() m.next_state() self.assertEqual(m.state, 'end') m.next_state() self.assertEqual(m.state, 'initial') # Include initial state in loop m = Machine('self', states) m.add_ordered_transitions(loop_includes_initial=False) m.to_end() m.next_state() self.assertEqual(m.state, 'beginning') # Do not loop transitions m = Machine('self', states) m.add_ordered_transitions(loop=False) m.to_end() with self.assertRaises(MachineError): m.next_state() # Test user-determined sequence and trigger name m = Machine('self', states, initial='beginning') m.add_ordered_transitions(['end', 'beginning'], trigger='advance') m.advance() self.assertEqual(m.state, 'end') m.advance() self.assertEqual(m.state, 'beginning') # Via init argument m = Machine('self', states, initial='beginning', ordered_transitions=True) m.next_state() self.assertEqual(m.state, 'middle') # Alter initial state m = Machine('self', states, initial='middle', ordered_transitions=True) m.next_state() self.assertEqual(m.state, 'end') m.next_state() self.assertEqual(m.state, 'beginning') # Partial state machine without the initial state m = Machine('self', states, initial='beginning') m.add_ordered_transitions(['middle', 'end']) self.assertEqual(m.state, 'beginning') with self.assertRaises(MachineError): m.next_state() m.to_middle() for s in ('end', 'middle', 'end'): m.next_state() self.assertEqual(m.state, s)
class TaskMachine(object): def __init__(self, machine_dict): # self.machine_dict = machine_dict self.events = Events([Event(**e) for e in machine_dict['events']]) self.machine = Machine(model=self, states=self.states(), initial=STATES.PENDING) self.machine.add_ordered_transitions() self.max_timeout = machine_dict.get('max_timeout', FIVE_MINUTES) def states(self): pre_states = [STATES.PENDING] # scheduled? # pre-flight resource checks? if a db or an integration # is not accessible, fail early option post_states = [STATES.FINISHED] return pre_states + self.events.states() + post_states def is_running(self): return True # can event fulfillment strategy decorate? # noop strategy by default def run_current_event(self, event_result_q): """ Executes the current event, using the provided fulfilment strategy until the transition conditions are met. TODO, errors, timeouts, etc. :param next_state_q: :return: """ # right now sleep then trigger completion gevent.spawn(self.events.run, self.state, event_result_q)
class Week(object): states = [ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday' ] def __init__(self, model): self.model = model self.machine = Machine(model=self, states=Week.states, initial='Thursday') self.machine.add_ordered_transitions()
def test_ordered_transition_condition(self): class Model: def __init__(self): self.blocker = False def check_blocker(self): return self.blocker model = Model() states = ['beginning', 'middle', 'end'] m = Machine(model, states, initial='beginning') m.add_ordered_transitions(conditions=[None, None, 'check_blocker']) model.to_end() self.assertFalse(model.next_state()) model.blocker = True self.assertTrue(model.next_state())
def get_machine(model): """Create the parser state machine. :param model: An instance of DbtLogParser. The state machine will mutate the parser after this function is invoked. """ m = Machine( model=model, states=[ State(name=States.SEEK_START), State(name=States.SEEK_START_SUMMARY), State(name=States.SEEK_FINISH), State(name=States.SEEK_DONE), State(name=States.DONE), ], initial=States.SEEK_START, ) # the states above are linear in order; by using `add_ordered_transitions` # we automatically make it such that the single trigger `process_next_line` # will move linearly between states as ordered above. m.add_ordered_transitions( trigger="process_next_line", # `condition` has a 1:1 mapping with states i.e. # we will not transition out of the first state until the first condition # is satisfied. conditions correspond to boolean attributes on the model # i.e. the parser conditions=[ "found_start", "found_start_summary", "found_finish", "found_done", lambda *args, **kwargs: True, ], # before attempting to transition, the following functions will be # invoked with any args or kwargs passed to `process_next_line`; # `prepare` occurs before conditions are evaluated; # if conditions fail to pass, a transition is halted; # in this way, we assure each attempted transition processes another # log line prepare=[ "seek_start", "seek_summary", "seek_finish", "seek_done", None ], ) return m
def test_ordered_transition_callback(self): class Model: def __init__(self): self.flag = False def make_true(self): self.flag = True model = Model() states = ['beginning', 'middle', 'end'] transits = [None, None, 'make_true'] m = Machine(model, states, initial='beginning') m.add_ordered_transitions(before=transits) model.next_state() self.assertFalse(model.flag) model.next_state() model.next_state() self.assertTrue(model.flag)
class NarcolepticAttocube(object): # Define some states. Most of the time, narcoleptic superheroes are just like # everyone else. Except for... def __init__(self, name): self.name = name # Initialize the state machine self.machine = Machine( model=self, states=attocube_states, transitions=attocube_transitions, initial='system idle', ignore_invalid_triggers=True, ) self.machine.add_ordered_transitions( ['measurement starting', 'measurement running', 'system idle']) self.machine.add_ordered_transitions([ 'pilot laser enabled', 'optics alignment starting', 'optics alignment running', 'pilot laser enabled', ]) def on_enter_measurement_starting(self): sleep(1) self.next_state() def on_enter_measurement_running(self): sleep(3) self.next_state() def on_enter_alignment_starting(self): print(self.state) sleep(1) self.next_state() def on_enter_alignment_running(self): print(self.state) sleep(3) self.next_state()
class FSM(object): state = None states = ['injecting', 'testing_quality', 'testing_extraction'] initial_state = states[0] camera = None def __init__(self): self.camera = Camera() # Initialize the state machine self.machine = Machine(model=self, states=self.states, initial=self.initial_state) self.machine.add_ordered_transitions() self.machine.on_enter_injecting('inject') self.machine.on_enter_testing_quality('test_quality') self.machine.on_enter_testing_extraction('test_extraction') def test_quality(self): log.info("Testing quality") log.info("Waiting for open signal") open_mould_signal = IO(Ports["open_signal"]) open_mould_signal.wait_signal() log.info("Open signal acknowledged") log.info("Taking photo") test_quality_image = self.camera.take_photo() test_quality_image.save("full") def test_extraction(self): log.info("Testing extraction") log.info("Waiting for extraction signal") extration_complete_signal = IO(Ports["extraction_signal"]) extration_complete_signal.wait_signal() log.info("Open signal acknowledged") log.info("Taking photo") test_extraction_image = self.camera.take_photo() test_extraction_image.save("empty") def inject(self): log.info("Injecting")
def test_ordered_transitions(self): states = ['beginning', 'middle', 'end'] m = Machine(None, states) m.add_ordered_transitions() self.assertEquals(m.state, 'initial') m.next_state() self.assertEquals(m.state, 'beginning') m.next_state() m.next_state() self.assertEquals(m.state, 'end') m.next_state() self.assertEquals(m.state, 'initial') # Include initial state in loop m = Machine(None, states) m.add_ordered_transitions(loop_includes_initial=False) m.to_end() m.next_state() self.assertEquals(m.state, 'beginning') # Test user-determined sequence and trigger name m = Machine(None, states, initial='beginning') m.add_ordered_transitions(['end', 'beginning'], trigger='advance') m.advance() self.assertEquals(m.state, 'end') m.advance() self.assertEquals(m.state, 'beginning') # Via init argument m = Machine( None, states, initial='beginning', ordered_transitions=True) m.next_state() self.assertEquals(m.state, 'middle')
def test_ordered_transitions(self): states = ["beginning", "middle", "end"] m = Machine(None, states) m.add_ordered_transitions() self.assertEquals(m.state, "initial") m.next_state() self.assertEquals(m.state, "beginning") m.next_state() m.next_state() self.assertEquals(m.state, "end") m.next_state() self.assertEquals(m.state, "initial") # Include initial state in loop m = Machine(None, states) m.add_ordered_transitions(loop_includes_initial=False) m.to_end() m.next_state() self.assertEquals(m.state, "beginning") # Test user-determined sequence and trigger name m = Machine(None, states, initial="beginning") m.add_ordered_transitions(["end", "beginning"], trigger="advance") m.advance() self.assertEquals(m.state, "end") m.advance() self.assertEquals(m.state, "beginning") # Via init argument m = Machine(None, states, initial="beginning", ordered_transitions=True) m.next_state() self.assertEquals(m.state, "middle")
class Calendar(object): def __init__(self, months, daysPerMonth, firstMonth, year): # self.locality = locality self.machine = Machine(model=self, states=months, initial=firstMonth) self.machine.add_ordered_transitions() self.first_month = firstMonth self.dayOfMonth = 1 #should use daysPerMonth def next_day(self): if self.dayOfMonth == 30: self.next_state() self.dayOfMonth = 1 else: self.dayOfMonth += 1 def yearChange(self): self.year += 1 def date(self): date = self.state + " " + str(self.dayOfMonth) + ", " + str(self.year) return date
def test_ordered_transition_error(self): m = Machine(states=['A'], initial='A') with self.assertRaises(ValueError): m.add_ordered_transitions() m.add_state('B') m.add_ordered_transitions() m.add_state('C') with self.assertRaises(ValueError): m.add_ordered_transitions(['C'])
class TransportOrderStateMachine(object): # Define some states. Most of the time, narcoleptic superheroes are just like # everyone else. Except for... states = [ 'init', 'waitForTrigger', 'startPickup', 'movingToPickup', 'waitForLoading', 'startDelivery', 'movingToDelivery', 'waitForUnloading', 'waitForFinished', 'waitForFinishedEvents', 'finished', 'error' ] def __init__(self, name): self.name = name #self.task = task self.uuid = createUuid(self.name) print(self.uuid) # Initialize the state machine self.machine = Machine(model=self, states=TransportOrderStateMachine.states, initial='init') self.machine.add_ordered_transitions() # Add some transitions. We could also define these using a static list of # dictionaries, as we did with states above, and then pass the list to # the Machine initializer as the transitions= argument. # At some point, every superhero must rise and shine. self.machine.add_transition(trigger='Initialized', source='init', dest='waitForTrigger') self.machine.add_transition(trigger='TriggerReceived', source='waitForTrigger', dest='startPickup') # Pickup self.machine.add_transition(trigger='GotoPickupDestination', source='startPickup', dest='movingToPickup') self.machine.add_transition(trigger='ArrivedAtPickupDestination', source='movingToPickup', dest='waitForLoading') self.machine.add_transition(trigger='AgvIsLoaded', source='waitForLoading', dest='startDelivery') # Delivery self.machine.add_transition(trigger='GotoDeliveryDestination', source='startDelivery', dest='movingToDelivery') self.machine.add_transition(trigger='ArrivedAtDeliveryDestination', source='movingToDelivery', dest='waitForUnloading') self.machine.add_transition(trigger='AgvIsUnloaded', source='waitForUnloading', dest='waitForFinished') # Unused at the moment self.machine.add_transition(trigger='OrderStart', source='moveOrderStart', dest='moveOrder') self.machine.add_transition(trigger='OrderFinished', source='moveOrder', dest='moveOrderFinished') # Done self.machine.add_transition(trigger='SubscribedToFinishedEvents', source='waitForFinished', dest='waitForFinishedEvents') self.machine.add_transition(trigger='FinishedTriggerReceived', source='waitForFinishedEvents', dest='finished') self.machine.add_transition( trigger='FinishedReceived', source=['waitForFinished', 'waitForFinishedEvents'], dest='finished') self.machine.add_transition(trigger='TransportOrderError', source='*', dest='error') self.machine.add_transition(trigger='Panic', source='*', dest='idle') self.machine.add_transition('Panic', '*', 'error') self.machine.add_transition('Init', 'error', 'init') # def registerForTrigger(self): # print "reigstererd for Trigger" def get_state(self): return self.state def current_state_is(self, _state): if not isinstance(_state, TRANSPORT_ORDER_STATES): raise RuntimeError("Wrong parameter") if self.__dict__["state"]: if self.state == self.states[_state.value]: return True return False def getUuid(self): return self.uuid
class MainController: """ This Class is the global controller of the application. """ states = ['init', 'starting_trigger', 'unpausing_trigger', 'playing_ready_sound', 'waiting_for_trigger_callback', 'start_order_listener', 'playing_wake_up_answer', 'waiting_for_order_listener_callback', 'analysing_order'] def __init__(self, brain=None): self.brain = brain # get global configuration sl = SettingLoader() self.settings = sl.settings # keep in memory the order to process self.order_to_process = None # Starting the rest API self._start_rest_api() # save an instance of the trigger self.trigger_instance = None self.trigger_callback_called = False # save the current order listener self.order_listener = None self.order_listener_callback_called = False # boolean used to know id we played the on ready notification at least one time self.on_ready_notification_played_once = False # Initialize the state machine self.machine = Machine(model=self, states=MainController.states, initial='init', queued=True) # define transitions self.machine.add_transition('start_trigger', 'init', 'starting_trigger') self.machine.add_transition('unpause_trigger', ['starting_trigger', 'analysing_order'], 'unpausing_trigger') self.machine.add_transition('play_ready_sound', 'unpausing_trigger', 'playing_ready_sound') self.machine.add_transition('wait_trigger_callback', 'playing_ready_sound', 'waiting_for_trigger_callback') self.machine.add_transition('play_wake_up_answer', 'waiting_for_trigger_callback', 'playing_wake_up_answer') self.machine.add_transition('wait_for_order', 'playing_wake_up_answer', 'waiting_for_order_listener_callback') self.machine.add_transition('analyse_order', 'waiting_for_order_listener_callback', 'analysing_order') self.machine.add_ordered_transitions() # add method which are called when changing state self.machine.on_enter_starting_trigger('start_trigger_process') self.machine.on_enter_playing_ready_sound('play_ready_sound_process') self.machine.on_enter_waiting_for_trigger_callback('waiting_for_trigger_callback_thread') self.machine.on_enter_playing_wake_up_answer('play_wake_up_answer_thread') self.machine.on_enter_start_order_listener('start_order_listener_thread') self.machine.on_enter_waiting_for_order_listener_callback('waiting_for_order_listener_callback_thread') self.machine.on_enter_analysing_order('analysing_order_thread') self.machine.on_enter_unpausing_trigger('unpausing_trigger_process') self.start_trigger() def start_trigger_process(self): """ This function will start the trigger thread that listen for the hotword """ logger.debug("Entering state: %s" % self.state) self.trigger_instance = self._get_default_trigger() self.trigger_instance.daemon = True # Wait that the kalliope trigger is pronounced by the user self.trigger_instance.start() self.next_state() def unpausing_trigger_process(self): """ If the trigger was in pause, this method will unpause it to listen again for the hotword """ logger.debug("Entering state: %s" % self.state) self.trigger_instance.unpause() self.trigger_callback_called = False Utils.print_info("Waiting for trigger detection") self.next_state() def play_ready_sound_process(self): """ Play a sound when Kalliope is ready to be awaken at the first start """ logger.debug("Entering state: %s" % self.state) if (not self.on_ready_notification_played_once and self.settings.play_on_ready_notification == "once") or \ self.settings.play_on_ready_notification == "always": # we remember that we played the notification one time self.on_ready_notification_played_once = True # here we tell the user that we are listening if self.settings.on_ready_answers is not None: Say(message=self.settings.on_ready_answers) elif self.settings.on_ready_sounds is not None: random_sound_to_play = self._get_random_sound(self.settings.on_ready_sounds) Mplayer.play(random_sound_to_play) self.next_state() def waiting_for_trigger_callback_thread(self): """ Method to print in debug that the main process is waiting for a trigger detection """ logger.debug("Entering state: %s" % self.state) # this loop is used to keep the main thread alive while not self.trigger_callback_called: sleep(0.1) self.next_state() def waiting_for_order_listener_callback_thread(self): """ Method to print in debug that the main process is waiting for an order to analyse """ logger.debug("Entering state: %s" % self.state) # this loop is used to keep the main thread alive while not self.order_listener_callback_called: sleep(0.1) self.next_state() def trigger_callback(self): """ we have detected the hotword, we can now pause the Trigger for a while The user can speak out loud his order during this time. """ logger.debug("Trigger callback called, switching to the next state") # self.next_state() self.trigger_callback_called = True def start_order_listener_thread(self): """ Start the STT engine thread """ logger.debug("Entering state: %s" % self.state) # pause the trigger process self.trigger_instance.pause() # start listening for an order self.order_listener_callback_called = False self.order_listener = OrderListener(callback=self.order_listener_callback) self.order_listener.daemon = True self.order_listener.start() self.next_state() def play_wake_up_answer_thread(self): """ Play a sound or make Kalliope say something to notify the user that she has been awaken and now waiting for order """ logger.debug("Entering state: %s" % self.state) # if random wake answer sentence are present, we play this if self.settings.random_wake_up_answers is not None: Say(message=self.settings.random_wake_up_answers) else: random_sound_to_play = self._get_random_sound(self.settings.random_wake_up_sounds) Mplayer.play(random_sound_to_play) self.next_state() def order_listener_callback(self, order): """ Receive an order, try to retrieve it in the brain.yml to launch to attached plugins :param order: the sentence received :type order: str """ logger.debug("order listener callback called. Order to process: %s" % order) self.order_to_process = order self.order_listener_callback_called = True def analysing_order_thread(self): """ Start the order analyser with the caught order to process """ logger.debug("order in analysing_order_thread %s" % self.order_to_process) if self.order_to_process is not None: # maybe we have received a null audio from STT engine order_analyser = OrderAnalyser(self.order_to_process, brain=self.brain) order_analyser.start() else: if self.settings.default_synapse is not None: SynapseLauncher.start_synapse(name=self.settings.default_synapse, brain=self.brain) # return to the state "unpausing_trigger" self.unpause_trigger() def _get_default_trigger(self): """ Return an instance of the default trigger :return: Trigger """ for trigger in self.settings.triggers: if trigger.name == self.settings.default_trigger_name: return TriggerLauncher.get_trigger(trigger, callback=self.trigger_callback) @staticmethod def _get_random_sound(random_wake_up_sounds): """ Return a path of a sound to play If the path is absolute, test if file exist If the path is relative, we check if the file exist in the sound folder :param random_wake_up_sounds: List of wake_up sounds :return: path of a sound to play """ # take first randomly a path random_path = random.choice(random_wake_up_sounds) logger.debug("Selected sound: %s" % random_path) return Utils.get_real_file_path(random_path) def _start_rest_api(self): """ Start the Rest API if asked in the user settings """ # run the api if the user want it if self.settings.rest_api.active: Utils.print_info("Starting REST API Listening port: %s" % self.settings.rest_api.port) app = Flask(__name__) flask_api = FlaskAPI(app=app, port=self.settings.rest_api.port, brain=self.brain, allowed_cors_origin=self.settings.rest_api.allowed_cors_origin) flask_api.daemon = True flask_api.start()
class Order(SignalModule, Thread): states = ['init', 'starting_trigger', 'waiting_for_trigger_callback', 'stopping_trigger', 'start_order_listener', 'waiting_for_order_listener_callback', 'analysing_order'] def __init__(self): super(SignalModule, self).__init__() Thread.__init__(self, name=Order) Utils.print_info('Starting order signal') # load settings and brain from singleton sl = SettingLoader() self.settings = sl.settings self.brain = BrainLoader().brain # keep in memory the order to process self.order_to_process = None # get the player instance self.player_instance = PlayerLauncher.get_player(settings=self.settings) # save an instance of the trigger self.trigger_instance = None self.trigger_callback_called = False self.skip_trigger = False # keep the status of the trigger, if true we can skip it in the statue machine # save the current order listener self.order_listener = None self.order_listener_callback_called = False # Initialize the state machine self.machine = Machine(model=self, states=Order.states, initial='init', queued=True) # define transitions self.machine.add_transition('start_trigger', ['init', 'analysing_order'], 'starting_trigger') self.machine.add_transition('wait_trigger_callback', 'starting_trigger', 'waiting_for_trigger_callback') self.machine.add_transition('stop_trigger', 'waiting_for_trigger_callback', 'stopping_trigger') self.machine.add_transition('wait_for_order', 'stopping_trigger', 'waiting_for_order_listener_callback') self.machine.add_transition('analyse_order', 'waiting_for_order_listener_callback', 'analysing_order') self.machine.add_transition('start_order_listener', 'analysing_order', 'start_order_listener') self.machine.add_ordered_transitions() # add method which are called when changing state self.machine.on_enter_starting_trigger('start_trigger_process') self.machine.on_enter_waiting_for_trigger_callback('waiting_for_trigger_callback_thread') self.machine.on_enter_stopping_trigger('stop_trigger_process') self.machine.on_enter_start_order_listener('start_order_listener_thread') self.machine.on_enter_waiting_for_order_listener_callback('waiting_for_order_listener_callback_thread') self.machine.on_enter_analysing_order('analysing_order_thread') def run(self): # run hook on_start HookManager.on_start() self.start_trigger() def start_trigger_process(self): """ This function will start the trigger thread that listen for the hotword """ logger.debug("[Order] Entering state: %s" % self.state) HookManager.on_waiting_for_trigger() self.trigger_instance = TriggerLauncher.get_trigger(settings=self.settings, callback=self.trigger_callback) self.trigger_callback_called = False self.trigger_instance.daemon = True # Wait that the kalliope trigger is pronounced by the user self.trigger_instance.start() self.next_state() def waiting_for_trigger_callback_thread(self): """ Method to print in debug that the main process is waiting for a trigger detection """ logger.debug("[Order] Entering state: %s" % self.state) if self.settings.options.deaf: # the user asked to deaf inside the deaf neuron Utils.print_info("Kalliope is deaf") self.trigger_instance.pause() else: Utils.print_info("Waiting for trigger detection") # this loop is used to keep the main thread alive while not self.trigger_callback_called: sleep(0.1) # if here, then the trigger has been called HookManager.on_triggered() self.next_state() def waiting_for_order_listener_callback_thread(self): """ Method to print in debug that the main process is waiting for an order to analyse """ logger.debug("[Order] Entering state: %s" % self.state) # this loop is used to keep the main thread alive while not self.order_listener_callback_called: sleep(0.1) # TODO on end listening here self.next_state() def trigger_callback(self): """ we have detected the hotword, we can now pause the Trigger for a while The user can speak out loud his order during this time. """ logger.debug("[Order] Trigger callback called, switching to the next state") self.trigger_callback_called = True def stop_trigger_process(self): """ The trigger has been awaken, we don't needed it anymore :return: """ logger.debug("[Order] Entering state: %s" % self.state) self.trigger_instance.stop() self.next_state() def start_order_listener_thread(self): """ Start the STT engine thread """ logger.debug("[Order] Entering state: %s" % self.state) HookManager.on_start_listening() # start listening for an order self.order_listener_callback_called = False self.order_listener = OrderListener(callback=self.order_listener_callback) self.order_listener.daemon = True self.order_listener.start() self.next_state() def order_listener_callback(self, order): """ Receive an order, try to retrieve it in the brain.yml to launch to attached plugins :param order: the sentence received :type order: str """ logger.debug("[Order] Order listener callback called. Order to process: %s" % order) HookManager.on_stop_listening() self.order_to_process = order self.order_listener_callback_called = True # save in kalliope memory the last order Cortex.save('kalliope_last_order', order) def analysing_order_thread(self): """ Start the order analyser with the caught order to process """ if self.order_to_process is None or self.order_to_process == "": logger.debug("[Order] No audio caught from analysing_order_thread") HookManager.on_stt_error() else: logger.debug("[Order] order in analysing_order_thread %s" % self.order_to_process) SynapseLauncher.run_matching_synapse_from_order(self.order_to_process, self.brain, self.settings, is_api_call=False) if self.skip_trigger: self.start_order_listener() else: self.start_trigger() def on_notification_received(self, notification=None, payload=None): logger.debug("[Order] received notification, notification: %s, payload: %s" % (notification, payload)) if notification == "skip_trigger": if "status" in payload: if payload["status"] == "True": logger.debug("[Order] switch signals to True") self.skip_trigger = True if payload["status"] == "False": logger.debug("[Order] switch signals to False") self.skip_trigger = False
class Order(SignalModule, Thread): states = [ 'init', 'starting_trigger', 'unpausing_trigger', 'waiting_for_trigger_callback', 'pausing_trigger', 'start_order_listener', 'waiting_for_order_listener_callback', 'analysing_order' ] def __init__(self): super(SignalModule, self).__init__() Thread.__init__(self, name=Order) Utils.print_info('Starting order signal') # load settings and brain from singleton sl = SettingLoader() self.settings = sl.settings self.brain = BrainLoader().brain # keep in memory the order to process self.order_to_process = None # get the player instance self.player_instance = PlayerLauncher.get_player( settings=self.settings) # save an instance of the trigger self.trigger_instance = None self.trigger_callback_called = False # variable from notifications self.skip_trigger = False # keep the status of the trigger, if true we can skip it in the statue machine self.counter_max_retry = 0 # 0 means disabled # save the current order listener self.order_listener = None self.order_listener_callback_called = False # Initialize the state machine self.machine = Machine(model=self, states=Order.states, initial='init', queued=True) # define transitions self.machine.add_transition('start_trigger', 'init', 'starting_trigger') self.machine.add_transition('unpause_trigger', 'analysing_order', 'unpausing_trigger') self.machine.add_transition('wait_trigger_callback', 'unpausing_trigger', 'waiting_for_trigger_callback') self.machine.add_transition('pause_trigger', 'waiting_for_trigger_callback', 'pausing_trigger') self.machine.add_transition('wait_for_order', 'pausing_trigger', 'waiting_for_order_listener_callback') self.machine.add_transition('analyse_order', 'waiting_for_order_listener_callback', 'analysing_order') self.machine.add_transition('start_order_listener', 'analysing_order', 'start_order_listener') self.machine.add_ordered_transitions() # add method which are called when changing state self.machine.on_enter_starting_trigger('start_trigger_process') self.machine.on_enter_unpausing_trigger('unpausing_trigger_process') self.machine.on_enter_waiting_for_trigger_callback( 'waiting_for_trigger_callback_thread') self.machine.on_enter_pausing_trigger('pause_trigger_process') self.machine.on_enter_start_order_listener( 'start_order_listener_thread') self.machine.on_enter_waiting_for_order_listener_callback( 'waiting_for_order_listener_callback_thread') self.machine.on_enter_analysing_order('analysing_order_thread') def run(self): # run hook on_start self.start_trigger() def start_trigger_process(self): """ This function will start the trigger thread that listen for the hotword """ logger.debug("[Order] Entering state: %s" % self.state) self.trigger_instance = TriggerLauncher.get_trigger( settings=self.settings, callback=self.trigger_callback) self.trigger_callback_called = False self.trigger_instance.daemon = True # Wait that the kalliope trigger is pronounced by the user self.trigger_instance.start() HookManager.on_start() self.next_state() def unpausing_trigger_process(self): """ If the trigger was in pause, this method will unpause it to listen again for the hotword """ logger.debug("Entering state: %s" % self.state) HookManager.on_waiting_for_trigger() self.trigger_instance.unpause() self.trigger_callback_called = False self.next_state() #self.waiting_for_trigger_callback_thread() def waiting_for_trigger_callback_thread(self): """ Method to print in debug that the main process is waiting for a trigger detection """ logger.debug("[Order] Entering state: %s" % self.state) if self.settings.options.deaf: # the user asked to deaf inside the deaf neuron Utils.print_info("Kalliope is deaf") self.trigger_instance.pause() else: Utils.print_info("Waiting for trigger detection") # this loop is used to keep the main thread alive while not self.trigger_callback_called: sleep(0.1) # if here, then the trigger has been called HookManager.on_triggered() self.next_state() def waiting_for_order_listener_callback_thread(self): """ Method to print in debug that the main process is waiting for an order to analyse """ logger.debug("[Order] Entering state: %s" % self.state) # this loop is used to keep the main thread alive while not self.order_listener_callback_called: sleep(0.1) # TODO on end listening here self.next_state() def trigger_callback(self): """ we have detected the hotword, we can now pause the Trigger for a while The user can speak out loud his order during this time. """ logger.debug( "[Order] Trigger callback called, switching to the next state") self.trigger_callback_called = True def pause_trigger_process(self): """ The trigger has been awaken, we pause it :return: """ logger.debug("[Order] Entering state: %s" % self.state) self.trigger_instance.pause() self.next_state() def start_order_listener_thread(self): """ Start the STT engine thread """ logger.debug("[Order] Entering state: %s" % self.state) # start listening for an order HookManager.on_start_listening() self.order_listener_callback_called = False self.order_listener = OrderListener( callback=self.order_listener_callback) self.order_listener.daemon = True self.order_listener.start() self.next_state() def order_listener_callback(self, order): """ Receive an order, try to retrieve it in the brain.yml to launch to attached plugins :param order: the sentence received :type order: str """ logger.debug( "[Order] Order listener callback called. Order to process: %s" % order) HookManager.on_stop_listening() self.order_to_process = order self.order_listener_callback_called = True # save in kalliope memory the last order Cortex.save('kalliope_last_order', order) def analysing_order_thread(self): """ Start the order analyser with the caught order to process """ if self.order_to_process is None or self.order_to_process == "": logger.debug("[Order] No audio caught from analysing_order_thread") HookManager.on_stt_error() else: logger.debug("[Order] order in analysing_order_thread %s" % self.order_to_process) SynapseLauncher.run_matching_synapse_from_order( self.order_to_process, self.brain, self.settings, is_api_call=False) if self.skip_trigger: self.start_order_listener() else: self.unpause_trigger() def on_notification_received(self, notification=None, payload=None): logger.debug( "[Order] received notification, notification: %s, payload: %s" % (notification, payload)) # skip_trigger: change the trigger status if notification == "skip_trigger": self.switch_trigger(payload) if notification == "skip_trigger_max_retry": self.set_counter_max_retry(payload) if notification == "skip_trigger_decrease_max_retry": self.decrease_max_retry() def set_counter_max_retry(self, payload): """ set a 'counter_max_retry' for max retry before switching automatically the skip_trigger flag to False :param payload: payload that contains the max_retry counter value to set """ if "max_retry" in payload: if payload["max_retry"] > 0: self.counter_max_retry = payload["max_retry"] logger.debug("[Order] max_retry set to %s" % self.counter_max_retry) def decrease_max_retry(self): """ will decrease the current value of 'counter_max_retry' if the current is > 0 If the new value == 0, then the skip_trigger flag is automatically switched to False """ logger.debug("[Order] current max_retry: %s" % self.counter_max_retry) if self.counter_max_retry > 0: self.counter_max_retry = self.counter_max_retry - 1 logger.debug("[Order] new max_retry value after decrease: %s" % self.counter_max_retry) if self.counter_max_retry == 0: logger.debug( "[Order] max_retry reached '0'. Set skip_trigger to False") # the counter raised 0, we can stop to skip the trigger self.skip_trigger = False else: logger.debug( "[Order] cannot decrease max_retry because current value is <= 0" ) def switch_trigger(self, payload): """ switch the skip_trigger flag :param payload: payload dict that contains the new status of the skip_trigger flag """ if "status" in payload: status = Utils.str_to_bool(payload["status"]) if status: logger.debug("[Order] switch signals to True") self.skip_trigger = True else: logger.debug("[Order] switch signals to False") self.skip_trigger = False
class Order(Thread): states = ['init', 'starting_trigger', 'playing_ready_sound', 'waiting_for_trigger_callback', 'stopping_trigger', 'playing_wake_up_answer', 'start_order_listener', 'waiting_for_order_listener_callback', 'analysing_order'] def __init__(self): super(Order, self).__init__() Utils.print_info('Starting voice order manager') # load settings and brain from singleton sl = SettingLoader() self.settings = sl.settings self.brain = BrainLoader().get_brain() # keep in memory the order to process self.order_to_process = None # get the player instance self.player_instance = PlayerLauncher.get_player(settings=self.settings) # save an instance of the trigger self.trigger_instance = None self.trigger_callback_called = False self.is_trigger_muted = False # save the current order listener self.order_listener = None self.order_listener_callback_called = False # boolean used to know id we played the on ready notification at least one time self.on_ready_notification_played_once = False # rpi setting for led and mute button self.init_rpi_utils() # Initialize the state machine self.machine = Machine(model=self, states=Order.states, initial='init', queued=True) # define transitions self.machine.add_transition('start_trigger', ['init', 'analysing_order'], 'starting_trigger') self.machine.add_transition('play_ready_sound', 'starting_trigger', 'playing_ready_sound') self.machine.add_transition('wait_trigger_callback', 'playing_ready_sound', 'waiting_for_trigger_callback') self.machine.add_transition('stop_trigger', 'waiting_for_trigger_callback', 'stopping_trigger') self.machine.add_transition('play_wake_up_answer', 'stopping_trigger', 'playing_wake_up_answer') self.machine.add_transition('wait_for_order', 'playing_wake_up_answer', 'waiting_for_order_listener_callback') self.machine.add_transition('analyse_order', 'playing_wake_up_answer', 'analysing_order') self.machine.add_ordered_transitions() # add method which are called when changing state self.machine.on_enter_starting_trigger('start_trigger_process') self.machine.on_enter_playing_ready_sound('play_ready_sound_process') self.machine.on_enter_waiting_for_trigger_callback('waiting_for_trigger_callback_thread') self.machine.on_enter_playing_wake_up_answer('play_wake_up_answer_thread') self.machine.on_enter_stopping_trigger('stop_trigger_process') self.machine.on_enter_start_order_listener('start_order_listener_thread') self.machine.on_enter_waiting_for_order_listener_callback('waiting_for_order_listener_callback_thread') self.machine.on_enter_analysing_order('analysing_order_thread') def run(self): self.start_trigger() def start_trigger_process(self): """ This function will start the trigger thread that listen for the hotword """ logger.debug("[MainController] Entering state: %s" % self.state) self.trigger_instance = TriggerLauncher.get_trigger(settings=self.settings, callback=self.trigger_callback) self.trigger_callback_called = False self.trigger_instance.daemon = True # Wait that the kalliope trigger is pronounced by the user self.trigger_instance.start() self.next_state() def play_ready_sound_process(self): """ Play a sound when Kalliope is ready to be awaken at the first start """ logger.debug("[MainController] Entering state: %s" % self.state) if (not self.on_ready_notification_played_once and self.settings.play_on_ready_notification == "once") or \ self.settings.play_on_ready_notification == "always": # we remember that we played the notification one time self.on_ready_notification_played_once = True # here we tell the user that we are listening if self.settings.on_ready_answers is not None: Say(message=self.settings.on_ready_answers) elif self.settings.on_ready_sounds is not None: random_sound_to_play = self._get_random_sound(self.settings.on_ready_sounds) self.player_instance.play(random_sound_to_play) self.next_state() def waiting_for_trigger_callback_thread(self): """ Method to print in debug that the main process is waiting for a trigger detection """ logger.debug("[MainController] Entering state: %s" % self.state) if self.is_trigger_muted: # the user asked to mute inside the mute neuron Utils.print_info("Kalliope is muted") self.trigger_instance.pause() else: Utils.print_info("Waiting for trigger detection") # this loop is used to keep the main thread alive while not self.trigger_callback_called: sleep(0.1) self.next_state() def waiting_for_order_listener_callback_thread(self): """ Method to print in debug that the main process is waiting for an order to analyse """ logger.debug("[MainController] Entering state: %s" % self.state) # this loop is used to keep the main thread alive while not self.order_listener_callback_called: sleep(0.1) if self.settings.rpi_settings: if self.settings.rpi_settings.pin_led_listening: RpiUtils.switch_pin_to_off(self.settings.rpi_settings.pin_led_listening) self.next_state() def trigger_callback(self): """ we have detected the hotword, we can now pause the Trigger for a while The user can speak out loud his order during this time. """ logger.debug("[MainController] Trigger callback called, switching to the next state") self.trigger_callback_called = True def stop_trigger_process(self): """ The trigger has been awaken, we don't needed it anymore :return: """ logger.debug("[MainController] Entering state: %s" % self.state) self.trigger_instance.stop() self.next_state() def start_order_listener_thread(self): """ Start the STT engine thread """ logger.debug("[MainController] Entering state: %s" % self.state) # start listening for an order self.order_listener_callback_called = False self.order_listener = OrderListener(callback=self.order_listener_callback) self.order_listener.daemon = True self.order_listener.start() self.next_state() def play_wake_up_answer_thread(self): """ Play a sound or make Kalliope say something to notify the user that she has been awaken and now waiting for order """ logger.debug("[MainController] Entering state: %s" % self.state) # if random wake answer sentence are present, we play this if self.settings.random_wake_up_answers is not None: Say(message=self.settings.random_wake_up_answers) else: random_sound_to_play = self._get_random_sound(self.settings.random_wake_up_sounds) self.player_instance.play(random_sound_to_play) self.next_state() def order_listener_callback(self, order): """ Receive an order, try to retrieve it in the brain.yml to launch to attached plugins :param order: the sentence received :type order: str """ logger.debug("[MainController] Order listener callback called. Order to process: %s" % order) self.order_to_process = order self.order_listener_callback_called = True def analysing_order_thread(self): """ Start the order analyser with the caught order to process """ logger.debug("[MainController] order in analysing_order_thread %s" % self.order_to_process) SynapseLauncher.run_matching_synapse_from_order(self.order_to_process, self.brain, self.settings, is_api_call=False) # return to the state "unpausing_trigger" self.start_trigger() @staticmethod def _get_random_sound(random_wake_up_sounds): """ Return a path of a sound to play If the path is absolute, test if file exist If the path is relative, we check if the file exist in the sound folder :param random_wake_up_sounds: List of wake_up sounds :return: path of a sound to play """ # take first randomly a path random_path = random.choice(random_wake_up_sounds) logger.debug("[MainController] Selected sound: %s" % random_path) return Utils.get_real_file_path(random_path) def set_mute_status(self, muted=False): """ Define is the trigger is listening or not :param muted: Boolean. If true, kalliope is muted """ logger.debug("[MainController] Mute button pressed. Switch trigger process to muted: %s" % muted) if muted: self.trigger_instance.pause() self.is_trigger_muted = True Utils.print_info("Kalliope now muted") else: self.trigger_instance.unpause() self.is_trigger_muted = False Utils.print_info("Kalliope now listening for trigger detection") def get_mute_status(self): """ return the current state of the trigger (muted or not) :return: Boolean """ return self.is_trigger_muted def init_rpi_utils(self): """ Start listening on GPIO if defined in settings """ if self.settings.rpi_settings: # the user set GPIO pin, we need to instantiate the RpiUtils class in order to setup GPIO rpi_utils = RpiUtils(self.settings.rpi_settings, self.set_mute_status) if self.settings.rpi_settings.pin_mute_button: # start the listening for button pressed thread only if the user set a pin rpi_utils.daemon = True rpi_utils.start() # switch high the start led, as kalliope is started. Only if the setting exist if self.settings.rpi_settings: if self.settings.rpi_settings.pin_led_started: logger.debug("[MainController] Switching pin_led_started to ON") RpiUtils.switch_pin_to_on(self.settings.rpi_settings.pin_led_started)
class Order(Thread): states = ['init', 'starting_trigger', 'waiting_for_trigger_callback', 'stopping_trigger', 'start_order_listener', 'waiting_for_order_listener_callback', 'analysing_order'] def __init__(self): super(Order, self).__init__() Utils.print_info('Starting order signal') # load settings and brain from singleton sl = SettingLoader() self.settings = sl.settings self.brain = BrainLoader().brain # keep in memory the order to process self.order_to_process = None # get the player instance self.player_instance = PlayerLauncher.get_player(settings=self.settings) # save an instance of the trigger self.trigger_instance = None self.trigger_callback_called = False self.is_trigger_muted = False # If intelora is asked to start muted if self.settings.start_options['muted'] is True: self.is_trigger_muted = True # save the current order listener self.order_listener = None self.order_listener_callback_called = False # Initialize the state machine self.machine = Machine(model=self, states=Order.states, initial='init', queued=True) # define transitions self.machine.add_transition('start_trigger', ['init', 'analysing_order'], 'starting_trigger') self.machine.add_transition('wait_trigger_callback', 'starting_trigger', 'waiting_for_trigger_callback') self.machine.add_transition('stop_trigger', 'waiting_for_trigger_callback', 'stopping_trigger') self.machine.add_transition('wait_for_order', 'stopping_trigger', 'waiting_for_order_listener_callback') self.machine.add_transition('analyse_order', 'waiting_for_order_listener_callback', 'analysing_order') self.machine.add_ordered_transitions() # add method which are called when changing state self.machine.on_enter_starting_trigger('start_trigger_process') self.machine.on_enter_waiting_for_trigger_callback('waiting_for_trigger_callback_thread') self.machine.on_enter_stopping_trigger('stop_trigger_process') self.machine.on_enter_start_order_listener('start_order_listener_thread') self.machine.on_enter_waiting_for_order_listener_callback('waiting_for_order_listener_callback_thread') self.machine.on_enter_analysing_order('analysing_order_thread') def run(self): # run hook on_start HookManager.on_start() self.start_trigger() def start_trigger_process(self): """ This function will start the trigger thread that listen for the hotword """ logger.debug("[MainController] Entering state: %s" % self.state) HookManager.on_waiting_for_trigger() self.trigger_instance = TriggerLauncher.get_trigger(settings=self.settings, callback=self.trigger_callback) self.trigger_callback_called = False self.trigger_instance.daemon = True # Wait that the intelora trigger is pronounced by the user self.trigger_instance.start() self.next_state() def waiting_for_trigger_callback_thread(self): """ Method to print in debug that the main process is waiting for a trigger detection """ logger.debug("[MainController] Entering state: %s" % self.state) if self.is_trigger_muted: # the user asked to mute inside the mute neuron Utils.print_info("Intelora is muted") self.trigger_instance.pause() else: Utils.print_info("Waiting for trigger detection") # this loop is used to keep the main thread alive while not self.trigger_callback_called: sleep(0.1) # if here, then the trigger has been called HookManager.on_triggered() self.next_state() def waiting_for_order_listener_callback_thread(self): """ Method to print in debug that the main process is waiting for an order to analyse """ logger.debug("[MainController] Entering state: %s" % self.state) # this loop is used to keep the main thread alive while not self.order_listener_callback_called: sleep(0.1) # TODO on end listening here self.next_state() def trigger_callback(self): """ we have detected the hotword, we can now pause the Trigger for a while The user can speak out loud his order during this time. """ logger.debug("[MainController] Trigger callback called, switching to the next state") self.trigger_callback_called = True def stop_trigger_process(self): """ The trigger has been awaken, we don't needed it anymore :return: """ logger.debug("[MainController] Entering state: %s" % self.state) self.trigger_instance.stop() self.next_state() def start_order_listener_thread(self): """ Start the STT engine thread """ logger.debug("[MainController] Entering state: %s" % self.state) HookManager.on_start_listening() # start listening for an order self.order_listener_callback_called = False self.order_listener = OrderListener(callback=self.order_listener_callback) self.order_listener.daemon = True self.order_listener.start() self.next_state() def order_listener_callback(self, order): """ Receive an order, try to retrieve it in the brain.yml to launch to attached plugins :param order: the sentence received :type order: str """ logger.debug("[MainController] Order listener callback called. Order to process: %s" % order) HookManager.on_stop_listening() self.order_to_process = order self.order_listener_callback_called = True def analysing_order_thread(self): """ Start the order analyser with the caught order to process """ logger.debug("[MainController] order in analysing_order_thread %s" % self.order_to_process) SynapseLauncher.run_matching_synapse_from_order(self.order_to_process, self.brain, self.settings, is_api_call=False) # return to the state "unpausing_trigger" self.start_trigger() def set_mute_status(self, muted=False): """ Define is the trigger is listening or not :param muted: Boolean. If true, intelora is muted """ logger.debug("[MainController] Mute button pressed. Switch trigger process to muted: %s" % muted) if muted: self.trigger_instance.pause() self.is_trigger_muted = True Utils.print_info("Intelora now muted") HookManager.on_mute() else: self.trigger_instance.unpause() self.is_trigger_muted = False Utils.print_info("Intelora now listening for trigger detection") HookManager.on_unmute() def get_mute_status(self): """ return the current state of the trigger (muted or not) :return: Boolean """ return self.is_trigger_muted
class Clock(object): states = ['work', 'relax', 'shop', 'sleep'] def __init__(self, model): self.dayNumber = -1 self.model = model self.machine = Machine(model=self, states=Clock.states, initial='sleep') self.machine.add_ordered_transitions() self.machine.on_enter_work('workHandler') self.machine.on_enter_relax('relaxHandler') self.machine.on_enter_shop('shopHandler') self.machine.on_enter_sleep('sleepHandler') def next_day(self): self.model.week.next_state() self.model.calendar.next_day() d.shufflePeople() self.dayNumber += 1 def workHandler(self): self.next_day() religionList = d.getReligions() unitList = d.getUnit() businessList = d.getBusinesses() peopleList = d.getPeople() bossList = d.getBosses() localityList = d.getLocality() if self.model.week.state == 'Friday': self.model.salaryPayer.paySalaries() if self.model.week.state == 'Sunday': for person in peopleList: person.churchHandler() for religion in religionList: for business in religion.getBusinesses(): for priest in business.getPriestJobs(): priest.service() #workday if self.model.week.state != 'Sunday': for business in businessList: business.workHandler() for person in peopleList: person.workHandler() person.bossmaker() for boss in bossList: i_build = self.model.startupAI.whatToBuild(boss) self.model.builder.buildChain(boss.businesses[0], i_build) def relaxHandler(self): bossList = d.getBosses() businessList = d.getBusinesses() peopleList = d.getPeople() if self.model.week.state != 'Sunday': for boss in bossList: for business in boss.getBusinesses(): self.model.productionAI.setProduction(business) for job in business.craftingJobs: self.model.jobPoster.managePositions(job) for business in businessList: business.restHandler() for person in peopleList: person.restHandler() def shopHandler(self): businessList = d.getBusinesses() peopleList = d.getPeople() if self.model.week.state != 'Sunday': for business in businessList: business.shopHandler() for person in peopleList: person.shopHandler() def sleepHandler(self): peopleList = d.getPeople() businessList = d.getBusinesses() for person in peopleList: person.sleepHandler() if self.model.week.state != 'Sunday': for business in businessList: business.sleepHandler() self.model.out("\nThe day ends.\n") def toString(self): return ("Today is " + self.model.week.state + ", " + str(self.model.calendar.dayOfMonth) + " of " + self.model.calendar.state + " in the year " + str(self.model.calendar.year) + "." + " At this time of day people generally " + self.state + ".") def runDay(self): self.next_state() self.next_state() self.next_state() self.next_state() def getDayNum(self): return self.dayNumber
class Order(SignalModule, Thread): states = [ 'init', 'starting_trigger', 'waiting_for_trigger_callback', 'stopping_trigger', 'start_order_listener', 'waiting_for_order_listener_callback', 'analysing_order' ] def __init__(self): super(SignalModule, self).__init__() Thread.__init__(self, name=Order) Utils.print_info('Starting order signal') # load settings and brain from singleton sl = SettingLoader() self.settings = sl.settings self.brain = BrainLoader().brain # keep in memory the order to process self.order_to_process = None # get the player instance self.player_instance = PlayerLauncher.get_player( settings=self.settings) # save an instance of the trigger self.trigger_instance = None self.trigger_callback_called = False self.skip_trigger = False # keep the status of the trigger, if true we can skip it in the statue machine # save the current order listener self.order_listener = None self.order_listener_callback_called = False # Initialize the state machine self.machine = Machine(model=self, states=Order.states, initial='init', queued=True) # define transitions self.machine.add_transition('start_trigger', ['init', 'analysing_order'], 'starting_trigger') self.machine.add_transition('wait_trigger_callback', 'starting_trigger', 'waiting_for_trigger_callback') self.machine.add_transition('stop_trigger', 'waiting_for_trigger_callback', 'stopping_trigger') self.machine.add_transition('wait_for_order', 'stopping_trigger', 'waiting_for_order_listener_callback') self.machine.add_transition('analyse_order', 'waiting_for_order_listener_callback', 'analysing_order') self.machine.add_transition('start_order_listener', 'analysing_order', 'start_order_listener') self.machine.add_ordered_transitions() # add method which are called when changing state self.machine.on_enter_starting_trigger('start_trigger_process') self.machine.on_enter_waiting_for_trigger_callback( 'waiting_for_trigger_callback_thread') self.machine.on_enter_stopping_trigger('stop_trigger_process') self.machine.on_enter_start_order_listener( 'start_order_listener_thread') self.machine.on_enter_waiting_for_order_listener_callback( 'waiting_for_order_listener_callback_thread') self.machine.on_enter_analysing_order('analysing_order_thread') def run(self): # run hook on_start HookManager.on_start() self.start_trigger() def start_trigger_process(self): """ This function will start the trigger thread that listen for the hotword """ logger.debug("[Order] Entering state: %s" % self.state) HookManager.on_waiting_for_trigger() self.trigger_instance = TriggerLauncher.get_trigger( settings=self.settings, callback=self.trigger_callback) self.trigger_callback_called = False self.trigger_instance.daemon = True # Wait that the kalliope trigger is pronounced by the user self.trigger_instance.start() self.next_state() def waiting_for_trigger_callback_thread(self): """ Method to print in debug that the main process is waiting for a trigger detection """ logger.debug("[Order] Entering state: %s" % self.state) if self.settings.options.deaf: # the user asked to deaf inside the deaf neuron Utils.print_info("Kalliope is deaf") self.trigger_instance.pause() else: Utils.print_info("Waiting for trigger detection") # this loop is used to keep the main thread alive while not self.trigger_callback_called: sleep(0.1) # if here, then the trigger has been called HookManager.on_triggered() self.next_state() def waiting_for_order_listener_callback_thread(self): """ Method to print in debug that the main process is waiting for an order to analyse """ logger.debug("[Order] Entering state: %s" % self.state) # this loop is used to keep the main thread alive while not self.order_listener_callback_called: sleep(0.1) # TODO on end listening here self.next_state() def trigger_callback(self): """ we have detected the hotword, we can now pause the Trigger for a while The user can speak out loud his order during this time. """ logger.debug( "[Order] Trigger callback called, switching to the next state") self.trigger_callback_called = True def stop_trigger_process(self): """ The trigger has been awaken, we don't needed it anymore :return: """ logger.debug("[Order] Entering state: %s" % self.state) self.trigger_instance.stop() self.next_state() def start_order_listener_thread(self): """ Start the STT engine thread """ logger.debug("[Order] Entering state: %s" % self.state) HookManager.on_start_listening() # start listening for an order self.order_listener_callback_called = False self.order_listener = OrderListener( callback=self.order_listener_callback) self.order_listener.daemon = True self.order_listener.start() self.next_state() def order_listener_callback(self, order): """ Receive an order, try to retrieve it in the brain.yml to launch to attached plugins :param order: the sentence received :type order: str """ logger.debug( "[Order] Order listener callback called. Order to process: %s" % order) HookManager.on_stop_listening() self.order_to_process = order self.order_listener_callback_called = True # save in kalliope memory the last order Cortex.save('kalliope_last_order', order) def analysing_order_thread(self): """ Start the order analyser with the caught order to process """ if self.order_to_process is None or self.order_to_process == "": logger.debug("[Order] No audio caught from analysing_order_thread") HookManager.on_stt_error() else: logger.debug("[Order] order in analysing_order_thread %s" % self.order_to_process) SynapseLauncher.run_matching_synapse_from_order( self.order_to_process, self.brain, self.settings, is_api_call=False) if self.skip_trigger: self.start_order_listener() else: self.start_trigger() def on_notification_received(self, notification=None, payload=None): logger.debug( "[Order] received notification, notification: %s, payload: %s" % (notification, payload)) if notification == "skip_trigger": if "status" in payload: if payload["status"] == "True": logger.debug("[Order] switch signals to True") self.skip_trigger = True if payload["status"] == "False": logger.debug("[Order] switch signals to False") self.skip_trigger = False
def __init__(self, game): self.game = game m = Machine(self, states=GAME_STATES, initial='turn_start' ) #Note! on_enter won't fire for initial state first time! m.add_ordered_transitions()
from transitions import Machine from .models import Pizza states = [{ 'name': 'start' }, { 'name': 'size' }, { 'name': 'payment_type' }, { 'name': 'confirmation' }] machine = Machine(states=states, initial='start') machine.add_ordered_transitions() TELEGRAM_URL = 'https://api.telegram.org/bot{TOKEN}/' class Phrases: def get_size(self): return "Какую вы хотите пиццу? Большую или маленькую?" def get_payment(self): return 'Как вы будете платить?' def get_confirm(self, size, payment_type): return 'Вы хотите {} пиццу, оплата - {}?'.format( size.lower(), payment_type.lower())