From a1fdae3415e9d3006e6a4348468058232bc13db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=85ke=20Forslund?= Date: Sat, 28 Mar 2020 08:29:24 +0100 Subject: [PATCH] Add support for watchdog in skills and speech client If no watchdog is provided a dummy function will be called --- mycroft/client/speech/__main__.py | 4 ++-- mycroft/client/speech/listener.py | 9 +++++++-- mycroft/client/speech/mic.py | 5 ++++- mycroft/skills/__main__.py | 8 ++++---- mycroft/skills/skill_manager.py | 6 +++++- 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/mycroft/client/speech/__main__.py b/mycroft/client/speech/__main__.py index c6c62b82e3..08a8517a50 100644 --- a/mycroft/client/speech/__main__.py +++ b/mycroft/client/speech/__main__.py @@ -207,7 +207,7 @@ def connect_bus_events(bus): bus.on('message', create_echo_function('VOICE')) -def main(ready_hook=on_ready, error_hook=on_error): +def main(ready_hook=on_ready, error_hook=on_error, watchdog=lambda: None): global bus global loop global config @@ -219,7 +219,7 @@ def main(ready_hook=on_ready, error_hook=on_error): config = Configuration.get() # Register handlers on internal RecognizerLoop bus - loop = RecognizerLoop() + loop = RecognizerLoop(watchdog) connect_loop_events(loop) connect_bus_events(bus) create_daemon(bus.run_forever) diff --git a/mycroft/client/speech/listener.py b/mycroft/client/speech/listener.py index 3fbe7292f8..7251c5e8e9 100644 --- a/mycroft/client/speech/listener.py +++ b/mycroft/client/speech/listener.py @@ -275,10 +275,15 @@ class RecognizerLoop(BaseEventEmitter): """ EventEmitter loop running speech recognition. Local wake word recognizer and remote general speech recognition. + + Arguments: + watchdog: (callable) function to call periodically indicating + operational status. """ - def __init__(self): + def __init__(self, watchdog=None): super(RecognizerLoop, self).__init__() + self._watchdog = watchdog self.mute_calls = 0 self._load_config() @@ -305,7 +310,7 @@ class RecognizerLoop(BaseEventEmitter): # TODO - localization self.wakeup_recognizer = self.create_wakeup_recognizer() self.responsive_recognizer = ResponsiveRecognizer( - self.wakeword_recognizer) + self.wakeword_recognizer, self._watchdog) self.state = RecognizerLoopState() def create_wake_word_recognizer(self): diff --git a/mycroft/client/speech/mic.py b/mycroft/client/speech/mic.py index ebcae40ef2..4198c9e492 100644 --- a/mycroft/client/speech/mic.py +++ b/mycroft/client/speech/mic.py @@ -336,7 +336,8 @@ class ResponsiveRecognizer(speech_recognition.Recognizer): # Time between pocketsphinx checks for the wake word SEC_BETWEEN_WW_CHECKS = 0.2 - def __init__(self, wake_word_recognizer): + def __init__(self, wake_word_recognizer, watchdog=None): + self._watchdog = watchdog or (lambda: None) # Default to dummy func self.config = Configuration.get() listener_config = self.config.get('listener') self.upload_url = listener_config['wake_word_upload']['url'] @@ -474,6 +475,7 @@ class ResponsiveRecognizer(speech_recognition.Recognizer): # Periodically write the energy level to the mic level file. if num_chunks % 10 == 0: + self._watchdog() self.write_mic_level(energy, source) return byte_data @@ -654,6 +656,7 @@ class ResponsiveRecognizer(speech_recognition.Recognizer): # Periodically output energy level stats. This can be used to # visualize the microphone input, e.g. a needle on a meter. if mic_write_counter % 3: + self._watchdog() self.write_mic_level(energy, source) mic_write_counter += 1 diff --git a/mycroft/skills/__main__.py b/mycroft/skills/__main__.py index b64595d871..6f47194845 100644 --- a/mycroft/skills/__main__.py +++ b/mycroft/skills/__main__.py @@ -181,7 +181,7 @@ def on_error(e='Unknown'): LOG.info('Skill service failed to launch ({})'.format(repr(e))) -def main(ready_hook=on_ready, error_hook=on_error): +def main(ready_hook=on_ready, error_hook=on_error, watchdog=None): reset_sigint_handler() # Create PID file, prevent multiple instances of this service mycroft.lock.Lock('skills') @@ -193,7 +193,7 @@ def main(ready_hook=on_ready, error_hook=on_error): bus = _start_message_bus_client() _register_intent_services(bus) event_scheduler = EventScheduler(bus) - skill_manager = _initialize_skill_manager(bus) + skill_manager = _initialize_skill_manager(bus, watchdog) _wait_for_internet_connection() @@ -244,14 +244,14 @@ def _register_intent_services(bus): bus.on('intent_failure', FallbackSkill.make_intent_failure_handler(bus)) -def _initialize_skill_manager(bus): +def _initialize_skill_manager(bus, watchdog): """Create a thread that monitors the loaded skills, looking for updates Returns: SkillManager instance or None if it couldn't be initialized """ try: - skill_manager = SkillManager(bus) + skill_manager = SkillManager(bus, watchdog) skill_manager.load_priority() except MsmException: # skill manager couldn't be created, wait for network connection and diff --git a/mycroft/skills/skill_manager.py b/mycroft/skills/skill_manager.py index cc166b0037..5618171e5e 100644 --- a/mycroft/skills/skill_manager.py +++ b/mycroft/skills/skill_manager.py @@ -110,14 +110,17 @@ def _shutdown_skill(instance): class SkillManager(Thread): _msm = None - def __init__(self, bus): + def __init__(self, bus, watchdog=None): """Constructor Arguments: bus (event emitter): Mycroft messagebus connection + watchdog (callable): optional watchdog function """ super(SkillManager, self).__init__() self.bus = bus + # Set watchdog to argument or function returning None + self._watchdog = watchdog or (lambda: None) self._stop_event = Event() self._connected_event = Event() self.config = Configuration.get() @@ -243,6 +246,7 @@ class SkillManager(Thread): self.skill_updater.post_manifest() self.upload_queue.send() + self._watchdog() sleep(2) # Pause briefly before beginning next scan except Exception: LOG.exception('Something really unexpected has occured '