Add support for watchdog in skills and speech client

If no watchdog is provided a dummy function will be called
pull/2601/head
Åke Forslund 2020-03-28 08:29:24 +01:00
parent 09b1deb511
commit a1fdae3415
5 changed files with 22 additions and 10 deletions

View File

@ -207,7 +207,7 @@ def connect_bus_events(bus):
bus.on('message', create_echo_function('VOICE')) 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 bus
global loop global loop
global config global config
@ -219,7 +219,7 @@ def main(ready_hook=on_ready, error_hook=on_error):
config = Configuration.get() config = Configuration.get()
# Register handlers on internal RecognizerLoop bus # Register handlers on internal RecognizerLoop bus
loop = RecognizerLoop() loop = RecognizerLoop(watchdog)
connect_loop_events(loop) connect_loop_events(loop)
connect_bus_events(bus) connect_bus_events(bus)
create_daemon(bus.run_forever) create_daemon(bus.run_forever)

View File

@ -275,10 +275,15 @@ class RecognizerLoop(BaseEventEmitter):
""" EventEmitter loop running speech recognition. """ EventEmitter loop running speech recognition.
Local wake word recognizer and remote general 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__() super(RecognizerLoop, self).__init__()
self._watchdog = watchdog
self.mute_calls = 0 self.mute_calls = 0
self._load_config() self._load_config()
@ -305,7 +310,7 @@ class RecognizerLoop(BaseEventEmitter):
# TODO - localization # TODO - localization
self.wakeup_recognizer = self.create_wakeup_recognizer() self.wakeup_recognizer = self.create_wakeup_recognizer()
self.responsive_recognizer = ResponsiveRecognizer( self.responsive_recognizer = ResponsiveRecognizer(
self.wakeword_recognizer) self.wakeword_recognizer, self._watchdog)
self.state = RecognizerLoopState() self.state = RecognizerLoopState()
def create_wake_word_recognizer(self): def create_wake_word_recognizer(self):

View File

@ -336,7 +336,8 @@ class ResponsiveRecognizer(speech_recognition.Recognizer):
# Time between pocketsphinx checks for the wake word # Time between pocketsphinx checks for the wake word
SEC_BETWEEN_WW_CHECKS = 0.2 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() self.config = Configuration.get()
listener_config = self.config.get('listener') listener_config = self.config.get('listener')
self.upload_url = listener_config['wake_word_upload']['url'] 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. # Periodically write the energy level to the mic level file.
if num_chunks % 10 == 0: if num_chunks % 10 == 0:
self._watchdog()
self.write_mic_level(energy, source) self.write_mic_level(energy, source)
return byte_data return byte_data
@ -654,6 +656,7 @@ class ResponsiveRecognizer(speech_recognition.Recognizer):
# Periodically output energy level stats. This can be used to # Periodically output energy level stats. This can be used to
# visualize the microphone input, e.g. a needle on a meter. # visualize the microphone input, e.g. a needle on a meter.
if mic_write_counter % 3: if mic_write_counter % 3:
self._watchdog()
self.write_mic_level(energy, source) self.write_mic_level(energy, source)
mic_write_counter += 1 mic_write_counter += 1

View File

@ -181,7 +181,7 @@ def on_error(e='Unknown'):
LOG.info('Skill service failed to launch ({})'.format(repr(e))) 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() reset_sigint_handler()
# Create PID file, prevent multiple instances of this service # Create PID file, prevent multiple instances of this service
mycroft.lock.Lock('skills') mycroft.lock.Lock('skills')
@ -193,7 +193,7 @@ def main(ready_hook=on_ready, error_hook=on_error):
bus = _start_message_bus_client() bus = _start_message_bus_client()
_register_intent_services(bus) _register_intent_services(bus)
event_scheduler = EventScheduler(bus) event_scheduler = EventScheduler(bus)
skill_manager = _initialize_skill_manager(bus) skill_manager = _initialize_skill_manager(bus, watchdog)
_wait_for_internet_connection() _wait_for_internet_connection()
@ -244,14 +244,14 @@ def _register_intent_services(bus):
bus.on('intent_failure', FallbackSkill.make_intent_failure_handler(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 """Create a thread that monitors the loaded skills, looking for updates
Returns: Returns:
SkillManager instance or None if it couldn't be initialized SkillManager instance or None if it couldn't be initialized
""" """
try: try:
skill_manager = SkillManager(bus) skill_manager = SkillManager(bus, watchdog)
skill_manager.load_priority() skill_manager.load_priority()
except MsmException: except MsmException:
# skill manager couldn't be created, wait for network connection and # skill manager couldn't be created, wait for network connection and

View File

@ -110,14 +110,17 @@ def _shutdown_skill(instance):
class SkillManager(Thread): class SkillManager(Thread):
_msm = None _msm = None
def __init__(self, bus): def __init__(self, bus, watchdog=None):
"""Constructor """Constructor
Arguments: Arguments:
bus (event emitter): Mycroft messagebus connection bus (event emitter): Mycroft messagebus connection
watchdog (callable): optional watchdog function
""" """
super(SkillManager, self).__init__() super(SkillManager, self).__init__()
self.bus = bus self.bus = bus
# Set watchdog to argument or function returning None
self._watchdog = watchdog or (lambda: None)
self._stop_event = Event() self._stop_event = Event()
self._connected_event = Event() self._connected_event = Event()
self.config = Configuration.get() self.config = Configuration.get()
@ -243,6 +246,7 @@ class SkillManager(Thread):
self.skill_updater.post_manifest() self.skill_updater.post_manifest()
self.upload_queue.send() self.upload_queue.send()
self._watchdog()
sleep(2) # Pause briefly before beginning next scan sleep(2) # Pause briefly before beginning next scan
except Exception: except Exception:
LOG.exception('Something really unexpected has occured ' LOG.exception('Something really unexpected has occured '