예제 #1
0
    def handle_converse_request(self, message):
        """ Check if the targeted skill id can handle conversation

        If supported, the conversation is invoked.
        """

        skill_id = int(message.data["skill_id"])
        utterances = message.data["utterances"]
        lang = message.data["lang"]

        # loop trough skills list and call converse for skill with skill_id
        for skill in self.loaded_skills:
            if self.loaded_skills[skill]["id"] == skill_id:
                try:
                    instance = self.loaded_skills[skill]["instance"]
                except BaseException:
                    LOG.error("converse requested but skill not loaded")
                    self.ws.emit(Message("skill.converse.response", {
                        "skill_id": 0, "result": False}))
                    return
                try:
                    result = instance.converse(utterances, lang)
                    self.ws.emit(Message("skill.converse.response", {
                        "skill_id": skill_id, "result": result}))
                    return
                except BaseException:
                    LOG.error(
                        "Converse method malformed for skill " + str(skill_id))
        self.ws.emit(Message("skill.converse.response",
                             {"skill_id": 0, "result": False}))
예제 #2
0
 def send(self, *args, **kwargs):
     """ Send to all registered GUIs. """
     for gui in self.GUIs.values():
         if gui.socket:
             gui.socket.send(*args, **kwargs)
         else:
             LOG.error('GUI connection {} has no socket!'.format(gui))
예제 #3
0
def play_audio_file(uri: str):
    """ Play an audio file.

    This wraps the other play_* functions, choosing the correct one based on
    the file extension. The function will return directly and play the file
    in the background.

    Arguments:
        uri:    uri to play

    Returns: subprocess.Popen object. None if the format is not supported or
             an error occurs playing the file.

    """
    extension_to_function = {
        '.wav': play_wav,
        '.mp3': play_mp3,
        '.ogg': play_ogg
    }
    _, extension = splitext(uri)
    play_function = extension_to_function.get(extension.lower())
    if play_function:
        return play_function(uri)
    else:
        LOG.error("Could not find a function capable of playing {uri}."
                  " Supported formats are {keys}."
                  .format(uri=uri, keys=list(extension_to_function.keys())))
        return None
예제 #4
0
    def __init__(self, emitter):
        FallbackSkill.__init__(self)
        self.config = ConfigurationManager.get()['padatious']
        intent_cache = expanduser(self.config['intent_cache'])

        try:
            from padatious import IntentContainer
        except ImportError:
            LOG.error('Padatious not installed. Please re-run dev_setup.sh')
            try:
                call(['notify-send', 'Padatious not installed',
                      'Please run build_host_setup and dev_setup again'])
            except OSError:
                pass
            return
        ver = get_distribution('padatious').version
        if ver != PADATIOUS_VERSION:
            LOG.warning('Using Padatious v' + ver + '. Please re-run ' +
                        'dev_setup.sh to install ' + PADATIOUS_VERSION)

        self.container = IntentContainer(intent_cache)

        self.emitter = emitter
        self.emitter.on('padatious:register_intent', self.register_intent)
        self.emitter.on('padatious:register_entity', self.register_entity)
        self.register_fallback(self.handle_fallback, 5)
        self.finished_training_event = Event()

        self.train_delay = self.config['train_delay']
        self.train_time = get_time() + self.train_delay
        self.wait_and_train()
예제 #5
0
    def shutdown(self):
        for s in self.service:
            try:
                LOG.info('shutting down ' + s.name)
                s.shutdown()
            except Exception as e:
                LOG.error('shutdown of ' + s.name + ' failed: ' + repr(e))

        # remove listeners
        self.bus.remove('mycroft.audio.service.play', self._play)
        self.bus.remove('mycroft.audio.service.queue', self._queue)
        self.bus.remove('mycroft.audio.service.pause', self._pause)
        self.bus.remove('mycroft.audio.service.resume', self._resume)
        self.bus.remove('mycroft.audio.service.stop', self._stop)
        self.bus.remove('mycroft.audio.service.next', self._next)
        self.bus.remove('mycroft.audio.service.prev', self._prev)
        self.bus.remove('mycroft.audio.service.track_info', self._track_info)
        self.bus.remove('mycroft.audio.service.seek_forward',
                        self._seek_forward)
        self.bus.remove('mycroft.audio.service.seek_backward',
                        self._seek_backward)
        self.bus.remove('recognizer_loop:audio_output_start',
                        self._lower_volume)
        self.bus.remove('recognizer_loop:record_begin', self._lower_volume)
        self.bus.remove('recognizer_loop:audio_output_end',
                        self._restore_volume)
        self.bus.remove('recognizer_loop:record_end', self._restore_volume)
        self.bus.remove('mycroft.stop', self._stop)
예제 #6
0
def _read_data():
    """ Reads the file in (/tmp/mycroft/ipc/managers/disp_info)
        and returns the the data as python dict
    """
    managerIPCDir = os.path.join(get_ipc_directory(), "managers")

    path = os.path.join(managerIPCDir, "disp_info")
    permission = "r" if os.path.isfile(path) else "w+"

    if permission == "w+" and os.path.isdir(managerIPCDir) is False:
        os.makedirs(managerIPCDir)

    data = {}
    try:
        with open(path, permission) as dispFile:

            if os.stat(str(dispFile.name)).st_size != 0:
                data = json.load(dispFile)

    except Exception as e:
        LOG.error(e)
        os.remove(path)
        _read_data()

    return data
예제 #7
0
    def _poll_skill_settings(self):
        """ If identifier exists for this skill poll to backend to
            request settings and store it if it changes
            TODO: implement as websocket

            Args:
                hashed_meta (int): the hashed identifier
        """
        try:
            if not self._complete_intialization:
                self.initialize_remote_settings()
                if not self._complete_intialization:
                    return  # unable to do remote sync
            else:
                original = hash(str(self))
                self.update_remote()
                # Call callback for updated settings
                if self.changed_callback and hash(str(self)) != original:
                    self.changed_callback()

        except Exception as e:
            LOG.error(e)
            LOG.exception("")

        # this is used in core so do not delete!
        if self.is_alive:
            # continues to poll settings every 60 seconds
            t = Timer(60, self._poll_skill_settings)
            t.daemon = True
            t.start()
예제 #8
0
    def __init__(self):
        super(GoVivaceSTT, self).__init__()
        self.default_uri = "https://services.govivace.com:49149/telephony"

        if not self.lang.startswith("en") and not self.lang.startswith("es"):
            LOG.error("GoVivace STT only supports english and spanish")
            raise NotImplementedError
예제 #9
0
def _read_data():
    """ Writes the dictionary of state data from the IPC directory.
    Returns:
        dict: loaded state information
    """
    managerIPCDir = os.path.join(get_ipc_directory(), "managers")

    path = os.path.join(managerIPCDir, "disp_info")
    permission = "r" if os.path.isfile(path) else "w+"

    if permission == "w+" and os.path.isdir(managerIPCDir) is False:
        os.makedirs(managerIPCDir)

    data = {}
    try:
        with open(path, permission) as dispFile:

            if os.stat(str(dispFile.name)).st_size != 0:
                data = json.load(dispFile)

    except Exception as e:
        LOG.error(e)
        os.remove(path)
        _read_data()

    return data
예제 #10
0
    def __init__(self, cache=None):
        super(RemoteConf, self).__init__(None)

        cache = cache or '/opt/mycroft/web_config_cache.json'

        try:
            # Here to avoid cyclic import
            from mycroft.api import DeviceApi
            api = DeviceApi()
            setting = api.get_settings()
            location = api.get_location()
            if location:
                setting["location"] = location
            # Remove server specific entries
            config = {}
            translate_remote(config, setting)
            for key in config:
                self.__setitem__(key, config[key])
            self.store(cache)

        except HTTPError as e:
            LOG.error("HTTPError fetching remote configuration: %s" %
                      e.response.status_code)
            self.load_local(cache)

        except Exception as e:
            LOG.error("Failed to fetch remote configuration: %s" % repr(e),
                      exc_info=True)
            self.load_local(cache)
예제 #11
0
def mute_and_speak(utterance, ident):
    """
        Mute mic and start speaking the utterance using selected tts backend.

        Args:
            utterance:  The sentence to be spoken
            ident:      Ident tying the utterance to the source query
    """
    global tts_hash

    # update TTS object if configuration has changed
    if tts_hash != hash(str(config.get('tts', ''))):
        global tts
        # Stop tts playback thread
        tts.playback.stop()
        tts.playback.join()
        # Create new tts instance
        tts = TTSFactory.create()
        tts.init(bus)
        tts_hash = hash(str(config.get('tts', '')))

    LOG.info("Speak: " + utterance)
    try:
        tts.execute(utterance, ident)
    except RemoteTTSTimeoutException as e:
        LOG.error(e)
        mimic_fallback_tts(utterance, ident)
    except Exception as e:
        LOG.error('TTS execution failed ({})'.format(repr(e)))
예제 #12
0
 def read(self):
     while self.alive:
         try:
             data = self.serial.readline()[:-2]
             if data:
                 self.process(data)
         except Exception as e:
             LOG.error("Reading error: {0}".format(e))
예제 #13
0
 def deactivate_skill(self, message):
     """ Deactivate a skill. """
     try:
         skill = message.data['skill']
         if skill in [basename(s) for s in self.loaded_skills]:
             self.__deactivate_skill(skill)
     except Exception as e:
         LOG.error('Couldn\'t deactivate skill, {}'.format(repr(e)))
예제 #14
0
 def flush(self):
     while self.alive:
         try:
             cmd = self.commands.get()
             self.serial.write(cmd + '\n')
             self.commands.task_done()
         except Exception as e:
             LOG.error("Writing error: {0}".format(e))
예제 #15
0
 def __play(self, req):
     resp = req.result()
     if resp.status_code == 200:
         self.__save(resp.content)
         play_wav(self.filename).communicate()
     else:
         LOG.error(
             '%s Http Error: %s for url: %s' %
             (resp.status_code, resp.reason, resp.url))
예제 #16
0
 def run(self):
     try:
         self.ws.on('message', LOG.debug)
         self.ws.on('open', self.load_skill)
         self.ws.on('error', LOG.error)
         self.ws.run_forever()
     except Exception as e:
         LOG.error("Error: {0}".format(e))
         self.stop()
예제 #17
0
 def on_gui_send_event(self, message):
     """ Send an event to the GUIs. """
     try:
         data = {'type': 'mycroft.events.triggered',
                 'namespace': message.data.get('__from'),
                 'event_name': message.data.get('event_name'),
                 'params': message.data.get('params')}
         self.send(data)
     except Exception as e:
         LOG.error('Could not send event ({})'.format(repr(e)))
예제 #18
0
 def get():
     if (exists(VersionManager.__location) and
             isfile(VersionManager.__location)):
         try:
             with open(VersionManager.__location) as f:
                 return json.load(f)
         except:
             LOG.error("Failed to load version from '%s'"
                       % VersionManager.__location)
     return {"coreVersion": None, "enclosureVersion": None}
예제 #19
0
 def get():
     data_dir = expanduser(Configuration.get()['data_dir'])
     version_file = join(data_dir, 'version.json')
     if exists(version_file) and isfile(version_file):
         try:
             with open(version_file) as f:
                 return json.load(f)
         except Exception:
             LOG.error("Failed to load version from '%s'" % version_file)
     return {"coreVersion": None, "enclosureVersion": None}
예제 #20
0
def handle_speak(event):
    """
        Handle "speak" message
    """
    config = Configuration.get()
    Configuration.init(bus)
    global _last_stop_signal

    # Get conversation ID
    if event.context and 'ident' in event.context:
        ident = event.context['ident']
    else:
        ident = 'unknown'

    start = time.time()  # Time of speech request
    with lock:
        stopwatch = Stopwatch()
        stopwatch.start()
        utterance = event.data['utterance']
        if event.data.get('expect_response', False):
            # When expect_response is requested, the listener will be restarted
            # at the end of the next bit of spoken audio.
            bus.once('recognizer_loop:audio_output_end', _start_listener)

        # This is a bit of a hack for Picroft.  The analog audio on a Pi blocks
        # for 30 seconds fairly often, so we don't want to break on periods
        # (decreasing the chance of encountering the block).  But we will
        # keep the split for non-Picroft installs since it give user feedback
        # faster on longer phrases.
        #
        # TODO: Remove or make an option?  This is really a hack, anyway,
        # so we likely will want to get rid of this when not running on Mimic
        if (config.get('enclosure', {}).get('platform') != "picroft" and
                len(re.findall('<[^>]*>', utterance)) == 0):
            chunks = re.split(r'(?<!\w\.\w.)(?<![A-Z][a-z]\.)(?<=\.|\;|\?)\s',
                              utterance)
            for chunk in chunks:
                # Check if somthing has aborted the speech
                if (_last_stop_signal > start or
                        check_for_signal('buttonPress')):
                    # Clear any newly queued speech
                    tts.playback.clear()
                    break
                try:
                    mute_and_speak(chunk, ident)
                except KeyboardInterrupt:
                    raise
                except Exception:
                    LOG.error('Error in mute_and_speak', exc_info=True)
        else:
            mute_and_speak(utterance, ident)

        stopwatch.stop()
    report_timing(ident, 'speech', stopwatch, {'utterance': utterance,
                                               'tts': tts.__class__.__name__})
예제 #21
0
    def _play(self, message):
        """ Implementation specific async method to handle playback.
            This allows mpg123 service to use the "next method as well
            as basic play/stop.
        """
        LOG.info('SimpleAudioService._play')
        repeat = message.data.get('repeat', False)
        self._is_playing = True
        if isinstance(self.tracks[self.index], list):
            track = self.tracks[self.index][0]
            mime = self.tracks[self.index][1]
            mime = mime.split('/')
        else:  # Assume string
            track = self.tracks[self.index]
            mime = find_mime(track)
        # Indicate to audio service which track is being played
        if self._track_start_callback:
            self._track_start_callback(track)

        # Replace file:// uri's with normal paths
        track = track.replace('file://', '')
        try:
            if 'mpeg' in mime[1]:
                self.process = play_mp3(track)
            elif 'ogg' in mime[1]:
                self.process = play_ogg(track)
            elif 'wav' in mime[1]:
                self.process = play_wav(track)
            else:
                # If no mime info could be determined guess mp3
                self.process = play_mp3(track)
        except FileNotFoundError as e:
            LOG.error('Couldn\'t play audio, {}'.format(repr(e)))
            self.process = None

        # Wait for completion or stop request
        while (self.process and self.process.poll() is None and
                not self._stop_signal):
            sleep(0.25)

        if self._stop_signal:
            self.process.terminate()
            self.process = None
            self._is_playing = False
            return

        self.index += 1
        # if there are more tracks available play next
        if self.index < len(self.tracks) or repeat:
            if self.index >= len(self.tracks):
                self.index = 0
            self.bus.emit(Message('SimpleAudioServicePlay',
                                  {'repeat': repeat}))
        else:
            self._is_playing = False
예제 #22
0
파일: ws.py 프로젝트: Ceda-EI/mycroft-core
 def on_error(self, ws, error):
     try:
         self.emitter.emit('error', error)
         self.client.close()
     except Exception as e:
         LOG.error(repr(e))
     LOG.warning("WS Client will reconnect in %d seconds." % self.retry)
     time.sleep(self.retry)
     self.retry = min(self.retry * 2, 60)
     self.client = self.create_client()
     self.run_forever()
예제 #23
0
 def __deactivate_skill(self, skill):
     """ Deactivate a skill. """
     for s in self.loaded_skills:
         if skill in s:
             skill = s
             break
     try:
         self.loaded_skills[skill]['active'] = False
         self.loaded_skills[skill]['instance'].default_shutdown()
     except Exception as e:
         LOG.error('Couldn\'t deactivate skill, {}'.format(repr(e)))
예제 #24
0
 def __handle_stop(self, event):
     """
         Handler for the "mycroft.stop" signal. Runs the user defined
         `stop()` method.
     """
     self.stop_time = time.time()
     try:
         self.stop()
     except:
         LOG.error("Failed to stop skill: {}".format(self.name),
                   exc_info=True)
예제 #25
0
 def create_config(self, dict_name, config):
     model_file = join(RECOGNIZER_DIR, 'model', self.lang, 'hmm')
     if not exists(model_file):
         LOG.error('PocketSphinx model not found at ' + str(model_file))
     config.set_string('-hmm', model_file)
     config.set_string('-dict', dict_name)
     config.set_string('-keyphrase', self.key_phrase)
     config.set_float('-kws_threshold', float(self.threshold))
     config.set_float('-samprate', self.sample_rate)
     config.set_int('-nfft', 2048)
     config.set_string('-logfn', '/dev/null')
     return config
예제 #26
0
 def load_skill_settings_from_file(self):
     """ If settings.json exist, open and read stored values into self """
     if isfile(self._settings_path):
         with open(self._settings_path) as f:
             try:
                 json_data = json.load(f)
                 for key in json_data:
                     self[key] = json_data[key]
             except Exception as e:
                 # TODO: Show error on webUI.  Dev will have to fix
                 # metadata to be able to edit later.
                 LOG.error(e)
예제 #27
0
 def __init_serial(self):
     try:
         self.port = self.config.get("port")
         self.rate = self.config.get("rate")
         self.timeout = self.config.get("timeout")
         self.serial = serial.serial_for_url(
             url=self.port, baudrate=self.rate, timeout=self.timeout)
         LOG.info("Connected to: %s rate: %s timeout: %s" %
                  (self.port, self.rate, self.timeout))
     except:
         LOG.error("Impossible to connect to serial port: "+str(self.port))
         raise
예제 #28
0
    def write_skills_data(data: dict):
        skills_data_file = expanduser('~/.mycroft/skills.json')
        with open(skills_data_file, 'w') as f:
            json.dump(data, f)

        if (is_paired and
                Configuration.get()['skills'].get('upload_skill_manifest')):
            upload_data = SkillManager.convert_skills_data(data)
            try:
                DeviceApi().upload_skills_data(upload_data)
            except Exception as e:
                LOG.error('An error occured ({})'.format(e))
예제 #29
0
 def enable_intent(self, intent_name):
     """Reenable a registered intent"""
     for (name, intent) in self.registered_intents:
         if name == intent_name:
             self.registered_intents.remove((name, intent))
             intent.name = name
             self.register_intent(intent, None)
             LOG.debug('Enabling intent ' + intent_name)
             break
         else:
             LOG.error('Could not enable ' + intent_name +
                       ', it hasn\'t been registered.')
예제 #30
0
def load_skill(skill_descriptor, emitter, skill_id, BLACKLISTED_SKILLS=None):
    """
        load skill from skill descriptor.

        Args:
            skill_descriptor: descriptor of skill to load
            emitter:          messagebus emitter
            skill_id:         id number for skill
        Returns:
            MycroftSkill: the loaded skill or None on failure
    """
    BLACKLISTED_SKILLS = BLACKLISTED_SKILLS or []
    try:
        LOG.info("ATTEMPTING TO LOAD SKILL: " + skill_descriptor["name"] +
                 " with ID " + str(skill_id))
        if skill_descriptor['name'] in BLACKLISTED_SKILLS:
            LOG.info("SKILL IS BLACKLISTED " + skill_descriptor["name"])
            return None
        skill_module = imp.load_module(
            skill_descriptor["name"] + MainModule, *skill_descriptor["info"])
        if (hasattr(skill_module, 'create_skill') and
                callable(skill_module.create_skill)):
            # v2 skills framework
            skill = skill_module.create_skill()
            skill.settings.allow_overwrite = True
            skill.settings.load_skill_settings_from_file()
            skill.bind(emitter)
            skill.skill_id = skill_id
            skill.load_data_files(dirname(skill_descriptor['info'][1]))
            # Set up intent handlers
            skill.initialize()
            skill._register_decorated()
            LOG.info("Loaded " + skill_descriptor["name"])

            # The very first time a skill is run, speak the intro
            first_run = skill.settings.get("__mycroft_skill_firstrun", True)
            if first_run:
                LOG.info("First run of "+skill_descriptor["name"])
                skill.settings["__mycroft_skill_firstrun"] = False
                skill.settings.store()
                intro = skill.get_intro_message()
                if intro:
                    skill.speak(intro)
            return skill
        else:
            LOG.warning(
                "Module %s does not appear to be skill" % (
                    skill_descriptor["name"]))
    except:
        LOG.error(
            "Failed to load skill: " + skill_descriptor["name"],
            exc_info=True)
    return None
예제 #31
0
    def handle_current_weather(self, message):
        try:
            # Get a date from requests like "weather for next Tuesday"
            today = extract_datetime(" ")[0]
            when = extract_datetime(message.data.get('utterance'))[0]
            if today != when:
                LOG.info("Doing a forecast" + str(today) + " " + str(when))
                return self.handle_forecast(message)

            report = self.__initialize_report(message)

            # Get current conditions
            currentWeather = self.owm.weather_at_place(
                report['full_location'], report['lat'],
                report['lon']).get_weather()
            report['condition'] = currentWeather.get_detailed_status()
            report['temp'] = self.__get_temperature(currentWeather, 'temp')
            report['icon'] = currentWeather.get_weather_icon_name()

            # Get forecast for the day
            # can get 'min', 'max', 'eve', 'morn', 'night', 'day'
            # Set time to 12 instead of 00 to accomodate for timezones
            forecastWeather = self.__get_forecast(
                today.replace(
                    hour=12),
                report['full_location'],
                report['lat'],
                report['lon'])
            report['temp_min'] = self.__get_temperature(forecastWeather, 'min')
            report['temp_max'] = self.__get_temperature(forecastWeather, 'max')

            self.__report_weather("current", report)
        except HTTPError as e:
            self.__api_error(e)
        except Exception as e:
            LOG.error("Error: {0}".format(e))
예제 #32
0
파일: main.py 프로젝트: hungnt1/core
    def shutdown(self):
        for s in self.service:
            try:
                LOG.info('shutting down ' + s.name)
                s.shutdown()
            except Exception as e:
                LOG.error('shutdown of ' + s.name + ' failed: ' + repr(e))

        # remove listeners
        self.ws.remove('mycroft.audio.service.play', self._play)
        self.ws.remove('mycroft.audio.service.queue', self._queue)
        self.ws.remove('mycroft.audio.service.pause', self._pause)
        self.ws.remove('mycroft.audio.service.resume', self._resume)
        self.ws.remove('mycroft.audio.service.stop', self._stop)
        self.ws.remove('mycroft.audio.service.next', self._next)
        self.ws.remove('mycroft.audio.service.prev', self._prev)
        self.ws.remove('mycroft.audio.service.track_info', self._track_info)
        self.ws.remove('recognizer_loop:audio_output_start',
                       self._lower_volume)
        self.ws.remove('recognizer_loop:record_begin', self._lower_volume)
        self.ws.remove('recognizer_loop:audio_output_end',
                       self._restore_volume)
        self.ws.remove('recognizer_loop:record_end', self._restore_volume)
        self.ws.remove('mycroft.stop', self._stop)
예제 #33
0
 def run_requirements_sh(self, skill_folder):
     skill = self.skills[skill_folder]
     reqs = join(skill["path"], "requirements.sh")
     # TODO check hash before re running
     if exists(reqs):
         LOG.info("running requirements.sh for: " + skill_folder)
         # make exec
         subprocess.call((["chmod", "+x", reqs]))
         # handle sudo
         if self.platform in ["desktop", "kde", "jarbas"]:
             # gksudo
             args = ["gksu", "bash", reqs]
         else:  # no sudo
             args = ["bash", reqs]
         rc = subprocess.call(args)
         LOG.debug("Requirements.sh return code:" + str(rc))
         if rc != 0:
             LOG.error("Requirements.sh failed with error code: " + str(rc))
             raise SystemRequirementsException
         LOG.info("Successfully ran requirements.sh for " + skill_folder)
     else:
         LOG.info("no requirements.sh to run")
         return False
     return True
예제 #34
0
    def read(self):
        try:
            message = self.queue.get(timeout=0.5)
        except Empty:
            return

        if message is None:
            return

        tag, data = message

        if tag == AUDIO_DATA:
            if self.state.sleeping:
                self.wake_up(data)
            else:
                self.process(data)
        elif tag == STREAM_START:
            self.stt.stream_start()
        elif tag == STREAM_DATA:
            self.stt.stream_data(data)
        elif tag == STREAM_STOP:
            self.stt.stream_stop()
        else:
            LOG.error("Unknown audio queue type %r" % message)
예제 #35
0
    def run(self):
        """ Load skills and update periodically from disk and internet """

        self.remove_git_locks()
        self._connected_event.wait()
        has_loaded = False

        # check if skill updates are enabled
        update = Configuration.get()["skills"]["auto_update"]

        # Scan the file folder that contains Skills.  If a Skill is updated,
        # unload the existing version from memory and reload from the disk.
        while not self._stop_event.is_set():
            # Update skills once an hour if update is enabled
            if time.time() >= self.next_download and update:
                self.download_skills()

            # Look for recently changed skill(s) needing a reload
            # checking skills dir and getting all skills there
            skill_paths = glob(join(self.msm.skills_dir, '*/'))
            still_loading = False
            for skill_path in skill_paths:
                try:
                    still_loading = (self._load_or_reload_skill(skill_path)
                                     or still_loading)
                except Exception as e:
                    LOG.error('(Re)loading of {} failed ({})'.format(
                        skill_path, repr(e)))
            if not has_loaded and not still_loading and len(skill_paths) > 0:
                has_loaded = True
                LOG.info("Skills all loaded!")
                self.bus.emit(Message('mycroft.skills.initialized'))

            self._unload_removed(skill_paths)
            # Pause briefly before beginning next scan
            time.sleep(2)
예제 #36
0
def get_services(services_folder):
    """
        Load and initialize services from all subfolders.

        Args:
            services_folder: base folder to look for services in.

        Returns:
            Sorted list of audio services.
    """
    LOG.info("Loading services from " + services_folder)
    services = []
    possible_services = listdir(services_folder)
    for i in possible_services:
        location = join(services_folder, i)
        if (isdir(location) and
                not MAINMODULE + ".py" in listdir(location)):
            for j in listdir(location):
                name = join(location, j)
                if (not isdir(name) or
                        not MAINMODULE + ".py" in listdir(name)):
                    continue
                try:
                    services.append(create_service_descriptor(name))
                except Exception:
                    LOG.error('Failed to create service from ' + name,
                              exc_info=True)
        if (not isdir(location) or
                not MAINMODULE + ".py" in listdir(location)):
            continue
        try:
            services.append(create_service_descriptor(location))
        except Exception:
            LOG.error('Failed to create service from ' + location,
                      exc_info=True)
    return sorted(services, key=lambda p: p.get('name'))
예제 #37
0
    def play(self, device, uris=None, context_uri=None):
        """ Start playback of tracks, albums or artist.

        Can play either a list of uris or a context_uri for things like
        artists and albums. Both uris and context_uri shouldn't be provided
        at the same time.

        Args:
            device (int):      device id to start playback on
            uris (list):       list of track uris to play
            context_uri (str): Spotify context uri for playing albums or
                               artists.
        """
        data = {}
        if uris:
            data['uris'] = uris
        elif context_uri:
            data['context_uri'] = context_uri
        path = 'me/player/play?device_id={}'.format(device)
        try:
            self._put(path, payload=data)
        except Exception as e:
            LOG.error(e)
            raise
예제 #38
0
    def handle_next_hour(self, message):
        try:
            report = self.__initialize_report(message)

            # Get near-future forecast
            forecastWeather = self.owm.three_hours_forecast(
                report['full_location'], report['lat'],
                report['lon']).get_forecast().get_weathers()[0]

            # NOTE: The 3-hour forecast uses different temperature labels,
            # temp, temp_min and temp_max.
            report['temp'] = self.__get_temperature(forecastWeather, 'temp')
            report['temp_min'] = self.__get_temperature(
                forecastWeather, 'temp_min')
            report['temp_max'] = self.__get_temperature(
                forecastWeather, 'temp_max')
            report['condition'] = forecastWeather.get_detailed_status()
            report['icon'] = forecastWeather.get_weather_icon_name()

            self.__report_weather("hour", report)
        except HTTPError as e:
            self.__api_error(e)
        except Exception as e:
            LOG.error("Error: {0}".format(e))
예제 #39
0
    def on_error(self, error):
        """ On error start trying to reconnect to the websocket. """
        if isinstance(error, WebSocketConnectionClosedException):
            LOG.warning('Could not send message because connection has closed')
        else:
            LOG.exception('=== ' + repr(error) + ' ===')

        try:
            self.emitter.emit('error', error)
            if self.client.keep_running:
                self.client.close()
        except Exception as e:
            LOG.error('Exception closing websocket: ' + repr(e))

        LOG.warning("Message Bus Client will reconnect in %d seconds." %
                    self.retry)
        time.sleep(self.retry)
        self.retry = min(self.retry * 2, 60)
        try:
            self.emitter.emit('reconnecting')
            self.client = self.create_client()
            self.run_forever()
        except WebSocketException:
            pass
예제 #40
0
    def _poll_skill_settings(self):
        """ If identifier exists for this skill poll to backend to
            request settings and store it if it changes
            TODO: implement as websocket

            Args:
                hashed_meta (int): the hashed identifier
        """
        original = hash(str(self))
        try:
            if not is_paired():
                pass
            elif not self._complete_intialization:
                self.initialize_remote_settings()
                if not self._complete_intialization:
                    return  # unable to do remote sync
            else:
                self.update_remote()

        except Exception as e:
            LOG.error('Failed to fetch skill settings:\n{}'.format(e))
        finally:
            # Call callback for updated settings
            if self.changed_callback and hash(str(self)) != original:
                self.changed_callback()

        if self._poll_timer:
            self._poll_timer.cancel()

        if not self._is_alive:
            return

        # continues to poll settings every minute
        self._poll_timer = Timer(60, self._poll_skill_settings)
        self._poll_timer.daemon = True
        self._poll_timer.start()
예제 #41
0
 def play_film_by_search(self, kodi_id, film_search):
     # Todo need to remove kodi_id (kodipydent) reference
     results = self.find_films_matching(kodi_id, film_search)
     self.movie_list = results
     self.movie_index = 0
     if len(results) == 1:
         self.play_film(results[0]['movieid'])
     elif len(results):
         self.set_context('NavigateContextKeyword', 'NavigateContext')
         if self.notifier_bool:
             try:
                 self.post_kodi_notification(film_search + ' : '+ str(len(results)))
             except Exception as e:
                 LOG.error(e)
                 self.on_websettings_changed()
         self.speak_dialog('multiple.results', data={"result": str(len(results))}, expect_response=True)
     else:
         if self.notifier_bool:
             try:
                 self.post_kodi_notification(film_search + ' : '+ str(len(results)))
             except Exception as e:
                 LOG.error(e)
                 self.on_websettings_changed()
         self.speak_dialog('no.results', data={"result": film_search}, expect_response=False)
예제 #42
0
 def play_film_by_search(
         self, kodi_id,
         film_search):  # called from, handle_play_film_intent
     results = self.find_films_matching(kodi_id, film_search)
     self.movie_list = results
     self.movie_index = 0
     if len(results) == 1:
         self.play_film(kodi_id, results[0]['movieid'])
     elif len(results):
         msg_payload = "I found, " + str(
             len(results)) + ", results, would you like me to list them?"
         if self.notifier_bool:
             try:
                 self.kodi_instance.GUI.ShowNotification(
                     title="Mycroft.AI",
                     message=msg_payload,
                     displaytime=2500)
             except Exception as e:
                 LOG.error(e)
                 self.on_websettings_changed()
         self.speak_dialog('context',
                           data={"result": msg_payload},
                           expect_response=True)
     else:
         msg_payload = "I found no results for the search: {}.".format(
             film_search)
         if self.notifier_bool:
             try:
                 self.kodi_instance.GUI.ShowNotification(
                     title="Mycroft.AI",
                     message=msg_payload,
                     displaytime=2500)
             except Exception as e:
                 LOG.error(e)
                 self.on_websettings_changed()
         self.stop_navigation(msg_payload)
예제 #43
0
def play_wav(uri):
    """ Play a wav-file.

        This will use the application specified in the mycroft config
        and play the uri passed as argument. The function will return directly
        and play the file in the background.

        Arguments:
            uri:    uri to play

        Returns: subprocess.Popen object
    """
    config = mycroft.configuration.Configuration.get()
    play_cmd = config.get("play_wav_cmdline")
    play_wav_cmd = str(play_cmd).split(" ")
    for index, cmd in enumerate(play_wav_cmd):
        if cmd == "%1":
            play_wav_cmd[index] = (get_http(uri))
    try:
        return subprocess.Popen(play_wav_cmd)
    except Exception as e:
        LOG.error("Failed to launch WAV: {}".format(play_wav_cmd))
        LOG.debug("Error: {}".format(repr(e)), exc_info=True)
        return None
예제 #44
0
def pause_all(kodi_path, player_id=1):
    """
     Must perform a GetActivePlayer to retrieve player_id
    """
    api_path = kodi_path + "/jsonrpc"
    json_header = {'content-type': 'application/json'}
    method = "Player.PlayPause"
    kodi_payload = {
        "jsonrpc": "2.0",
        "method": method,
        "params": {
            "playerid": int(player_id),
            "play": False
        },
        "id": 1
    }
    try:
        kodi_response = requests.post(api_path,
                                      data=json.dumps(kodi_payload),
                                      headers=json_header)
        LOG.info(kodi_response.text)
        return kodi_response
    except Exception as e:
        LOG.error(e)
예제 #45
0
    def _send_settings_meta(self, settings_meta, hashed_meta):
        """ Send settingsmeta.json to the backend.

            Args:
                settings_meta (dict): dictionary of the current settings meta
                                      data
                hased_meta (int): hash value for settings meta data

            Returns:
                str: uuid, a unique id for the setting meta data
        """
        try:
            settings_meta["identifier"] = str(hashed_meta)
            self._put_metadata(settings_meta)
            settings = self._get_remote_settings()
            skill_identity = str(hashed_meta)
            uuid = None
            # TODO: note uuid should be returned from the put request
            for skill_setting in settings:
                if skill_setting['identifier'] == skill_identity:
                    uuid = skill_setting["uuid"]
            return uuid
        except Exception as e:
            LOG.error(e)
예제 #46
0
    def handle_movie_search(self, message):
        # Pull data from intent
        search_title = message.data.get('title')
        search_actor = message.data.get('actor')

        # Talk to the user
        self.speak_dialog('search.for.that')

        # If the user specified an actor, search for the first matching title on IMDB to get the IMDB ID
        if search_actor:
            try:
                self.results = self.search_imdb_actor(search_title, search_actor)
                # Didn't find anything in IMDB
                if not self.results:
                    self.speak_dialog('what.movie')
                # Found one in IMDB, go find it via utelly, etc
                else:
                    self.movie_search(0)
            # Something went wrong with IMDB search
            except Exception as e:
                self.speak_dialog('unable.to.connect', data={'service':'imdb'})
                LOG.error("Error searching imdb: " + str(e))

        # If no actor was specified, find the top three and let the user choose the correct option
        else:
            # Make IMDB api request and get results
            try:
                # Search IMDB for IMDB ID (top three results)
                self.results = self.search_imdb(search_title)[0:3]
                self.speak_dialog('movies.results')
                # List top three videos found on IMDB for the user to chose from
                self.list_movies()
            # Something went wrong talking to IMDB
            except Exception as e:
                self.speak_dialog('unable.to.connect', data={'service':'imdb'})
                LOG.error("Error searching imdb: " + str(e))
예제 #47
0
    def _load_settings_meta(self):
        """ Load settings metadata from the skill folder.

        If no settingsmeta exists a basic settingsmeta will be created
        containing a basic identifier.

        Returns:
            (dict) settings meta
        """
        if self._meta_path and os.path.isfile(self._meta_path):
            _, ext = os.path.splitext(self._meta_path)
            json_file = True if ext.lower() == ".json" else False

            try:
                with open(self._meta_path, encoding='utf-8') as f:
                    if json_file:
                        data = json.load(f)
                    else:
                        data = yaml.safe_load(f)
            except Exception as e:
                LOG.error("Failed to load setting file: " + self._meta_path)
                LOG.error(repr(e))
                data = {}
        else:
            data = {}

        # Insert skill_gid and display_name
        data['skill_gid'] = self.skill_gid
        data['display_name'] = (self.display_name or data.get('name') or
                                display_name(self.name))

        # Backwards compatibility:
        if 'name' not in data:
            data['name'] = data['display_name']

        return data
예제 #48
0
    def download_skills(self, speak=False):
        """ Invoke MSM to install default skills and/or update installed skills

            Args:
                speak (bool, optional): Speak the result? Defaults to False
        """
        # Don't invoke msm if already running
        if exists(MSM_BIN) and self.__msm_lock.acquire():
            try:
                # Invoke the MSM script to do the hard work.
                LOG.debug("==== Invoking Mycroft Skill Manager: " + MSM_BIN)
                p = subprocess.Popen(MSM_BIN + " default",
                                     stderr=subprocess.STDOUT,
                                     stdout=subprocess.PIPE,
                                     shell=True)
                (output, err) = p.communicate()
                res = p.returncode
                # Always set next update to an hour from now if successful
                if res == 0:
                    self.next_download = time.time() + 60 * MINUTES

                    if res == 0 and speak:
                        self.ws.emit(
                            Message(
                                "speak",
                                {'utterance': dialog.get("skills updated")}))
                    return True
                elif not connected():
                    LOG.error('msm failed, network connection not available')
                    if speak:
                        self.ws.emit(
                            Message(
                                "speak", {
                                    'utterance':
                                    dialog.get("not connected to the internet")
                                }))
                    self.next_download = time.time() + 5 * MINUTES
                    return False
                elif res != 0:
                    LOG.error('msm failed with error {}: {}'.format(
                        res, output))
                    if speak:
                        self.ws.emit(
                            Message(
                                "speak", {
                                    'utterance':
                                    dialog.get(
                                        "sorry I couldn't install default skills"
                                    )
                                }))
                    self.next_download = time.time() + 5 * MINUTES
                    return False
            finally:
                self.__msm_lock.release()
        else:
            LOG.error("Unable to invoke Mycroft Skill Manager: " + MSM_BIN)
예제 #49
0
    def handle_latest_intent(self, message):
        try:
            self.stop()

            feeddata = feedparser.parse(self.url_rss)
            data = feeddata.entries[0]
            # Stop anything already playing

            url = data.enclosures[0]['url']
            LOG.info('latest')
            LOG.info(url)

            # After the intro, start the no agenda stream
            # if audio service module is available use it
            wait_while_speaking()
            if self.audioservice:
                LOG.info('AudioService')
                self.audioservice.play(url, message.data['utterance'])
            else:  # othervice use normal mp3 playback
                LOG.info('playmp3')
                self.process = play_mp3(url)

        except Exception as e:
            LOG.error("Error: {0}".format(e))
예제 #50
0
    def handle_forecast(self, message):
        try:
            report = self.__initialize_report(message)

            # Get a date from spoken request
            when = extract_datetime(message.data.get('utterance'))[0]

            # Get forecast for the day
            forecastWeather = self.__get_forecast(
                when, report['full_location'], report['lat'], report['lon'])
            if forecastWeather is None:
                self.speak_dialog("no forecast", {'day': self.__to_day(when)})
                return

            # Can get temps for 'min', 'max', 'eve', 'morn', 'night', 'day'
            report['temp'] = self.__get_temperature(forecastWeather, 'day')
            report['temp_min'] = self.__get_temperature(forecastWeather, 'min')
            report['temp_max'] = self.__get_temperature(forecastWeather, 'max')
            report['icon'] = forecastWeather.get_weather_icon_name()

            # TODO: Run off of status IDs instead of the status text?
            # This converts a status like "sky is clear" to a different
            # text and tense, because you don't want:
            # "Friday it will be 82 and the sky is clear", it should be
            # 'Friday it will be 82 and the sky will be clear' or just
            # 'Friday it will be 82 and clear.
            report['condition'] = self.__translate(
                forecastWeather.get_detailed_status(), True)

            report['day'] = self.__to_day(when)  # Tuesday, tomorrow, etc.

            self.__report_weather("forecast", report)
        except HTTPError as e:
            self.__api_error(e)
        except Exception as e:
            LOG.error("Error: {0}".format(e))
예제 #51
0
    def _send_settings_meta(self, settings_meta):
        """ Send settingsmeta to the server.

        Args:
            settings_meta (dict): dictionary of the current settings meta
        Returns:
            dict: uuid, a unique id for the setting meta data
        """
        if self._meta_upload:
            try:
                uuid = self.api.upload_skill_metadata(
                    self._type_cast(settings_meta, to_platform='web'))
                return uuid
            except HTTPError as e:
                if e.response.status_code in [422, 500, 501]:
                    self._meta_upload = False
                    raise DelayRequest
                else:
                    LOG.error(e)
                    return None

            except Exception as e:
                LOG.error(e)
                return None
예제 #52
0
def skip_play(kodi_path, dir_skip):
    """
        Confirm that Koid i splaying before Executing this script
    """
    api_path = kodi_path + "/jsonrpc"
    json_header = {'content-type': 'application/json'}
    method = "Player.Seek"
    kodi_payload = {
        "jsonrpc": "2.0",
        "method": method,
        "params": {
            "playerid": 1,
            "value": dir_skip
        },
        "id": 1
    }
    try:
        kodi_response = requests.post(api_path,
                                      data=json.dumps(kodi_payload),
                                      headers=json_header)
        LOG.info(kodi_response.text)
        return kodi_response
    except Exception as e:
        LOG.error(e)
예제 #53
0
    def __init__(self, cache=None):
        super().__init__(None)
        cache = cache or WEB_CONFIG_CACHE
        from mycroft.api import is_paired
        if not is_paired():
            self.load_local(cache)
            return
        try:
            # Here to avoid cyclic import
            from mycroft.api import DeviceApi
            from mycroft.api import is_backend_disabled

            if is_backend_disabled():
                # disable options that require backend
                config = {
                    "server": {
                        "metrics": False,
                        "sync_skill_settings": False
                    },
                    "skills": {"upload_skill_manifest": False},
                    "opt_in": False
                }
                for key in config:
                    self.__setitem__(key, config[key])
            else:
                api = DeviceApi()
                setting = api.get_settings()
                location = None
                try:
                    location = api.get_location()
                except RequestException as e:
                    LOG.error("RequestException fetching remote location: {}"
                              .format(str(e)))
                    if exists(cache) and isfile(cache):
                        location = load_commented_json(cache).get('location')

                if location:
                    setting["location"] = location
                # Remove server specific entries
                config = {}
                translate_remote(config, setting)

                for key in config:
                    self.__setitem__(key, config[key])
                self.store(cache)

        except RequestException as e:
            LOG.error("RequestException fetching remote configuration: {}"
                      .format(str(e)))
            self.load_local(cache)

        except Exception as e:
            LOG.error("Failed to fetch remote configuration: %s" % repr(e),
                      exc_info=True)
            self.load_local(cache)
예제 #54
0
 def wrapper(message):
     try:
         # Indicate that the skill handler is starting
         name = get_handler_name(handler)
         self.emitter.emit(
             Message("mycroft.skill.handler.start",
                     data={'handler': name}))
         if need_self:
             # When registring from decorator self is required
             if len(getargspec(handler).args) == 2:
                 handler(self, message)
             elif len(getargspec(handler).args) == 1:
                 handler(self)
             elif len(getargspec(handler).args) == 0:
                 # Zero may indicate multiple decorators, trying the
                 # usual call signatures
                 try:
                     handler(self, message)
                 except TypeError:
                     handler(self)
             else:
                 LOG.error("Unexpected argument count:" +
                           str(len(getargspec(handler).args)))
                 raise TypeError
         else:
             if len(getargspec(handler).args) == 2:
                 handler(message)
             elif len(getargspec(handler).args) == 1:
                 handler()
             else:
                 LOG.error("Unexpected argument count:" +
                           str(len(getargspec(handler).args)))
                 raise TypeError
         self.settings.store()  # Store settings if they've changed
     except Exception as e:
         # Convert "MyFancySkill" to "My Fancy Skill" for speaking
         name = re.sub("([a-z])([A-Z])", "\g<1> \g<2>", self.name)
         # TODO: Localize
         self.speak("An error occurred while processing a request in " +
                    name)
         LOG.error("An error occurred while processing a request in " +
                   self.name,
                   exc_info=True)
         # indicate completion with exception
         self.emitter.emit(
             Message('mycroft.skill.handler.complete',
                     data={
                         'handler': name,
                         'exception': e.message
                     }))
     # Indicate that the skill handler has completed
     self.emitter.emit(
         Message('mycroft.skill.handler.complete',
                 data={'handler': name}))
예제 #55
0
 def transcribe(self, audio):
     text = None
     try:
         # Invoke the STT engine on the audio clip
         text = self.stt.execute(audio).lower().strip()
         LOG.debug("STT: " + text)
     except sr.RequestError as e:
         LOG.error("Could not request Speech Recognition {0}".format(e))
     except ConnectionError as e:
         LOG.error("Connection Error: {0}".format(e))
         self.emitter.emit("recognizer_loop:no_internet")
     except HTTPError as e:
         if e.response.status_code == 401:
             text = "pair my device"  # phrase to start the pairing process
             LOG.warning("Access Denied at mycroft.ai")
     except Exception as e:
         self.emitter.emit('recognizer_loop:speech.recognition.unknown')
         LOG.error(e)
         LOG.error("Speech Recognition could not understand audio")
     return text
예제 #56
0
    def handle_send(self, message):
        ''' mycroft wants to send a message to a node instance '''
        # send message to client
        LOG.info("sending")
        msg = message.data.get("payload")
        is_file = message.data.get("isBinary", False)
        peer = message.data.get("peer")
        ident = message.context.get("ident")
        if not peer and ident:
            name = ident.split(":")[0]
            peer = ":".join(ident.split(":")[1:])
        elif peer and ":" not in peer:
            # name provided
            peer = self.factory.get_peer_by_name(peer)
            if not len(peer):
                peer = None
            else:
                peer = peer[0]
        if self.factory is None:
            LOG.error("factory not ready")
            return
        try:
            if is_file:
                # TODO send file
                self.bus.emit(message.reply("node_red.send.error",
                                                {
                                                    "error": "binary files not supported",
                                                    "peer": peer,
                                                    "payload": msg}))
            elif peer is None:
                # send message to client
                self.factory.broadcast_message(msg)
                

                self.bus.emit(message.reply("node_red.send.broadcast",
                                                {"peer": peer,
                                                 "payload": msg}))
            else:
                # send message to client
                if self.factory.send_message(peer, msg):
                    self.bus.emit(message.reply("node_red.send.success",
                                                    {"peer": peer,
                                                     "payload": msg}))
                else:
                    LOG.error("That client is not connected")
                    self.bus.emit(message.reply("node_red.send.error",
                                                    {"error": "unknown error",
                                                     "peer": peer,
                                                     "payload": msg}))
        except Exception as e:
            LOG.error(e)
예제 #57
0
    def __init__(self, cache=None):
        super(RemoteConf, self).__init__(None)

        cache = cache or join(xdg.BaseDirectory.xdg_cache_home, 'mycroft',
                              'web_cache.json')
        from mycroft.api import is_paired
        if not is_paired():
            self.load_local(cache)
            return

        try:
            # Here to avoid cyclic import
            from mycroft.api import DeviceApi
            api = DeviceApi()
            setting = api.get_settings()

            location = None
            try:
                location = api.get_location()
            except RequestException as e:
                LOG.error(
                    "RequestException fetching remote location: {}".format(
                        str(e)))
                if exists(cache) and isfile(cache):
                    location = load_commented_json(cache).get('location')

            if location:
                setting["location"] = location
            # Remove server specific entries
            config = {}
            translate_remote(config, setting)
            for key in config:
                self.__setitem__(key, config[key])
            self.store(cache)

        except RequestException as e:
            LOG.error(
                "RequestException fetching remote configuration: {}".format(
                    str(e)))
            self.load_local(cache)

        except Exception as e:
            LOG.error("Failed to fetch remote configuration: %s" % repr(e),
                      exc_info=True)
            self.load_local(cache)
예제 #58
0
def load_services(config, ws, path=None):
    """
        Search though the service directory and load any services.

        Args:
            config: configuration dicrt for the audio backends.
            ws: websocket object for communication.

        Returns:
            List of started services.
    """
    LOG.info("Loading services")
    if path is None:
        path = dirname(abspath(__file__)) + '/services/'
    service_directories = get_services(path)
    service = []
    for descriptor in service_directories:
        LOG.info('Loading ' + descriptor['name'])
        try:
            service_module = imp.load_module(descriptor["name"] + MAINMODULE,
                                             *descriptor["info"])
        except (KeyboardInterrupt, SystemExit):
            raise
        except Exception:
            LOG.error('Failed to import module ' + descriptor['name'],
                      exc_info=True)
        if (hasattr(service_module, 'autodetect')
                and callable(service_module.autodetect)):
            try:
                s = service_module.autodetect(config, ws)
                service += s
            except (KeyboardInterrupt, SystemExit):
                raise
            except Exception:
                LOG.error('Failed to autodetect...', exc_info=True)
        if hasattr(service_module, 'load_service'):
            try:
                s = service_module.load_service(config, ws)
                service += s
            except (KeyboardInterrupt, SystemExit):
                raise
            except Exception:
                LOG.error('Failed to load service...', exc_info=True)

    return service
예제 #59
0
def load_services(config, bus, path=None):
    """
        Search though the service directory and load any services.

        Args:
            config: configuration dict for the audio backends.
            bus: Mycroft messagebus

        Returns:
            List of started services.
    """
    if path is None:
        path = dirname(abspath(__file__)) + '/services/'
    service_directories = get_services(path)
    service = []
    for descriptor in service_directories:
        LOG.info('Loading ' + descriptor['name'])
        try:
            service_module = descriptor['info']['mod']
            spec = descriptor['info']['spec']
            module_name = descriptor['info']['module_name']
            sys.modules[module_name] = service_module
            spec.loader.exec_module(service_module)
        except Exception as e:
            LOG.error('Failed to import module ' + descriptor['name'] + '\n' +
                      repr(e))
            continue

        if (hasattr(service_module, 'autodetect')
                and callable(service_module.autodetect)):
            try:
                s = service_module.autodetect(config, bus)
                service += s
            except Exception as e:
                LOG.error('Failed to autodetect. ' + repr(e))
        if hasattr(service_module, 'load_service'):
            try:
                s = service_module.load_service(config, bus)
                service += s
            except Exception as e:
                LOG.error('Failed to load service. ' + repr(e))

    return service
예제 #60
0
파일: main.py 프로젝트: hungnt1/core
def load_services(config, ws, path=None):
    """
        Search though the service directory and load any services.

        Args:
            config: configuration dict for the audio backends.
            ws: websocket object for communication.

        Returns:
            List of started services.
    """
    if path is None:
        path = dirname(abspath(__file__)) + '/services/'
    service_directories = get_services(path)
    service = []
    for descriptor in service_directories:
        LOG.info('Loading ' + descriptor['name'])
        try:
            service_module = imp.load_module(descriptor["name"] + MAINMODULE,
                                             *descriptor["info"])
        except Exception as e:
            LOG.error('Failed to import module ' + descriptor['name'] + '\n' +
                      repr(e))
            continue

        if (hasattr(service_module, 'autodetect')
                and callable(service_module.autodetect)):
            try:
                s = service_module.autodetect(config, ws)
                service += s
            except Exception as e:
                LOG.error('Failed to autodetect. ' + repr(e))
        if hasattr(service_module, 'load_service'):
            try:
                s = service_module.load_service(config, ws)
                service += s
            except Exception as e:
                LOG.error('Failed to load service. ' + repr(e))

    return service