def get_neon_skills_config() -> dict: """ Get a configuration dict for the skills module. Merge any values from Mycroft config if missing from Neon. Returns: dict of config params used for the Mycroft Skills module """ core_config = get_neon_local_config() mycroft_config = _safe_mycroft_config() neon_skills = deepcopy(core_config.get("skills", {})) neon_skills["directory"] = os.path.expanduser(core_config["dirVars"].get("skillsDir")) neon_skills["disable_osm"] = neon_skills["skill_manager"] != "osm" if not isinstance(neon_skills["auto_update_interval"], float): try: neon_skills["auto_update_interval"] = float(neon_skills["auto_update_interval"]) except Exception as e: LOG.error(e) neon_skills["auto_update_interval"] = 24.0 if not isinstance(neon_skills["appstore_sync_interval"], float): try: neon_skills["appstore_sync_interval"] = float(neon_skills["appstore_sync_interval"]) except Exception as e: LOG.error(e) neon_skills["appstore_sync_interval"] = 6.0 neon_skills["update_interval"] = neon_skills["auto_update_interval"] # Backwards Compat. if not neon_skills["neon_token"]: try: neon_skills["neon_token"] = find_neon_git_token() # TODO: GetPrivateKeys populate_github_token_config(neon_skills["neon_token"]) except FileNotFoundError: LOG.warning(f"No Github token found; skills may fail to install!") skills_config = {**mycroft_config.get("skills", {}), **neon_skills} return skills_config
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)))
def get_coordinates(gps_loc: dict) -> (float, float): """ Gets the latitude and longitude for the passed location :param gps_loc: dict of "city", "state", "country" :return: lat, lng float values """ coordinates = Nominatim(user_agent="neon-ai") try: location = coordinates.geocode(gps_loc) LOG.debug(f"{location}") return location.latitude, location.longitude except Exception as x: LOG.error(x) return -1, -1
def encode_file_to_base64_string(path: str) -> str: """ Encodes a file to a base64 string (useful for passing file data over a messagebus) :param path: Path to file to be encoded :return: encoded string """ if not isinstance(path, str): raise TypeError path = os.path.expanduser(path) if not os.path.isfile(path): LOG.error(f"File Not Found: {path}") raise FileNotFoundError with open(path, "rb") as file_in: encoded = base64.b64encode(file_in.read()).decode("utf-8") return encoded
def _write_yaml_file(self): """ Overwrites and/or updates the YML at the specified file_path. """ try: with self.lock: tmp_filename = join(self.path, f".{self.name}.tmp") LOG.debug(f"tmp_filename={tmp_filename}") shutil.copy2(self.file_path, tmp_filename) with open(self.file_path, 'w+') as f: self.parser.dump(self._content, f) LOG.debug(f"YAML updated {self.name}") self._loaded = os.path.getmtime(self.file_path) self._pending_write = False self._disk_content_hash = hash(repr(self._content)) except FileNotFoundError as x: LOG.error(f"Configuration file not found error: {x}")
def _load_yaml_file(self) -> dict: """ Loads and parses the YAML file at a given filepath into the Python dictionary object. :return: dictionary, containing all keys and values from the most current selected YAML. """ try: self._loaded = os.path.getmtime(self.file_path) with self.lock: with open(self.file_path, 'r') as f: return self.parser.load(f) or dict() except FileNotFoundError as x: LOG.error(f"Configuration file not found error: {x}") except Exception as c: LOG.error(f"{self.file_path} Configuration file error: {c}") return dict()
def check_for_updates(self) -> dict: """ Reloads updated configuration from disk. Used to reload changes when other instances modify a configuration Returns:Updated configuration.content """ new_content = self._load_yaml_file() if new_content: LOG.debug(f"{self.name} Checked for Updates") self._content = new_content else: LOG.error("new_content is empty!!") new_content = self._load_yaml_file() if new_content: LOG.debug("second attempt success") self._content = new_content else: LOG.error("second attempt failed") return self._content
def decode_base64_string_to_file(encoded_string: str, output_path: str) -> str: """ Writes out a base64 string to a file object at the specified path :param encoded_string: Base64 encoded string :param output_path: Path to file to write (throws exception if file exists) :return: Path to output file """ if not isinstance(output_path, str): raise TypeError output_path = os.path.expanduser(output_path) if os.path.isfile(output_path): LOG.error(f"File already exists: {output_path}") raise FileExistsError ensure_directory_exists(os.path.dirname(output_path)) with open(output_path, "wb+") as file_out: byte_data = base64.b64decode(encoded_string.encode("utf-8")) file_out.write(byte_data) return output_path
def get_neon_cli_config() -> dict: """ Get a configuration dict for the neon_cli Returns: dict of config params used by the neon_cli """ local_config = NGIConfig("ngi_local_conf").content wake_words_enabled = local_config.get("interface", {}).get("wake_word_enabled", True) try: neon_core_version = os.path.basename(glob(local_config['dirVars']['ngiDir'] + '/*.release')[0]).split('.release')[0] except Exception as e: LOG.error(e) neon_core_version = "Unknown" log_dir = local_config.get("dirVars", {}).get("logsDir", "/var/log/mycroft") return {"neon_core_version": neon_core_version, "wake_words_enabled": wake_words_enabled, "log_dir": log_dir}
def update_yaml_file(self, header=None, sub_header=None, value="", multiple=False, final=False): """ Called by class's children to update, create, or initiate a new parameter in the specified YAML file. Creates and updates headers, adds or overwrites preference elements, associates value to the created or existing field. Recursive if creating a new header-preference-value combo. :param multiple: true if more than one continuous write is coming :param header: string with the new or existing main header :param sub_header: new or existing subheader (sublist) :param value: any value that should be associated with the headers. :param final: true if this is the last change when skip_reload was true :return: pre-existing parameter if nothing to update or error if invalid yaml_type. """ # with self.lock.acquire(30): self.check_reload() before_change = self._content LOG.debug(value) if header and sub_header: try: before_change[header][sub_header] = value except KeyError: before_change[header] = {sub_header: value} return elif header and not sub_header: try: before_change[header] = value except Exception as x: LOG.error(x) else: LOG.debug("No change needed") if not final: return if not multiple: self._write_yaml_file() else: LOG.debug("More than one change") self._pending_write = True