Exemple #1
0
def is_paired(ignore_errors=True):
    """ Determine if this device is actively paired with a web backend

    Determines if the installation of Mycroft has been paired by the user
    with the backend system, and if that pairing is still active.

    Returns:
        bool: True if paired with backend
    """
    global _paired_cache
    if _paired_cache:
        # NOTE: This assumes once paired, the unit remains paired.  So
        # un-pairing must restart the system (or clear this value).
        # The Mark 1 does perform a restart on RESET.
        return True

    try:
        api = DeviceApi()
        device = api.get()
        _paired_cache = api.identity.uuid is not None and \
            api.identity.uuid != ""
        return _paired_cache
    except HTTPError as e:
        if e.response.status_code == 401:
            return False
    except Exception as e:
        LOG.warning('Could not get device info: ' + repr(e))
    if ignore_errors:
        return False
    if connected():
        raise BackendDown
    raise InternetDown
Exemple #2
0
def install_default_skills(speak=True):
    """
        Install default skill set using msm.

        Args:
            speak (optional): Enable response for success. Default True
    """
    if exists(MSM_BIN):
        p = subprocess.Popen(MSM_BIN + " default", stderr=subprocess.STDOUT,
                             stdout=subprocess.PIPE, shell=True)
        (output, err) = p.communicate()
        res = p.returncode
        if res == 0 and speak:
            # ws.emit(Message("speak", {
            #     'utterance': mycroft.dialog.get("skills updated")}))
            pass
        elif not connected():
            LOG.error('msm failed, network connection is not available')
            ws.emit(Message("speak", {
                'utterance': mycroft.dialog.get("no network connection")}))
        elif res != 0:
            LOG.error('msm failed with error {}: {}'.format(res, output))
            ws.emit(Message("speak", {
                'utterance': mycroft.dialog.get(
                    "sorry I couldn't install default skills")}))

    else:
        LOG.error("Unable to invoke Mycroft Skill Manager: " + MSM_BIN)
def is_paired(ignore_errors=True):
    """ Determine if this device is actively paired with a web backend

    Determines if the installation of Mycroft has been paired by the user
    with the backend system, and if that pairing is still active.

    Returns:
        bool: True if paired with backend
    """
    global _paired_cache
    if _paired_cache:
        # NOTE: This assumes once paired, the unit remains paired.  So
        # un-pairing must restart the system (or clear this value).
        # The Mark 1 does perform a restart on RESET.
        return True

    try:
        api = DeviceApi()
        device = api.get()
        _paired_cache = api.identity.uuid is not None and \
            api.identity.uuid != ""
        return _paired_cache
    except HTTPError as e:
        if e.response.status_code == 401:
            return False
    except Exception as e:
        LOG.warning('Could not get device infO: ' + repr(e))
    if ignore_errors:
        return False
    if connected():
        raise BackendDown
    raise InternetDown
Exemple #4
0
    def _do_net_check(self):
        # TODO: This should live in the derived Enclosure, e.g. Enclosure_Mark1
        LOG.info("Checking internet connection")
        if not connected():  # and self.conn_monitor is None:
            if has_been_paired():
                # TODO: Enclosure/localization
                self.ws.emit(Message("speak", {
                    'utterance': "This unit is not connected to the Internet."
                                 " Either plug in a network cable or hold the "
                                 "button on top for two seconds, then select "
                                 "wifi from the menu"
                    }))
            else:
                # Begin the unit startup process, this is the first time it
                # is being run with factory defaults.

                # TODO: This logic should be in Enclosure_Mark1
                # TODO: Enclosure/localization

                # Don't listen to mic during this out-of-box experience
                self.ws.emit(Message("mycroft.mic.mute", None))

                # Kick off wifi-setup automatically
                self.ws.emit(Message("mycroft.wifi.start",
                                     {'msg': "Hello I am Mycroft, your new "
                                      "assistant.  To assist you I need to be "
                                      "connected to the internet.  You can "
                                      "either plug me in with a network cable,"
                                      " or use wifi.  To setup wifi ",
                                      'allow_timeout': False}))
def install_default_skills(speak=True):
    """
        Install default skill set using msm.

        Args:
            speak (optional): Enable response for success. Default True
    """
    if exists(MSM_BIN):
        p = subprocess.Popen(MSM_BIN + " default", stderr=subprocess.STDOUT,
                             stdout=subprocess.PIPE, shell=True)
        (output, err) = p.communicate()
        res = p.returncode
        if res == 0 and speak:
            # ws.emit(Message("speak", {
            #     'utterance': mycroft.dialog.get("skills updated")}))
            pass
        elif not connected():
            logger.error('msm failed, network connection is not available')
            ws.emit(Message("speak", {
                'utterance': mycroft.dialog.get("no network connection")}))
        elif res != 0:
            logger.error('msm failed with error {}: {}'.format(res, output))
            ws.emit(Message("speak", {
                'utterance': mycroft.dialog.get(
                             "sorry I couldn't install default skills")}))

    else:
        logger.error("Unable to invoke Mycroft Skill Manager: " + MSM_BIN)
Exemple #6
0
def check_connection():
    if connected():
        ws.emit(Message('mycroft.internet.connected'))
    else:
        thread = Timer(1, check_connection)
        thread.daemon = True
        thread.start()
Exemple #7
0
    def on_no_internet(self, event=None):
        if connected():
            # One last check to see if connection was established
            return

        if time.time() - Enclosure._last_internet_notification < 30:
            # don't bother the user with multiple notifications with 30 secs
            return

        Enclosure._last_internet_notification = time.time()

        # TODO: This should go into EnclosureMark1 subclass of Enclosure.
        if has_been_paired():
            # Handle the translation within that code.
            self.ws.emit(
                Message(
                    "speak", {
                        'utterance':
                        "This device is not connected to the Internet. "
                        "Either plug in a network cable or hold the "
                        "button on top for two seconds, then select "
                        "wifi from the menu"
                    }))
        else:
            # enter wifi-setup mode automatically
            self.ws.emit(Message('system.wifi.setup', {'lang': self.lang}))
Exemple #8
0
    def _do_net_check(self):
        # TODO: This should live in the derived Enclosure, e.g. Enclosure_Mark1
        LOG.info("Checking internet connection")
        if not connected():  # and self.conn_monitor is None:
            if has_been_paired():
                # TODO: Enclosure/localization
                self.speak("This unit is not connected to the Internet. "
                           "Either plug in a network cable or hold the "
                           "button on top for two seconds, then select "
                           "wifi from the menu")
            else:
                # Begin the unit startup process, this is the first time it
                # is being run with factory defaults.

                # TODO: This logic should be in Enclosure_Mark1
                # TODO: Enclosure/localization

                # Don't listen to mic during this out-of-box experience
                self.ws.emit(Message("mycroft.mic.mute"))
                # Setup handler to unmute mic at the end of on boarding
                # i.e. after pairing is complete
                self.ws.once('mycroft.paired', self._handle_pairing_complete)

                self.speak(mycroft.dialog.get('mycroft.intro'))
                wait_while_speaking()
                time.sleep(2)  # a pause sounds better than just jumping in

                # Kick off wifi-setup automatically
                data = {'allow_timeout': False, 'lang': self.lang}
                self.ws.emit(Message('system.wifi.setup', data))
Exemple #9
0
    def initialize(self):
        # Initialize...
        if self.settings.get('auto_brightness') is None:
            self.settings['auto_brightness'] = False
        if self.settings.get('eye color') is None:
            self.settings['eye color'] = "default"

        self.brightness_dict = self.translate_namedvalues('brightness.levels')
        self.color_dict = self.translate_namedvalues('colors')

        # Handle changing the eye color once Mark 1 is ready to go
        # (Part of the statup sequence)
        try:
            self.add_event('mycroft.internet.connected',
                           self.handle_internet_connected)
        except:
            pass

        # TODO: Add MycroftSkill.register_entity_list() and use the
        #  self.color_dict.keys() instead of duplicating data
        self.register_entity_file('color.entity')

        if connected():
            # Connected at startup: setting eye color
            self.enclosure.mouth_reset()
            self.set_eye_color(self.settings['eye color'], initing=True)
    def _do_net_check(self):
        # TODO: This should live in the derived Enclosure, e.g. Enclosure_Mark1
        LOG.info("Checking internet connection")
        if not connected():  # and self.conn_monitor is None:
            if has_been_paired():
                # TODO: Enclosure/localization
                self.ws.emit(Message("speak", {
                    'utterance': "This unit is not connected to the Internet."
                                 " Either plug in a network cable or hold the "
                                 "button on top for two seconds, then select "
                                 "wifi from the menu"
                    }))
            else:
                # Begin the unit startup process, this is the first time it
                # is being run with factory defaults.

                # TODO: This logic should be in Enclosure_Mark1
                # TODO: Enclosure/localization

                # Don't listen to mic during this out-of-box experience
                self.ws.emit(Message("mycroft.mic.mute", None))

                # Kick off wifi-setup automatically
                self.ws.emit(Message("mycroft.wifi.start",
                                     {'msg': "Hello I am Mycroft, your new "
                                      "assistant.  To assist you I need to be "
                                      "connected to the internet.  You can "
                                      "either plug me in with a network cable,"
                                      " or use wifi.  To setup wifi ",
                                      'allow_timeout': False}))
Exemple #11
0
    def transcribe(self, audio):
        try:
            # Invoke the STT engine on the audio clip
            text = self.stt.execute(audio).lower().strip()
            LOG.debug("STT: " + text)
            return 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:
                LOG.warning("Access Denied at mycroft.ai")
                return "pair my device"  # phrase to start the pairing process
            else:
                LOG.error(e.__class__.__name__ + ': ' + str(e))
        except RequestException as e:
            LOG.error(e.__class__.__name__ + ': ' + str(e))
        except Exception as e:
            self.emitter.emit('recognizer_loop:speech.recognition.unknown')
            if isinstance(e, IndexError):
                LOG.info('no words were transcribed')
            else:
                LOG.error(e)
            LOG.error("Speech Recognition could not understand audio")
            return None
        if connected():
            dialog_name = 'backend.down'
        else:
            dialog_name = 'not connected to the internet'
        self.emitter.emit('speak', {'utterance': dialog.get(dialog_name)})
    def transcribe(self, audio):
        def send_unknown_intent():
            """ Send message that nothing was transcribed. """
            self.emitter.emit('recognizer_loop:speech.recognition.unknown')

        try:
            # Invoke the STT engine on the audio clip
            text = self.stt.execute(audio)
            if text is not None:
                text = text.lower().strip()
                LOG.debug("STT: " + text)
            else:
                send_unknown_intent()
                LOG.info('no words were transcribed')
            return 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 RequestException as e:
            LOG.error(e.__class__.__name__ + ': ' + str(e))
        except Exception as e:
            send_unknown_intent()
            LOG.error(e)
            LOG.error("Speech Recognition could not understand audio")
            return None

        if connected():
            dialog_name = 'backend.down'
        else:
            dialog_name = 'not connected to the internet'
        self.emitter.emit('speak', {'utterance': dialog.get(dialog_name)})
Exemple #13
0
    def transcribe(self, audio_segments):
        utterances = []
        threads = []
        if connected():
            for audio in audio_segments:
                if self._audio_length(audio) < self.MIN_AUDIO_SIZE:
                    logger.debug("Audio too short to send to STT")
                    continue

                target = self._create_remote_stt_runnable(audio, utterances)
                t = threading.Thread(target=target)
                t.start()
                threads.append(t)

            for thread in threads:
                thread.join()
            if len(utterances) > 0:
                payload = {
                    'utterances': utterances,
                    'session': SessionManager.get().session_id
                }
                self.emitter.emit("recognizer_loop:utterance", payload)
                self.metrics.attr('utterances', utterances)
            else:
                raise sr.UnknownValueError
        else:  # TODO: Localization
            self.__speak("This device is not connected to the Internet")
    def _do_net_check(self):
        # TODO: This should live in the derived Enclosure, e.g. EnclosureMark1
        LOG.info("Checking internet connection")
        if not connected():  # and self.conn_monitor is None:
            if has_been_paired():
                # TODO: Enclosure/localization
                self.speak("This unit is not connected to the Internet. "
                           "Either plug in a network cable or hold the "
                           "button on top for two seconds, then select "
                           "wifi from the menu")
            else:
                # Begin the unit startup process, this is the first time it
                # is being run with factory defaults.

                # TODO: This logic should be in EnclosureMark1
                # TODO: Enclosure/localization

                # Don't listen to mic during this out-of-box experience
                self.bus.emit(Message("mycroft.mic.mute"))
                # Setup handler to unmute mic at the end of on boarding
                # i.e. after pairing is complete
                self.bus.once('mycroft.paired', self._handle_pairing_complete)

                self.speak(mycroft.dialog.get('mycroft.intro'))
                wait_while_speaking()
                time.sleep(2)  # a pause sounds better than just jumping in

                # Kick off wifi-setup automatically
                data = {'allow_timeout': False, 'lang': self.lang}
                self.bus.emit(Message('system.wifi.setup', data))
Exemple #15
0
    def transcribe(self, audio_segments):
        utterances = []
        threads = []
        if connected():
            for audio in audio_segments:
                if self._audio_length(audio) < self.MIN_AUDIO_SIZE:
                    logger.debug("Audio too short to send to STT")
                    continue

                target = self._create_remote_stt_runnable(audio, utterances)
                t = threading.Thread(target=target)
                t.start()
                threads.append(t)

            for thread in threads:
                thread.join()
            if len(utterances) > 0:
                payload = {
                    'utterances': utterances,
                    'session': SessionManager.get().session_id
                }
                self.emitter.emit("recognizer_loop:utterance", payload)
                self.metrics.attr('utterances', utterances)
            else:
                raise sr.UnknownValueError
        else:  # TODO: Localization
            self.__speak("This device is not connected to the Internet")
Exemple #16
0
    def _do_net_check(self):
        # TODO: This should live in the derived Enclosure, e.g. Enclosure_Mark1
        LOG.info("Checking internet connection")
        if not connected():  # and self.conn_monitor is None:
            if has_been_paired():
                # TODO: Enclosure/localization
                self.ws.emit(
                    Message(
                        "speak", {
                            'utterance':
                            "This unit is not connected to the Internet."
                            " Either plug in a network cable or hold the "
                            "button on top for two seconds, then select "
                            "wifi from the menu"
                        }))
            else:
                # Begin the unit startup process, this is the first time it
                # is being run with factory defaults.

                # TODO: This logic should be in Enclosure_Mark1
                # TODO: Enclosure/localization

                # Don't listen to mic during this out-of-box experience
                self.ws.emit(Message("mycroft.mic.mute"))
                # Setup handler to unmute mic at the end of on boarding
                # i.e. after pairing is complete
                self.ws.once('mycroft.paired', self._handle_pairing_complete)

                self.speak(mycroft.dialog.get('mycroft.intro'))
                # Kick off wifi-setup automatically
                data = {'allow_timeout': False, 'lang': self.lang}
                self.ws.emit(Message('mycroft.wifi.start', data))
        else:
            # Indicate we are checking for updates from the internet now...
            self.writer.write("mouth.text=< < < UPDATING < < < ")
Exemple #17
0
def check_connection():
    """
        Check for network connection. If not paired trigger pairing.
        Runs as a Timer every second until connection is detected.
    """
    if connected():
        enclosure = EnclosureAPI(ws)

        if is_paired():
            # Skip the sync message when unpaired because the prompt to go to
            # home.mycrof.ai will be displayed by the pairing skill
            enclosure.mouth_text(mycroft.dialog.get("message_synching.clock"))
        # Force a sync of the local clock with the internet
        ws.emit(Message("system.ntp.sync"))
        time.sleep(15)  # TODO: Generate/listen for a message response...

        # Check if the time skewed significantly.  If so, reboot
        skew = abs((monotonic.monotonic() - start_ticks) -
                   (time.time() - start_clock))
        if skew > 60 * 60:
            # Time moved by over an hour in the NTP sync. Force a reboot to
            # prevent weird things from occcurring due to the 'time warp'.
            #
            ws.emit(
                Message(
                    "speak",
                    {'utterance': mycroft.dialog.get("time.changed.reboot")}))
            wait_while_speaking()

            # provide visual indicators of the reboot
            enclosure.mouth_text(mycroft.dialog.get("message_rebooting"))
            enclosure.eyes_color(70, 65, 69)  # soft gray
            enclosure.eyes_spin()

            # give the system time to finish processing enclosure messages
            time.sleep(1.0)

            # reboot
            ws.emit(Message("system.reboot"))
            return

        ws.emit(Message('mycroft.internet.connected'))
        # check for pairing, if not automatically start pairing
        if not is_paired():
            # begin the process
            payload = {'utterances': ["pair my device"], 'lang': "en-us"}
            ws.emit(Message("recognizer_loop:utterance", payload))
        else:
            if is_paired():
                # Skip the  message when unpaired because the prompt to go
                # to home.mycrof.ai will be displayed by the pairing skill
                enclosure.mouth_text(mycroft.dialog.get("message_updating"))

            from mycroft.api import DeviceApi
            api = DeviceApi()
            api.update_version()
    else:
        thread = Timer(1, check_connection)
        thread.daemon = True
        thread.start()
Exemple #18
0
    def transcribe(self, audio):
        try:
            # Invoke the STT engine on the audio clip
            text = self.stt.execute(audio).lower().strip()
            LOG.debug("STT: " + text)
            return 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:
                LOG.warning("Access Denied at mycroft.ai")
                return "pair my device"  # phrase to start the pairing process
            else:
                LOG.error(e.__class__.__name__ + ': ' + str(e))
        except RequestException as e:
            LOG.error(e.__class__.__name__ + ': ' + str(e))
        except Exception as e:
            self.emitter.emit('recognizer_loop:speech.recognition.unknown')
            if isinstance(e, IndexError):
                LOG.info('no words were transcribed')
            else:
                LOG.error(e)
            LOG.error("Speech Recognition could not understand audio")
            return None
        if connected():
            dialog_name = 'backend.down'
        else:
            dialog_name = 'not connected to the internet'
        self.emitter.emit('speak', {'utterance': dialog.get(dialog_name)})
Exemple #19
0
def check_remote_pairing(ignore_errors):
    """Check that a basic backend endpoint accepts our pairing.

    Arguments:
        ignore_errors (bool): True if errors should be ignored when

    Returns:
        True if pairing checks out, otherwise False.
    """
    try:
        DeviceApi().get()
        return True
    except HTTPError as e:
        if e.response.status_code == 401:
            return False
        error = e
    except Exception as e:
        error = e

    LOG.warning('Could not get device info: {}'.format(repr(error)))

    if ignore_errors:
        return False

    if isinstance(error, HTTPError):
        if connected():
            raise BackendDown from error
        else:
            raise InternetDown from error
    else:
        raise error
Exemple #20
0
    def update_skills(self, quick=False):
        """Invoke MSM to install default skills and/or update installed skills

        Args:
            quick (bool): Expedite the download by running with more threads?
        """
        LOG.info('Beginning skill update...')
        self.msm._device_skill_state = None  # TODO: Proper msm method
        success = True
        if connected():
            self._load_installed_skills()
            with self.msm_lock, self.msm.lock:
                self._apply_install_or_update(quick)
            self._save_installed_skills()
            # Schedule retry in 5 minutes on failure, after 10 shorter periods
            # Go back to 60 minutes wait
            if self.default_skill_install_error and self.install_retries < 10:
                self._schedule_retry()
                success = False
            else:
                self.install_retries = 0
                self._update_download_time()
        else:
            self.handle_not_connected()
            success = False

        if success:
            LOG.info('Skill update complete')

        return success
Exemple #21
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':
                                mycroft.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':
                                    mycroft.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':
                                    mycroft.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)
Exemple #22
0
    def from_wifi(self, update=True):
        self.log.info("Retrieving location data from available wifi")
        if connected():
            url = "https://www.googleapis.com/geolocation/v1/geolocate" \
                       "?key=" + self.geolocateApiKey
            # TODO this only supports connected to networks, change
            available = Cell.all('wlan0')
            mac = []
            signal = []
            channel = []
            for wifi in available:
                channel.append(wifi.channel)
                mac.append(wifi.address)
                signal.append(wifi.signal)
            payload, headers = self.build_wifi_JSON(mac, signal, channel)

            try:
                response = requests.post(url,
                                         data=json.dumps(payload),
                                         headers=headers)
                text = json.loads(response.text)

                if response.ok == False:  # Check if the response was ok
                    if text['error']['errors'][0][
                            'reason'] == 'dailyLimitExceeded':
                        self.log.error('You have exceeded you daily limit')
                    elif text['error']['errors'][0]['reason'] == 'keyInvalid':
                        self.log.error('Your API key is not valid for the '
                                       'Google Maps Geolocation API')
                    elif text['error']['errors'][0][
                            'reason'] == 'userRateLimitExceeded':
                        self.log.error(
                            'You\'ve exceeded the requests per '
                            'second per user limit that you configured in the Google Developers Console'
                        )
                    elif text['error']['errors'][0]['reason'] == 'notFound':
                        self.log.error(
                            'The request was valid, but no results were returned'
                        )
                    elif text['error']['errors'][0]['reason'] == 'parseError':
                        self.log.error('The request body is not valid JSON')
                    else:
                        self.log.error(
                            'Unknown error in the geolocation '
                            'response. Might be caught in an exception.')
            except Exception, e:
                self.log.error(str(e))
                return

            decimal.getcontext(
            ).prec = 15  # Setting precision for lat/lng response
            lng = decimal.Decimal(text['location']['lng']) + 0
            lat = decimal.Decimal(text['location']['lat']) + 0
            accuracy = response['accuracy']
            geolocator = Nominatim()
            location = geolocator.reverse(str(lat) + ", " + str(lng))
            adress = location.adress
Exemple #23
0
 def handle_update_intent(self, message):
     if connected():
         self.speak("updating location from ip address")
         config = self.get_location("ip")
         city = config.get("city", {}).get("name", "unknown city")
         country = config.get("city", {}).get("region").get("country").get(
             "name", "unknow country")
     else:
         self.speak("Cant do that offline")
Exemple #24
0
    def on_no_internet(self, event=None):
        if connected():
            # One last check to see if connection was established
            return

        if time.time() - Enclosure._last_internet_notification < 30:
            # don't bother the user with multiple notifications with 30 secs
            return

        Enclosure._last_internet_notification = time.time()
Exemple #25
0
    def initialize(self):
        # Initialize...
        if self.settings.get('auto_brightness') is None:
            self.settings['auto_brightness'] = False
        if self.settings.get('eye color') is None:
            self.settings['eye color'] = "default"
        if self.settings.get('auto_dim_eyes') is None:
            self.settings['auto_dim_eyes'] = 'false'
        if self.settings.get('use_listenting_beep') is None:
            self.settings['use_listening_beep'] = 'true'

        self.brightness_dict = self.translate_namedvalues('brightness.levels')
        self.color_dict = self.translate_namedvalues('colors')

        try:
            # Handle changing the eye color once Mark 1 is ready to go
            # (Part of the statup sequence)
            self.add_event('mycroft.internet.connected',
                           self.handle_internet_connected)

            # Handle the 'waking' visual
            self.add_event('recognizer_loop:record_begin',
                           self.handle_listener_started)
            self.start_idle_check()

            # Handle the 'busy' visual
            self.emitter.on('mycroft.skill.handler.start',
                            self.on_handler_started)
            self.emitter.on('mycroft.skill.handler.complete',
                            self.on_handler_complete)

            self.emitter.on('recognizer_loop:audio_output_start',
                            self.on_handler_interactingwithuser)
            self.emitter.on('enclosure.mouth.think',
                            self.on_handler_interactingwithuser)
            self.emitter.on('enclosure.mouth.events.deactivate',
                            self.on_handler_interactingwithuser)
            self.emitter.on('enclosure.mouth.text',
                            self.on_handler_interactingwithuser)
        except:
            pass

        # TODO: Add MycroftSkill.register_entity_list() and use the
        #  self.color_dict.keys() instead of duplicating data
        self.register_entity_file('color.entity')

        if connected():
            # Connected at startup: setting eye color
            self.enclosure.mouth_reset()
            self.set_eye_color(self.settings['eye color'], initing=True)

        # Update use of wake-up beep
        self._sync_wake_beep_setting()

        self.settings.set_changed_callback(self.on_websettings_changed)
Exemple #26
0
    def _do_net_check(self):
        # give system 5 seconds to resolve network or get plugged in
        sleep(5)

        LOG.info("Checking internet connection again")
        if not connected() and self.conn_monitor is None:
            # TODO: Enclosure/localization
            self._speak_and_show(
                "This device is not connected to the Internet. Either plug "
                "in a network cable or hold the button on top for two "
                "seconds, then select wifi from the menu", None)
Exemple #27
0
    def _do_net_check(self):
        # give system 5 seconds to resolve network or get plugged in
        sleep(5)

        LOG.info("Checking internet connection again")
        if not connected() and self.conn_monitor is None:
            # TODO: Enclosure/localization
            self._speak_and_show(
                "This device is not connected to the Internet. Either plug "
                "in a network cable or hold the button on top for two "
                "seconds, then select wifi from the menu", None)
Exemple #28
0
def check_connection():
    if connected():
        ws.emit(Message('mycroft.internet.connected'))
        # check for pairing, if not automatically start pairing
        if not is_paired():
            # begin the process
            payload = {'utterances': ["pair my device"], 'lang': "en-us"}
            ws.emit(Message("recognizer_loop:utterance", payload))
    else:
        thread = Timer(1, check_connection)
        thread.daemon = True
        thread.start()
Exemple #29
0
    def from_ip(self, update=True):
        self.log.info("Retrieving location data from ip adress")
        if connected():
            response = unirest.get("https://ipapi.co/json/")
            city = response.body.get("city")
            region_code = response.body.get("region_code")
            country = response.body.get("country")
            country_name = response.body.get("country_name")
            region = response.body.get("region")
            lon = response.body.get("longitude")
            lat = response.body.get("latitude")
            timezone = response.body.get("timezone")

            region_data = {
                "code": region_code,
                "name": region,
                "country": {
                    "code": country,
                    "name": country_name
                }
            }
            city_data = {
                "code": city,
                "name": city,
                "state": region_data,
                "region": region_data
            }
            timezone_data = {
                "code": timezone,
                "name": timezone,
                "dstOffset": 3600000,
                "offset": -21600000
            }
            coordinate_data = {"latitude": float(lat), "longitude": float(lon)}
            location_data = {
                "city": city_data,
                "coordinate": coordinate_data,
                "timezone": timezone_data
            }
            config = {"location": location_data}
            if update:
                try:
                    # jarbas core skill function
                    self.config_update(config)
                except:
                    pass
            return config
        else:
            self.log.warning("No internet connection, could not update "
                             "location from ip adress")
            return {}
Exemple #30
0
 def handle_update_intent(self, message):
     if connected():
         # TODO source select from utterance
         source = self.settings["update_source"]
         self.speak("updating location from " +
                    source.replace("-", " ").replace("_", " "))
         self.update_location(source)
         city = self.location.get("city", {}).get("name", "unknown city")
         country = self.location.get("city", {}).get("state", {}).get(
             "country", {}).get("name", "unknown country")
         text = self.location.get("address", city + ", " + country)
         self.speak(text)
     else:
         self.speak("Cant do that offline")
Exemple #31
0
    def process(self, audio):
        SessionManager.touch()
        payload = {
            'utterance': self.mycroft_recognizer.key_phrase,
            'session': SessionManager.get().session_id,
        }
        self.emitter.emit("recognizer_loop:wakeword", payload)

        if self._audio_length(audio) < self.MIN_AUDIO_SIZE:
            LOG.warn("Audio too short to be processed")
        elif connected():
            self.transcribe(audio)
        else:
            self.__speak("Mycroft seems not to be connected to the Internet")
Exemple #32
0
def install_default_skills(speak=True):
    if exists(MSM_BIN):
        p = subprocess.Popen(MSM_BIN + " default", stderr=subprocess.STDOUT,
                             stdout=subprocess.PIPE, shell=True)
        t = p.communicate()[0]
        if t.splitlines()[-1] == "Installed!" and speak:
            ws.emit(Message("speak", {
                'utterance': mycroft.dialog.get("skills updated")}))
        elif not connected():
            ws.emit(Message("speak", {
                'utterance': mycroft.dialog.get("no network connection")}))

    else:
        logger.error("Unable to invoke Mycroft Skill Manager: " + MSM_BIN)
Exemple #33
0
def check_connection():
    if connected():
        ws.emit(Message('mycroft.internet.connected'))
        # check for pairing, if not automatically start pairing
        if not is_paired():
            # begin the process
            payload = {
                'utterances': ["pair my device"],
                'lang': "en-us"
            }
            ws.emit(Message("recognizer_loop:utterance", payload))
    else:
        thread = Timer(1, check_connection)
        thread.daemon = True
        thread.start()
Exemple #34
0
    def on_arduino_responded(self, event=None):
        self.eyes = EnclosureEyes(self.bus, self.writer)
        self.mouth = EnclosureMouth(self.bus, self.writer)
        self.system = EnclosureArduino(self.bus, self.writer)
        self.__register_events()
        self.__reset()
        self.arduino_responded = True

        # verify internet connection and prompt user on bootup if needed
        if not connected():
            # We delay this for several seconds to ensure that the other
            # clients are up and connected to the messagebus in order to
            # receive the "speak".  This was sometimes happening too
            # quickly and the user wasn't notified what to do.
            Timer(5, self._do_net_check).start()
Exemple #35
0
    def process(self, audio):
        SessionManager.touch()
        payload = {
            'utterance': self.mycroft_recognizer.key_phrase,
            'session': SessionManager.get().session_id,
        }
        self.emitter.emit("recognizer_loop:wakeword", payload)

        if self._audio_length(audio) < self.MIN_AUDIO_SIZE:
            LOG.warn("Audio too short to be processed")
            self.emitter.emit("recognizer_loop:tooshort", {})
        elif connected():
            self.transcribe(audio)
        else:
            self.__speak("Mycroft seems not to be connected to the Internet")
    def on_arduino_responded(self, event=None):
    #    self.eyes = EnclosureEyes(self.bus, self.writer)
    #    self.mouth = EnclosureMouth(self.bus, self.writer)
        self.system = EnclosureArduino(self.bus, self.writer)
        self.__register_events()
        self.__reset()
        self.arduino_responded = True

        # verify internet connection and prompt user on bootup if needed
        if not connected():
            # We delay this for several seconds to ensure that the other
            # clients are up and connected to the messagebus in order to
            # receive the "speak".  This was sometimes happening too
            # quickly and the user wasn't notified what to do.
            Timer(5, self._do_net_check).start()
def _starting_up():
    """
        Start loading skills.
        Starts
        - SkillManager to load/reloading of skills when needed
        - a timer to check for internet connection
        - adapt intent service
        - padatious intent service
    """
    global bus, skill_manager, event_scheduler, connect_to_mycroft_backend

    bus.on('intent_failure', FallbackSkill.make_intent_failure_handler(bus))

    # Create the Intent manager, which converts utterances to intents
    # This is the heart of the voice invoked skill system
    service = IntentService(bus)
    try:
        PadatiousService(bus, service)
    except Exception as e:
        LOG.exception('Failed to create padatious handlers '
                      '({})'.format(repr(e)))
    event_scheduler = EventScheduler(bus)

    # Create a thread that monitors the loaded skills, looking for updates
    try:
        skill_manager = SkillManager(bus)
    except MsmException:
        # skill manager couldn't be created, wait for network connection and
        # retry
        LOG.info(
            'Msm is uninitialized and requires network connection',
            'to fetch skill information\n'
            'Waiting for network connection...')
        while not connected():
            time.sleep(30)
        skill_manager = SkillManager(bus)

    skill_manager.daemon = True
    # Wait until priority skills have been loaded before checking
    # network connection
    # print(skill_manager.msm.repo.get_default_skill_names())
    skill_manager.load_priority()
    skill_manager.start()
    bus.emit(Message('skill.manager.initialised'))
    if connect_to_mycroft_backend:
        check_connection()
    else:
        check_connection_without_backend()
Exemple #38
0
def check_connection():
    """
        Check for network connection. If not paired trigger pairing.
        Runs as a Timer every second until connection is detected.
    """
    if connected():
        ws.emit(Message('mycroft.internet.connected'))
        # check for pairing, if not automatically start pairing
        if not is_paired():
            # begin the process
            payload = {'utterances': ["pair my device"], 'lang': "en-us"}
            ws.emit(Message("recognizer_loop:utterance", payload))
    else:
        thread = Timer(1, check_connection)
        thread.daemon = True
        thread.start()
Exemple #39
0
def skills_manager(message):
    global skills_manager_timer, ws

    if connected():
        if skills_manager_timer is None:
            ws.emit(
                Message("speak", {'utterance':
                        mycroft.dialog.get("checking for updates")}))

        # Install default skills and look for updates via Github
        logger.debug("==== Invoking Mycroft Skill Manager: " + MSM_BIN)
        install_default_skills(False)

    # Perform check again once and hour
    skills_manager_timer = Timer(3600, _skills_manager_dispatch)
    skills_manager_timer.daemon = True
    skills_manager_timer.start()
Exemple #40
0
    def __init__(self):
        super().__init__()

        # Notifications from mycroft-core
        self.bus.on("enclosure.notify.no_internet", self.on_no_internet)

        # initiates the web sockets on display manager
        # NOTE: this is a temporary place to connect the display manager
        init_display_manager_bus_connection()

        # verify internet connection and prompt user on bootup if needed
        if not connected():
            # We delay this for several seconds to ensure that the other
            # clients are up and connected to the messagebus in order to
            # receive the "speak".  This was sometimes happening too
            # quickly and the user wasn't notified what to do.
            Timer(5, self._do_net_check).start()
Exemple #41
0
    def __init__(self):
        super().__init__()

        # Notifications from mycroft-core
        self.bus.on("enclosure.notify.no_internet", self.on_no_internet)

        # initiates the web sockets on display manager
        # NOTE: this is a temporary place to connect the display manager
        init_display_manager_bus_connection()

        # verify internet connection and prompt user on bootup if needed
        if not connected():
            # We delay this for several seconds to ensure that the other
            # clients are up and connected to the messagebus in order to
            # receive the "speak".  This was sometimes happening too
            # quickly and the user wasn't notified what to do.
            Timer(5, self._do_net_check).start()
Exemple #42
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':
                                     mycroft.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': mycroft.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': mycroft.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)
Exemple #43
0
def skills_manager(message):
    global skills_manager_timer, ws

    if connected():
        if skills_manager_timer is None:
            pass
            # ws.emit(
            #     Message("speak", {'utterance':
            #             mycroft.dialog.get("checking for updates")}))

        # Install default skills and look for updates via Github
        logger.debug("==== Invoking Mycroft Skill Manager: " + MSM_BIN)
        install_default_skills(False)

    # Perform check again once and hour
    skills_manager_timer = Timer(3600, _skills_manager_dispatch)
    skills_manager_timer.daemon = True
    skills_manager_timer.start()
Exemple #44
0
    def run(self):
        try:
            # When the system first boots up, check for a valid internet
            # connection.
            LOG.info("Checking internet connection")
            if not connected():
                LOG.info("No connection initially, waiting 20...")
                self.net_check = threading.Thread(
                    target=self._do_net_check,
                    args={})
                self.net_check.daemon = True
                self.net_check.start()
            else:
                LOG.info("Connection found!")

            self.ws.run_forever()
        except Exception as e:
            LOG.error("Error: {0}".format(e))
            self.stop()
Exemple #45
0
    def on_no_internet(self, event=None):
        if connected():
            # One last check to see if connection was established
            return

        if time.time() - Enclosure._last_internet_notification < 30:
            # don't bother the user with multiple notifications with 30 secs
            return

        Enclosure._last_internet_notification = time.time()

        # TODO: This should go into EnclosureMark1 subclass of Enclosure.
        if has_been_paired():
            # Handle the translation within that code.
            self.bus.emit(Message("speak", {
                'utterance': "This device is not connected to the Internet. "
                             "Either plug in a network cable or set up your "
                             "wifi connection."}))
        else:
            # enter wifi-setup mode automatically
            self.bus.emit(Message('system.wifi.setup', {'lang': self.lang}))
Exemple #46
0
def _starting_up():
    """
        Start loading skills.

        Starts
        - SkillManager to load/reloading of skills when needed
        - a timer to check for internet connection
        - adapt intent service
        - padatious intent service
    """
    global bus, skill_manager, event_scheduler

    bus.on('intent_failure', FallbackSkill.make_intent_failure_handler(bus))

    # Create the Intent manager, which converts utterances to intents
    # This is the heart of the voice invoked skill system

    service = IntentService(bus)
    PadatiousService(bus, service)
    event_scheduler = EventScheduler(bus)

    # Create a thread that monitors the loaded skills, looking for updates
    try:
        skill_manager = SkillManager(bus)
    except MsmException:
        # skill manager couldn't be created, wait for network connection and
        # retry
        LOG.info('Msm is uninitialized and requires network connection',
                 'to fetch skill information\n'
                 'Waiting for network connection...')
        while not connected():
            time.sleep(30)
        skill_manager = SkillManager(bus)

    skill_manager.daemon = True
    # Wait until priority skills have been loaded before checking
    # network connection
    skill_manager.load_priority()
    skill_manager.start()
    check_connection()
    def on_no_internet(self, event=None):
        if connected():
            # One last check to see if connection was established
            return

        if time.time()-Enclosure._last_internet_notification < 30:
            # don't bother the user with multiple notifications with 30 secs
            return

        Enclosure._last_internet_notification = time.time()

        # TODO: This should go into EnclosureMark1 subclass of Enclosure.
        if has_been_paired():
            # Handle the translation within that code.
            self.ws.emit(Message("speak", {
                'utterance': "This device is not connected to the Internet. "
                             "Either plug in a network cable or hold the "
                             "button on top for two seconds, then select "
                             "wifi from the menu"}))
        else:
            # enter wifi-setup mode automatically
            self.ws.emit(Message("mycroft.wifi.start"))
Exemple #48
0
def check_connection():
    """
        Check for network connection. If not paired trigger pairing.
        Runs as a Timer every second until connection is detected.
    """
    if connected():
        ws.emit(Message('mycroft.internet.connected'))
        # check for pairing, if not automatically start pairing
        if not is_paired():
            # begin the process
            payload = {
                'utterances': ["pair my device"],
                'lang': "en-us"
            }
            ws.emit(Message("recognizer_loop:utterance", payload))
        else:
            from mycroft.api import DeviceApi
            api = DeviceApi()
            api.update_version()
    else:
        thread = Timer(1, check_connection)
        thread.daemon = True
        thread.start()
def install_default_skills(speak=True):
    """
        Install default skill set using msm.

        Args:
            speak (optional): Enable response for success. Default True
    """
    if exists(MSM_BIN):
        res = subprocess.call(MSM_BIN + " default", stderr=subprocess.STDOUT,
                              stdout=subprocess.PIPE, shell=True)
        if res == 0 and speak:
            # ws.emit(Message("speak", {
            #     'utterance': mycroft.dialog.get("skills updated")}))
            pass
        elif not connected():
            ws.emit(Message("speak", {
                'utterance': mycroft.dialog.get("no network connection")}))
        elif res != 0:
            ws.emit(Message("speak", {
                'utterance': mycroft.dialog.get(
                             "sorry I couldn't install default skills")}))

    else:
        logger.error("Unable to invoke Mycroft Skill Manager: " + MSM_BIN)
Exemple #50
0
def check_connection():
    """
        Check for network connection. If not paired trigger pairing.
        Runs as a Timer every second until connection is detected.
    """
    if connected():
        enclosure = EnclosureAPI(ws)

        if is_paired():
            # Skip the sync message when unpaired because the prompt to go to
            # home.mycrof.ai will be displayed by the pairing skill
            enclosure.mouth_text(mycroft.dialog.get("message_synching.clock"))
        # Force a sync of the local clock with the internet
        ws.emit(Message("system.ntp.sync"))
        time.sleep(15)   # TODO: Generate/listen for a message response...

        # Check if the time skewed significantly.  If so, reboot
        skew = abs((monotonic.monotonic() - start_ticks) -
                   (time.time() - start_clock))
        if skew > 60*60:
            # Time moved by over an hour in the NTP sync. Force a reboot to
            # prevent weird things from occcurring due to the 'time warp'.
            #
            ws.emit(Message("speak", {'utterance':
                    mycroft.dialog.get("time.changed.reboot")}))
            wait_while_speaking()

            # provide visual indicators of the reboot
            enclosure.mouth_text(mycroft.dialog.get("message_rebooting"))
            enclosure.eyes_color(70, 65, 69)  # soft gray
            enclosure.eyes_spin()

            # give the system time to finish processing enclosure messages
            time.sleep(1.0)

            # reboot
            ws.emit(Message("system.reboot"))
            return

        ws.emit(Message('mycroft.internet.connected'))
        # check for pairing, if not automatically start pairing
        if not is_paired():
            # begin the process
            payload = {
                'utterances': ["pair my device"],
                'lang': "en-us"
            }
            ws.emit(Message("recognizer_loop:utterance", payload))
        else:
            if is_paired():
                # Skip the  message when unpaired because the prompt to go
                # to home.mycrof.ai will be displayed by the pairing skill
                enclosure.mouth_text(mycroft.dialog.get("message_updating"))

            from mycroft.api import DeviceApi
            api = DeviceApi()
            api.update_version()
    else:
        thread = Timer(1, check_connection)
        thread.daemon = True
        thread.start()
Exemple #51
0
def check_connection():
    """
        Check for network connection. If not paired trigger pairing.
        Runs as a Timer every second until connection is detected.
    """
    if connected():
        enclosure = EnclosureAPI(bus)

        if is_paired():
            # Skip the sync message when unpaired because the prompt to go to
            # home.mycrof.ai will be displayed by the pairing skill
            enclosure.mouth_text(dialog.get("message_synching.clock"))

        # Force a sync of the local clock with the internet
        config = Configuration.get()
        platform = config['enclosure'].get("platform", "unknown")
        if platform in ['mycroft_mark_1', 'picroft']:
            bus.wait_for_response(Message('system.ntp.sync'),
                                  'system.ntp.sync.complete', 15)

        if not is_paired():
            try_update_system(platform)

        # Check if the time skewed significantly.  If so, reboot
        skew = abs((time.monotonic() - start_ticks) -
                   (time.time() - start_clock))
        if skew > 60 * 60:
            # Time moved by over an hour in the NTP sync. Force a reboot to
            # prevent weird things from occcurring due to the 'time warp'.
            #
            data = {'utterance': dialog.get("time.changed.reboot")}
            bus.emit(Message("speak", data))
            wait_while_speaking()

            # provide visual indicators of the reboot
            enclosure.mouth_text(dialog.get("message_rebooting"))
            enclosure.eyes_color(70, 65, 69)  # soft gray
            enclosure.eyes_spin()

            # give the system time to finish processing enclosure messages
            time.sleep(1.0)

            # reboot
            bus.emit(Message("system.reboot"))
            return
        else:
            bus.emit(Message("enclosure.mouth.reset"))
            time.sleep(0.5)

        enclosure.eyes_color(189, 183, 107)  # dark khaki
        enclosure.mouth_text(dialog.get("message_loading.skills"))

        bus.emit(Message('mycroft.internet.connected'))
        # check for pairing, if not automatically start pairing
        try:
            if not is_paired(ignore_errors=False):
                payload = {
                    'utterances': ["pair my device"],
                    'lang': "en-us"
                }
                bus.emit(Message("recognizer_loop:utterance", payload))
            else:
                from mycroft.api import DeviceApi
                api = DeviceApi()
                api.update_version()
        except BackendDown:
            data = {'utterance': dialog.get("backend.down")}
            bus.emit(Message("speak", data))
            bus.emit(Message("backend.down"))

    else:
        thread = Timer(1, check_connection)
        thread.daemon = True
        thread.start()
    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
        """
        if not connected():
            LOG.error('msm failed, network connection not available')
            if speak:
                self.bus.emit(Message("speak", {
                    'utterance': dialog.get(
                        "not connected to the internet")}))
            self.next_download = time.time() + 5 * MINUTES
            return False

        installed_skills = self.load_installed_skills()
        msm = SkillManager.create_msm()
        with msm.lock, self.thread_lock:
            default_groups = dict(msm.repo.get_default_skill_names())
            if msm.platform in default_groups:
                platform_groups = default_groups[msm.platform]
            else:
                LOG.info('Platform defaults not found, using DEFAULT '
                         'skills only')
                platform_groups = []
            default_names = set(chain(default_groups['default'],
                                      platform_groups))
            default_skill_errored = False

            def get_skill_data(skill_name):
                """ Get skill data structure from name. """
                for e in msm.skills_data.get('skills', []):
                    if e.get('name') == skill_name:
                        return e
                # if skill isn't in the list return empty structure
                return {}

            def install_or_update(skill):
                """Install missing defaults and update existing skills"""
                if get_skill_data(skill.name).get('beta'):
                    skill.sha = None  # Will update to latest head
                if skill.is_local:
                    skill.update()
                    if skill.name not in installed_skills:
                        skill.update_deps()
                elif skill.name in default_names:
                    try:
                        msm.install(skill, origin='default')
                    except Exception:
                        if skill.name in default_names:
                            LOG.warning('Failed to install default skill: ' +
                                        skill.name)
                            nonlocal default_skill_errored
                            default_skill_errored = True
                        raise
                installed_skills.add(skill.name)
            try:
                msm.apply(install_or_update, msm.list())
                if SkillManager.manifest_upload_allowed and is_paired():
                    try:
                        DeviceApi().upload_skills_data(msm.skills_data)
                    except Exception:
                        LOG.exception('Could not upload skill manifest')

            except MsmException as e:
                LOG.error('Failed to update skills: {}'.format(repr(e)))

        self.save_installed_skills(installed_skills)

        if speak:
            data = {'utterance': dialog.get("skills updated")}
            self.bus.emit(Message("speak", data))

        if default_skill_errored and self.num_install_retries < 10:
            self.num_install_retries += 1
            self.next_download = time.time() + 5 * MINUTES
            return False
        self.num_install_retries = 0

        with open(self.dot_msm, 'a'):
            os.utime(self.dot_msm, None)
        self.next_download = time.time() + self.update_interval

        return True
    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
        """
        if not connected():
            LOG.error('msm failed, network connection not available')
            if speak:
                self.bus.emit(Message("speak", {
                    'utterance': dialog.get(
                        "not connected to the internet")}))
            self.next_download = time.time() + 5 * MINUTES
            return False

        installed_skills = self.load_installed_skills()
        default_groups = dict(self.msm.repo.get_default_skill_names())
        if self.msm.platform in default_groups:
            platform_groups = default_groups[self.msm.platform]
        else:
            LOG.info('Platform defaults not found, using DEFAULT skills only')
            platform_groups = []
        default_names = set(chain(default_groups['default'], platform_groups))
        default_skill_errored = False

        skills_data = self.load_skills_data()

        new_installs = []
        updated_skills = []

        def install_or_update(skill):
            """Install missing defaults and update existing skills"""
            if skills_data.get(skill.name, {}).get('beta'):
                skill.sha = None  # Will update to latest version
            if skill.is_local:
                skill.update()
                updated_skills.append(skill.name)
                if skill.name not in installed_skills:
                    skill.update_deps()
                    installed_skills.add(skill.name)
            elif skill.name in default_names:
                try:
                    new_installs.append(skill.name)
                    skill.install()
                except Exception:
                    if skill.name in default_names:
                        LOG.warning(
                            'Failed to install default skill: ' + skill.name
                        )
                        nonlocal default_skill_errored
                        default_skill_errored = True
                    raise
                installed_skills.add(skill.name)

        try:
            self.msm.apply(install_or_update, self.msm.list())
        except MsmException as e:
            LOG.error('Failed to update skills: {}'.format(repr(e)))

        for skill_name in new_installs + updated_skills:
            if skill_name not in skills_data or skill_name in new_installs:
                t = time.time() if skill_name in new_installs else 1
                skills_data.setdefault(skill_name, {})['installed'] = t
                skills_data[skill_name]['updated'] = 0

        self.write_skills_data(skills_data)
        self.save_installed_skills(installed_skills)

        if speak:
            data = {'utterance': dialog.get("skills updated")}
            self.bus.emit(Message("speak", data))

        if default_skill_errored and self.num_install_retries < 10:
            self.num_install_retries += 1
            self.next_download = time.time() + 5 * MINUTES
            return False
        self.num_install_retries = 0

        with open(self.dot_msm, 'a'):
            os.utime(self.dot_msm, None)
        self.next_download = time.time() + self.update_interval

        return True