def load_deprecated_info(self): """ Load info from smartVISU which widgets have been deprecated or removed """ self.deprecated_widgets = [] self.removed_widgets = [] self.deprecated_plugin_widgets = [] filename = os.path.join(self.smartvisu_dir, 'widgets', 'deprecated.yaml') dep_warnings = shyaml.yaml_load(filename, ordered=False, ignore_notfound=True) if dep_warnings is None: #load deprecated warnings for older versions of smartvisu if self.smartvisu_version.startswith('2.9'): filename = os.path.join(self.get_plugin_dir(), 'deprecated_29.yaml') dep_warnings = shyaml.yaml_load(filename, ordered=False, ignore_notfound=True) if dep_warnings is not None: self.logger.info( "Using deprecated info from file '{}' for smartVISU v{}". format(filename, self.smartvisu_version)) self.deprecated_widgets = dep_warnings.get('deprecated', []) self.removed_widgets = dep_warnings.get('removed', [])
def read(self, id=None): """ Handle GET requests """ self.logger.info("ConfigController.read(): config = {}".format(id)) self.core_confdata = shyaml.yaml_load(os.path.join(self.etc_dir, 'smarthome.yaml')) self.read_holidays() self.module_confdata = shyaml.yaml_load(os.path.join(self.etc_dir, 'module.yaml')) result = {} if (not id) or id == 'core': result['common'] = {} result['common']['data'] = self.core_confdata result['common']['meta'] = self.core_conf result['http'] = {} result['http']['data'] = self.module_confdata.get('http', {}) result['http']['meta'] = self.http_conf result['admin'] = {} result['admin']['data'] = self.module_confdata.get('admin', {}) result['admin']['meta'] = self.admin_conf result['mqtt'] = {} result['mqtt']['data'] = self.module_confdata.get('mqtt', {}) if result['mqtt']['data'].get('enabled', None) is None: result['mqtt']['data']['enabled'] = True result['mqtt']['meta'] = self.mqtt_conf self.logger.info(" - index: core = {}".format(result)) return json.dumps(result) if id == 'common': result['data'] = self.core_confdata result['meta'] = self.core_conf self.logger.info(" - index: common = {}".format(result)) return json.dumps(result) if id == 'http': result['data'] = self.module_confdata.get('http', {}) result['meta'] = self.http_conf self.logger.info(" - index: http = {}".format(result)) return json.dumps(result) if id == 'admin': result['data'] = self.module_confdata.get('admin', {}) result['meta'] = self.admin_conf self.logger.info(" - index: admin = {}".format(result)) return json.dumps(result) if id == 'mqtt': result['data'] = self.module_confdata.get('mqtt', {}) if result['mqtt']['data'].get('enabled', None) is None: result['mqtt']['data']['enabled'] = True result['meta'] = self.mqtt_conf self.logger.info(" - index: admin = {}".format(result)) return json.dumps(result) raise cherrypy.NotFound
def __init__(self, module): self._sh = module._sh self.module = module self.base_dir = self._sh.get_basedir() self.logger = logging.getLogger(__name__) self.etc_dir = self._sh._etc_dir self.modules_dir = os.path.join(self.base_dir, 'modules') self.core_conf = shyaml.yaml_load(os.path.join(self.modules_dir, 'core', 'module.yaml')) self.http_conf = shyaml.yaml_load(os.path.join(self.modules_dir, 'http', 'module.yaml')) self.admin_conf = shyaml.yaml_load(os.path.join(self.modules_dir, 'admin', 'module.yaml')) self.mqtt_conf = shyaml.yaml_load(os.path.join(self.modules_dir, 'mqtt', 'module.yaml')) return
def read_holidays(self): self.holidays_confdata = shyaml.yaml_load( os.path.join(self.etc_dir, 'holidays.yaml')) if self.holidays_confdata.get('location', None) is not None: self.core_confdata['holidays_country'] = self.holidays_confdata[ 'location'].get('country', '') self.core_confdata['holidays_province'] = self.holidays_confdata[ 'location'].get('province', '') self.core_confdata['holidays_state'] = self.holidays_confdata[ 'location'].get('state', '') for i in range(1, 6): self.core_confdata['holidays_custom' + str(i)] = '' try: for i in range(1, 6): if isinstance(self.holidays_confdata['custom'][i - 1], dict): self.core_confdata['holidays_custom' + str(i)] = json.dumps( self.holidays_confdata['custom'][i - 1]) else: self.core_confdata[ 'holidays_custom' + str(i)] = self.holidays_confdata['custom'][i - 1] except: pass return
def load_struct_definitions(self, etc_dir): # -------------------------------------------------------------------- # Read in all struct definitions before reading item definitions # # structs are merged into the item tree in lib.config # # structs are read in from metadata file of plugins while loading plugins # and from ../etc/struct.yaml # # Read in item structs from ../etc/struct.yaml struct_definitions = shyaml.yaml_load(os.path.join( etc_dir, 'struct.yaml'), ordered=True, ignore_notfound=True) if struct_definitions is not None: if isinstance(struct_definitions, collections.OrderedDict): for key in struct_definitions: self.add_struct_definition('', key, struct_definitions[key]) else: self.logger.error( "load_itemdefinitions(): Invalid content in struct.yaml: struct_definitions = '{}'" .format(struct_definitions)) self.fill_nested_structs() # for Testing: Save structure of joined item structs self.logger.info( "load_itemdefinitions(): For testing the joined item structs are saved to {}" .format(os.path.join(etc_dir, 'structs_joined.yaml'))) shyaml.yaml_save(os.path.join(etc_dir, 'structs_joined.yaml'), self._struct_definitions)
def reload_translations(): """ Reload translations for existing translation_ids - to test new translations without having to restart SmartHomeNG """ logger.info("reload_translations") for id in _translation_files: translation_type = _translation_files[id]['type'] filename = _translation_files[id]['filename'] trans_dict = shyaml.yaml_load(filename, ordered=False, ignore_notfound=True) if trans_dict != None: if translation_type == 'global': for translation_section in trans_dict.keys(): if translation_section.endswith('_translations'): id = translation_section.split('_')[0].replace( '.', '/') trans = trans_dict.get(translation_section, {}) logger.info( "Reloading {} translations (id={}) from {}".format( translation_type, id, filename)) _translations[id] = trans else: trans = trans_dict.get(translation_type + '_translations', {}) logger.info("Reloading {} translations (id={}) from {}".format( translation_type, id, filename)) _translations[id] = trans return
def get_logic_info(self, logicname): """ Get code of a logic from file """ config_filename = os.path.join(self.etc_dir, 'logic.yaml') wrk = shyaml.yaml_load(config_filename) logic_conf = wrk.get(logicname, {}) if Utils.get_type(logic_conf.get('watch_item', None)) == 'str': self.logger.info( "get_logic: logicname = '{}', converting watch_item = '{}' to list" .format(logicname, logic_conf['watch_item'])) logic_conf['watch_item'] = [logic_conf['watch_item']] self.logger.info( "get_logic: logicname = '{}', logic_conf = '{}'".format( logicname, logic_conf)) mylogic = self.fill_logicdict(logicname) logic_conf['name'] = mylogic['name'] logic_conf['next_exec'] = mylogic['next_exec'] logic_conf['last_run'] = mylogic['last_run'] # self.logger.warning("type = {}, mylogic = {}".format(type(mylogic), mylogic)) # self.logger.warning("type = {}, logic_conf = {}".format(type(logic_conf), logic_conf)) return json.dumps(logic_conf)
def load_struct_definitions_from_file(self, etc_dir, fn, key_prefix): """ Loads struct definitions from a file :param etc_dir: path to etc directory of SmartHomeNG :param fn: filename to load struct definition(s) from :param key_prefix: prefix to be used when adding struct(s) to loaded definitions """ if key_prefix == '': self.logger.info(f"Loading struct file '{fn}' without key-prefix") else: self.logger.info(f"Loading struct file '{fn}' with key-prefix '{key_prefix}'") # Read in item structs from ../etc/struct.yaml struct_definitions = shyaml.yaml_load(os.path.join(etc_dir, fn), ordered=True, ignore_notfound=True) # if valid struct definition file etc/struct.yaml ist found if struct_definitions is not None: if isinstance(struct_definitions, collections.OrderedDict): for key in struct_definitions: if fn == 'struct.yaml': struct_name = key else: struct_name = key_prefix + '.' + key self.add_struct_definition('', struct_name, struct_definitions[key]) else: self.logger.error(f"load_itemdefinitions(): Invalid content in {fn}: struct_definitions = '{struct_definitions}'") return
def _load_learned_values(self, scene): """ Load learned values for the scene from a file """ scene_learnfile = os.path.join(self._scenes_dir, scene + '_learned') learned_dict = yaml.yaml_load(scene_learnfile + '.yaml', ordered=False, ignore_notfound=True) logger.info("Loading learned values for scene {} from file {}:".format( scene, scene_learnfile)) logger.info(" -> loaded dict learned_dict {}:".format(learned_dict)) if learned_dict is not None: if learned_dict != {}: logger.info( "Loading learned values for scene {}".format(scene)) for fkey in learned_dict: key = scene + '#' + fkey lvalue = learned_dict[fkey] self._learned_values[key] = lvalue logger.debug(" - Loading value {} for state/ditem {}".format( lvalue, key)) logger.info(" -> to dict self._learned_values {}:".format( self._learned_values)) return
def __init__(self, smarthome): self._sh = smarthome global _scenes_instance if _scenes_instance is not None: import inspect curframe = inspect.currentframe() calframe = inspect.getouterframes(curframe, 2) logger.critical("A second 'scenes' object has been created. There should only be ONE instance of class 'Scenes'!!! Called from: {} ({})".format(calframe[1][1], calframe[1][3])) _scenes_instance = self self.items = Items.get_instance() self._scenes = {} self._learned_values = {} self._scenes_dir = smarthome.base_dir + '/scenes/' if not os.path.isdir(self._scenes_dir): logger.warning("Directory scenes not found. Ignoring scenes.".format(self._scenes_dir)) return # for item in smarthome.return_items(): for item in self.items.return_items(): if item.type() == 'scene': scene_file = os.path.join(self._scenes_dir, item.id()) scene_file_yaml = yaml.yaml_load(scene_file+'.yaml', ordered=False, ignore_notfound=True) if scene_file_yaml is not None: # Reading yaml file with scene definition for state in scene_file_yaml: actions = scene_file_yaml[state]['actions'] if isinstance(actions, dict): actions = [ actions ] if isinstance( actions, list ): for action in actions: if isinstance(action, dict): self._add_scene_entry(item, str(state), action.get('item', ''), str(action.get('value', '')), action.get('learn', ''), scene_file_yaml[state].get('name', '')) else: logger.warning("Scene {}, state {}: action '{}' is not a dict".format(item, state, action)) else: logger.warning("Scene {}, state {}: actions are not a list".format(item, state)) self._load_learned_values(str(item.id())) else: # Trying to read conf file with scene definition scene_conf_file = scene_file + '.conf' try: with open(scene_conf_file, 'r', encoding='UTF-8') as f: reader = csv.reader(f, delimiter=' ') for row in reader: if row == []: # ignore empty lines continue if row[0][0] == '#': # ignore comments continue self._add_scene_entry(item, row[0], row[1], row[2]) except Exception as e: logger.warning("Problem reading scene file {0}: {1}".format(scene_file, e)) continue item.add_method_trigger(self._trigger)
def read(self, id=None): """ Handle GET requests for threads API return an object with type info about all installed plugins """ self.logger.info("PluginsController(): read") default_language = self._sh.get_defaultlanguage() if self.plugin_data == {}: plugins_list = sorted(os.listdir(self.plugins_dir)) self.logger.info("- plugins_list_sorted = {}".format(plugins_list)) for p in plugins_list: if not (p[0] in ['.', '_']): if os.path.isfile(os.path.join(self.plugins_dir, p, 'plugin.yaml')): plg_yaml = shyaml.yaml_load(os.path.join(os.path.join(self.plugins_dir, p, 'plugin.yaml'))) if plg_yaml is None: self.logger.warning("- no valid plugin.yaml found for plugin {}".format(p)) else: plg_data = plg_yaml.get('plugin', None) if plg_data is None: self.logger.info("- plugin.yaml has no section 'plugin': {}".format(p)) else: self.plugin_data[p] = plg_data.get('type', '') else: self.logger.info("- no plugin.yaml: {}".format(p)) return json.dumps(self.plugin_data)
def __init__(self, module): self._sh = module._sh self.module = module self.base_dir = self._sh.get_basedir() self.logger = logging.getLogger(__name__) self.etc_dir = self._sh._etc_dir self.log_dir = os.path.join(self.base_dir, 'var', 'log') self.logging_conf = shyaml.yaml_load( os.path.join(self.etc_dir, 'logging.yaml')) self.chunksize = self.module.log_chunksize try: roothandler = self.logging_conf['root']['handlers'][0] self.root_logname = os.path.splitext( os.path.basename( self.logging_conf['handlers'][roothandler]['filename']))[0] except: self.root_logname = '' self.logger.info("logging_conf: self.root_logname = {}".format( self.root_logname)) return
def parse_yaml(filename, config=None, addfilenames=False): """ Load and parse a yaml configuration file and merge it to the configuration tree :param filename: Name of the configuration file :param config: Optional OrderedDict tree, into which the configuration should be merged :type filename: str :type config: bool :return: The resulting merged OrderedDict tree :rtype: OrderedDict The config file should stick to the following setup: .. code-block:: yaml firstlevel: attribute1: xyz attribute2: foo attribute3: bar secondlevel: attribute1: abc attribute2: bar attribute3: foo thirdlevel: attribute1: def attribute2: barfoo attribute3: foobar anothersecondlevel: attribute1: and so on where firstlevel, secondlevel, thirdlevel and anothersecondlevel are defined as items and attribute are their respective attribute - value pairs Valid characters for the items are a-z and A-Z plus any digit and underscore as second or further characters. Valid characters for the attributes are the same as for an item plus @ and * """ logger.debug("parse_yaml: Parsing file {}".format(os.path.basename(filename))) if config is None: config = collections.OrderedDict() items = shyaml.yaml_load(filename, ordered=True) if items is not None: remove_comments(items) remove_digits(items) remove_reserved(items) remove_keyword(items) remove_invalid(items) if addfilenames: logger.debug("parse_yaml: Add filename = {} to items".format(os.path.basename(filename))) _add_filenames_to_config(items, os.path.basename(filename)) config = merge(items, config) return config
def _load_scenes(self): """ Load defined scenes with learned values from ../scene directory :return: """ self._scenes = {} self._learned_values = {} self._scenes_dir = self._sh._scenes_dir if not os.path.isdir(self._scenes_dir): logger.warning(translate("Directory '{scenes_dir}' not found. Ignoring scenes.", {'scenes_dir': self._scenes_dir})) return self._learned_values = {} # for item in smarthome.return_items(): for item in self.items.return_items(): if item.type() == 'scene': self.scene_file = os.path.join(self._scenes_dir, item.id()) scene_file_yaml = yaml.yaml_load(self.scene_file+'.yaml', ordered=False, ignore_notfound=True) if scene_file_yaml is not None: # Reading yaml file with scene definition for state in scene_file_yaml: actions = scene_file_yaml[state].get('actions', None) if actions is not None: if isinstance(actions, dict): actions = [ actions ] if isinstance( actions, list ): for action in actions: if isinstance(action, dict): self._add_scene_entry(item, str(state), action.get('item', ''), str(action.get('value', '')), action.get('learn', ''), scene_file_yaml[state].get('name', '')) else: logger.warning(translate("Scene {scene}, state {state}: action '{action}' is not a dict", {'scene': item, 'state': state, 'action': action})) else: logger.warning(translate("Scene {scene}, state {state}: actions are not a list", {'scene': item, 'state': state})) self._load_learned_values(str(item.id())) else: # Trying to read conf file with scene definition scene_conf_file = self.scene_file + '.conf' try: with open(scene_conf_file, 'r', encoding='UTF-8') as f: reader = csv.reader(f, delimiter=' ') for row in reader: if row == []: # ignore empty lines continue if row[0][0] == '#': # ignore comments continue self._add_scene_entry(item, row[0], row[1], row[2]) except Exception as e: logger.warning(translate("Problem reading scene file {file}: No .yaml or .conf file found with this name", {'file': self.scene_file})) continue item.add_method_trigger(self._trigger) return
def _load_translations(self): """ """ self._gtrans = {} self.relative_filename = os.path.join( 'bin', 'locale'+YAML_FILE ) filename = os.path.join( self._sh.get_basedir(), self.relative_filename ) trans = shyaml.yaml_load(filename, ordered=False, ignore_notfound=True) if trans != None: self._gtrans = trans.get('global_translations', {}) logger.info("Loaded global translations = {}".format(self._gtrans))
def _load_translations(self): """ """ self._gtrans = {} self.relative_filename = os.path.join('bin', 'locale' + YAML_FILE) filename = os.path.join(self._sh.get_basedir(), self.relative_filename) trans = shyaml.yaml_load(filename, ordered=False, ignore_notfound=True) if trans != None: self._gtrans = trans.get('global_translations', {}) logger.info("Loaded global translations = {}".format(self._gtrans))
def load_logging_config(self): """ Load config from logging.yaml to a dict If logging.yaml does not contain a 'shng_version' key, a backup is created """ conf_filename = os.path.join(self.etc_dir, 'logging') result = shyaml.yaml_load(conf_filename + '.yaml') return result
def read_visu_definition(self): from pprint import pformat self.etc_dir = self._sh._etc_dir filename = os.path.join(self.etc_dir, 'visu.yaml') self.visu_definition = shyaml.yaml_load(filename, ordered=False, ignore_notfound=True) return
def test_conf_plugins_requirements(self, plugin_conf_basename, plugins_dir): # import lib.shyaml here, so test_base_requirements() can be run even if ruamel.yaml package is not installed import lib.shyaml as shyaml if not os.path.isfile(plugin_conf_basename + YAML_FILE): self.logger.warning( "Requirments for configured plugins were not checked because the plugin configuration is not in YAML format" ) return True plugin_conf = shyaml.yaml_load(plugin_conf_basename + YAML_FILE, ordered=False) req_dict = {} for plugin_instance in plugin_conf: plugin_name = plugin_conf[plugin_instance].get('plugin_name', None) class_path = plugin_conf[plugin_instance].get('class_path', None) plugin = '' if class_path: if class_path.startswith('plugins.'): sp = class_path.split('.') if len(sp) == 2: plugin = sp[1] if plugin == '' and plugin_name: plugin = plugin_name filename = os.path.join(plugins_dir, plugin, 'requirements.txt') if not os.path.isfile(filename): filename = '' else: if plugin != '': req_dict[plugin] = filename self._conf_plugin_filelist = [] for plugin in req_dict: self._conf_plugin_filelist.append(req_dict[plugin]) #req_files = Requirements_files() self.req_files.set_conf_plugin_files(self._conf_plugin_filelist) self.req_files.create_requirementsfile('conf_all') requirements_met = self.test_requirements( os.path.join(self._sh_dir, 'requirements', 'conf_all.txt'), True) if not requirements_met: self.logger.info( "test_conf_plugins_requirements: Python package requirements for configured plugins not met" ) return requirements_met
def read(self, id=None): """ return an object with data about all installed plugins """ self.logger.info("PluginsInstalledController(): index") if self._sh.shng_status['code'] < 20: self.logger.error("PluginsInstalledController.read(): SmartHomeNG has not yet finished initialization") return json.dumps({}) default_language = self._sh.get_defaultlanguage() if self.plugin_data == {}: plugins_list = sorted(os.listdir(self.plugins_dir)) self.logger.warning("PluginsInstalledController.read(): plugin_list (sollte sortiert sein) = '{}'".format(plugins_list)) self.logger.info("- plugins_list_sorted = {}".format(plugins_list)) for p in plugins_list: if not (p[0] in ['.', '_']): if os.path.isfile(os.path.join(self.plugins_dir, p, 'plugin.yaml')): plg_yaml = shyaml.yaml_load(os.path.join(os.path.join(self.plugins_dir, p, 'plugin.yaml'))) if plg_yaml == None: self.logger.warning("PluginsInstalledController.read(): Plugin '{}': plugin.yaml cannot be read".format(p)) else: plg_data = plg_yaml.get('plugin', None) if plg_data is None: self.logger.info("- plugin.yaml has no section 'plugin': {}".format(p)) else: # self.plugin_data[p] = {} self.plugin_data[p] = collections.OrderedDict() self.plugin_data[p]['type'] = plg_data.get('type', '') description = plg_data.get('description', {'de': '', 'en': ''}) # self.plugin_data[p]['description'] = description.get(default_language, '') # if self.plugin_data[p]['description'] == '': # self.plugin_data[p]['description'] = description[self.fallback_language_order[0]] # if self.plugin_data[p]['description'] == '': # self.plugin_data[p]['description'] = description[self.fallback_language_order[1]] self.plugin_data[p]['description'] = description self.plugin_data[p]['version'] = plg_data.get('version', '') self.plugin_data[p]['state'] = plg_data.get('state', '') self.plugin_data[p]['documentation'] = plg_data.get('documentation', '') self.plugin_data[p]['multi_instance'] = plg_data.get('multi_instance', '') self.plugin_data[p]['configuration_needed'] = plg_data.get('configuration_needed', True) else: self.logger.info("- no plugin.yaml: {}".format(p)) self.logger.warning("PluginsInstalledController.read(): Plugin Liste (sollte sortiert sein), json.dumps(self.plugin_data) = '{}'".format(json.dumps(self.plugin_data))) return json.dumps(self.plugin_data, sort_keys=True)
def _load_learned_values(self, scene): """ Load learned values for the scene from a file """ self._learned_values = {} scene_learnfile = os.path.join(self._scenes_dir, scene+'_learned') learned_dict = yaml.yaml_load(scene_learnfile+'.yaml', ordered=False, ignore_notfound=True) if learned_dict is not None: if learned_dict != {}: logger.info("Loading learned values for scene {}".format(scene)) for fkey in learned_dict: key = scene + '#' + fkey lvalue = learned_dict[fkey] self._learned_values[key] = lvalue logger.debug(" - Loading value {} for state/ditem {}".format(lvalue, key)) return
def load_translations(translation_type='global', from_dir='bin', translation_id='global'): """ Load global or plugin-specific translations from a locale.yaml file :param translation_type: 'global' or 'plugin' :param from_dir: 'bin' (for global) or 'plugins/<plugin name>' :return: loaded translations as s dict """ global _translations trans = {} relative_filename = os.path.join(from_dir, 'locale' + YAML_FILE) filename = os.path.join(_base_dir, relative_filename) trans_dict = shyaml.yaml_load(filename, ordered=False, ignore_notfound=True) if trans_dict != None: if translation_type == 'global': for translation_section in trans_dict.keys(): if translation_section.endswith('_translations'): trans_id = translation_section.split('_')[0].replace( '.', '/') trans = trans_dict.get(translation_section, {}) _translations[trans_id] = trans logger.info( "Loading {} translations (id={}) from {}".format( translation_type, trans_id, relative_filename)) logger.debug(" - translations = {}".format(trans)) else: trans = trans_dict.get(translation_type + '_translations', {}) logger.info("Loading {} translations (id={}) from {}".format( translation_type, translation_id, relative_filename)) if _translations.get(translation_id, None) is not None: logger.info( "Duplicate identifier '{}' used for translation_type '{}' to load from '{}' - translations not loaded" .format(translation_id, translation_type, from_dir)) return trans _translations[translation_id] = trans logger.debug(" - translations = {}".format(trans)) _translation_files[translation_id] = {} _translation_files[translation_id]['type'] = translation_type _translation_files[translation_id]['filename'] = filename return trans
def parse_yaml(filename, config=None): ''' Load and parse a yaml configuration file and merge it to the configuration tree :param filename: Name of the configuration file :param config: Optional OrderedDict tree, into which the configuration should be merged :return: The resulting merged OrderedDict tree ''' if config is None: config = collections.OrderedDict() items = shyaml.yaml_load(filename, ordered=True) if items is not None: remove_comments(items) remove_digits(items) remove_reserved(items) remove_keyword(items) remove_invalid(items) config = merge(items, config) return config
def __init__(self, smarthome, name, classname, classpath, args, instance, meta, gtranslations): """ Initialization of wrapper class """ logger.debug( 'PluginWrapper __init__: Section {}, classname {}, classpath {}'. format(name, classname, classpath)) threading.Thread.__init__(self, name=name) self._init_complete = False self.meta = meta # Load an instance of the plugin try: exec("import {0}".format(classpath)) except Exception as e: logger.exception( "Plugin '{0}' exception during import of __init__.py: {1}". format(name, e)) return exec("self.plugin = {0}.{1}.__new__({0}.{1})".format( classpath, classname)) relative_filename = os.path.join(classpath.replace('.', '/'), 'locale' + YAML_FILE) filename = os.path.join(smarthome.get_basedir(), relative_filename) trans = shyaml.yaml_load(filename, ordered=False, ignore_notfound=True) if trans != None: self._ptrans = trans.get('plugin_translations', {}) logger.info("Plugin '{}': Loaded plugin translations = {}".format( name, self._ptrans)) else: self._ptrans = {} # make the plugin a method/function of the main smarthome object (MS: Ist das zu früh? Falls Init fehlschlägt?) # setattr(smarthome, self.name, self.plugin) # initialize attributes of the newly created plugin object instance if isinstance(self.get_implementation(), SmartPlugin): self.get_implementation()._gtranslations = gtranslations self.get_implementation()._ptranslations = self._ptrans self.get_implementation()._set_configname(name) # self.get_implementation()._config_section = name self.get_implementation()._set_shortname( str(classpath).split('.')[1]) self.get_implementation()._classpath = classpath self.get_implementation()._set_classname(classname) # if instance != '' war auskommentiert, reaktiviert: 26.01.2018 MS if self.get_implementation().ALLOW_MULTIINSTANCE is None: self.get_implementation( ).ALLOW_MULTIINSTANCE = self.meta.get_bool('multi_instance') if instance != '': logger.debug("set plugin {0} instance to {1}".format( name, instance)) self.get_implementation()._set_instance_name(instance) self.get_implementation()._set_sh(smarthome) self.get_implementation()._set_plugin_dir( os.path.join( os.path.dirname(os.path.dirname( os.path.abspath(__file__))), classpath.replace('.', os.sep))) self.get_implementation()._plgtype = self.meta.get_string('type') else: # classic plugin # self.get_implementation()._config_section = name self.get_implementation()._configname = name self.get_implementation()._shortname = str(classpath).split('.')[1] self.get_implementation()._classpath = classpath self.get_implementation()._classname = classname self.get_implementation()._plgtype = '' self.get_implementation()._itemlist = [] # get arguments defined in __init__ of plugin's class to self.args exec("self.args = inspect.getargspec({0}.{1}.__init__)[0][1:]".format( classpath, classname)) # get list of argument used names, if they are defined in the plugin's class logger.debug("Plugin '{}': args = '{}'".format(classname, str(args))) arglist = [name for name in self.args if name in args] argstring = ",".join( ["{}={}".format(name, args[name]) for name in arglist]) # logger.debug("Plugin '{}' using arguments {}".format(str(classpath).split('.')[1], arglist)) self.get_implementation()._init_complete = False (plugin_params, params_ok, hide_params) = self.meta.check_parameters(args) if params_ok == True: if plugin_params != {}: # initialize parameters the old way argstring = ",".join([ "{}={}".format( name, '"' + str(plugin_params.get(name, '')) + '"') for name in arglist ]) # initialize parameters the new way: Define a dict within the instance self.get_implementation()._parameters = plugin_params self.get_implementation()._hide_parameters = hide_params self.get_implementation()._metadata = self.meta # initialize the loaded instance of the plugin self.get_implementation( )._init_complete = True # set to false by plugin, if an initalization error occurs # initialize the loaded instance of the plugin exec("self.plugin.__init__(smarthome{0}{1})".format( "," if len(arglist) else "", argstring)) # set level to make logger appear in internal list of loggers (if not configured by logging.yaml) try: # skip classic plugins if self.get_implementation().logger.level == 0: self.get_implementation().logger.setLevel('WARNING') except: pass # set the initialization complete status for the wrapper instance self._init_complete = self.get_implementation()._init_complete if self.get_implementation()._init_complete == True: # make the plugin a method/function of the main smarthome object (MS: Ist das zu früh? Falls Init fehlschlägt?) setattr(smarthome, self.name, self.plugin) try: code_version = self.get_implementation().PLUGIN_VERSION except: code_version = None # if plugin code without version if isinstance(self.get_implementation(), SmartPlugin): if self.meta.test_version(code_version): # set version in plugin instance (if not defined in code) if code_version == None: self.get_implementation( ).PLUGIN_VERSION = self.meta.get_version() # set multiinstance in plugin instance (if not defined in code) try: dummy = self.get_implementation().ALLOW_MULTIINSTANCE except: # logger.warning("self.meta.get_bool('multi_instance') = {}".format(self.meta.get_bool('multi_instance'))) self.get_implementation( ).ALLOW_MULTIINSTANCE = self.meta.get_bool( 'multi_instance') # logger.warning("get_implementation().ALLOW_MULTIINSTANCE = {}".format(self.get_implementation().ALLOW_MULTIINSTANCE)) if not self.get_implementation( )._set_multi_instance_capable( self.meta.get_bool('multi_instance')): logger.error( "Plugins: Loaded plugin '{}' ALLOW_MULTIINSTANCE differs between metadata ({}) and Python code ({})" .format( name, self.meta.get_bool('multi_instance'), self.get_implementation().ALLOW_MULTIINSTANCE)) logger.debug( "Plugins: Loaded plugin '{}' (class '{}') v{}: {}". format( name, str(self.get_implementation().__class__.__name__), self.meta.get_version(), self.meta.get_mlstring('description'))) else: logger.debug( "Plugins: Loaded classic-plugin '{}' (class '{}')".format( name, str(self.get_implementation().__class__.__name__))) if instance != '': logger.debug("set plugin {0} instance to {1}".format( name, instance)) self.get_implementation()._set_instance_name(instance) else: logger.error( "Plugins: Plugin '{}' initialization failed, plugin not loaded" .format(classpath.split('.')[1]))
def __init__(self, smarthome, name, classname, classpath, args, instance, meta, gtranslations): """ Initialization of wrapper class """ logger.debug('PluginWrapper __init__: Section {}, classname {}, classpath {}'.format( name, classname, classpath )) threading.Thread.__init__(self, name=name) self._init_complete = False self.meta = meta # Load an instance of the plugin try: exec("import {0}".format(classpath)) except Exception as e: logger.exception("Plugin '{0}' exception during import of __init__.py: {1}".format(name, e)) return exec("self.plugin = {0}.{1}.__new__({0}.{1})".format(classpath, classname)) relative_filename = os.path.join( classpath.replace('.', '/'), 'locale'+YAML_FILE ) filename = os.path.join( smarthome.get_basedir(), relative_filename ) trans = shyaml.yaml_load(filename, ordered=False, ignore_notfound=True) if trans != None: self._ptrans = trans.get('plugin_translations', {}) logger.info("Plugin '{}': Loaded plugin translations = {}".format(name, self._ptrans)) else: self._ptrans = {} # make the plugin a method/function of the main smarthome object (MS: Ist das zu früh? Falls Init fehlschlägt?) # setattr(smarthome, self.name, self.plugin) # initialize attributes of the newly created plugin object instance if isinstance(self.get_implementation(), SmartPlugin): self.get_implementation()._gtranslations = gtranslations self.get_implementation()._ptranslations = self._ptrans self.get_implementation()._set_configname(name) # self.get_implementation()._config_section = name self.get_implementation()._set_shortname(str(classpath).split('.')[1]) self.get_implementation()._classpath = classpath self.get_implementation()._set_classname(classname) # if instance != '' war auskommentiert, reaktiviert: 26.01.2018 MS if self.get_implementation().ALLOW_MULTIINSTANCE is None: self.get_implementation().ALLOW_MULTIINSTANCE = self.meta.get_bool('multi_instance') if instance != '': logger.debug("set plugin {0} instance to {1}".format(name, instance )) self.get_implementation()._set_instance_name(instance) self.get_implementation()._set_sh(smarthome) self.get_implementation()._set_plugin_dir( os.path.join( os.path.dirname( os.path.dirname(os.path.abspath(__file__)) ), classpath.replace('.',os.sep) ) ) self.get_implementation()._plgtype = self.meta.get_string('type') else: # classic plugin # self.get_implementation()._config_section = name self.get_implementation()._configname = name self.get_implementation()._shortname = str(classpath).split('.')[1] self.get_implementation()._classpath = classpath self.get_implementation()._classname = classname self.get_implementation()._plgtype = '' self.get_implementation()._itemlist = [] # get arguments defined in __init__ of plugin's class to self.args exec("self.args = inspect.getargspec({0}.{1}.__init__)[0][1:]".format(classpath, classname)) # get list of argument used names, if they are defined in the plugin's class logger.debug("Plugin '{}': args = '{}'".format(classname, str(args))) arglist = [name for name in self.args if name in args] argstring = ",".join(["{}={}".format(name, args[name]) for name in arglist]) # logger.debug("Plugin '{}' using arguments {}".format(str(classpath).split('.')[1], arglist)) self.get_implementation()._init_complete = False (plugin_params, params_ok, hide_params) = self.meta.check_parameters(args) if params_ok == True: if plugin_params != {}: # initialize parameters the old way argstring = ",".join(["{}={}".format(name, '"'+str(plugin_params.get(name,''))+'"') for name in arglist]) # initialize parameters the new way: Define a dict within the instance self.get_implementation()._parameters = plugin_params self.get_implementation()._hide_parameters = hide_params self.get_implementation()._metadata = self.meta # initialize the loaded instance of the plugin self.get_implementation()._init_complete = True # set to false by plugin, if an initalization error occurs # initialize the loaded instance of the plugin exec("self.plugin.__init__(smarthome{0}{1})".format("," if len(arglist) else "", argstring)) # set level to make logger appear in internal list of loggers (if not configured by logging.yaml) try: # skip classic plugins if self.get_implementation().logger.level == 0: self.get_implementation().logger.setLevel('WARNING') except: pass # set the initialization complete status for the wrapper instance self._init_complete = self.get_implementation()._init_complete if self.get_implementation()._init_complete == True: # make the plugin a method/function of the main smarthome object (MS: Ist das zu früh? Falls Init fehlschlägt?) setattr(smarthome, self.name, self.plugin) try: code_version = self.get_implementation().PLUGIN_VERSION except: code_version = None # if plugin code without version if isinstance(self.get_implementation(), SmartPlugin): if self.meta.test_version(code_version): # set version in plugin instance (if not defined in code) if code_version == None: self.get_implementation().PLUGIN_VERSION = self.meta.get_version() # set multiinstance in plugin instance (if not defined in code) try: dummy = self.get_implementation().ALLOW_MULTIINSTANCE except: # logger.warning("self.meta.get_bool('multi_instance') = {}".format(self.meta.get_bool('multi_instance'))) self.get_implementation().ALLOW_MULTIINSTANCE = self.meta.get_bool('multi_instance') # logger.warning("get_implementation().ALLOW_MULTIINSTANCE = {}".format(self.get_implementation().ALLOW_MULTIINSTANCE)) if not self.get_implementation()._set_multi_instance_capable(self.meta.get_bool('multi_instance')): logger.error("Plugins: Loaded plugin '{}' ALLOW_MULTIINSTANCE differs between metadata ({}) and Python code ({})".format(name, self.meta.get_bool('multi_instance'), self.get_implementation().ALLOW_MULTIINSTANCE )) logger.debug("Plugins: Loaded plugin '{}' (class '{}') v{}: {}".format( name, str(self.get_implementation().__class__.__name__), self.meta.get_version(), self.meta.get_mlstring('description') ) ) else: logger.debug("Plugins: Loaded classic-plugin '{}' (class '{}')".format( name, str(self.get_implementation().__class__.__name__) ) ) if instance != '': logger.debug("set plugin {0} instance to {1}".format(name, instance )) self.get_implementation()._set_instance_name(instance) else: logger.error("Plugins: Plugin '{}' initialization failed, plugin not loaded".format(classpath.split('.')[1]))
def parse_yaml(filename, config=None, addfilenames=False): """ Load and parse a yaml configuration file and merge it to the configuration tree :param filename: Name of the configuration file :param config: Optional OrderedDict tree, into which the configuration should be merged :type filename: str :type config: bool :return: The resulting merged OrderedDict tree :rtype: OrderedDict The config file should stick to the following setup: .. code-block:: yaml firstlevel: attribute1: xyz attribute2: foo attribute3: bar secondlevel: attribute1: abc attribute2: bar attribute3: foo thirdlevel: attribute1: def attribute2: barfoo attribute3: foobar anothersecondlevel: attribute1: and so on where firstlevel, secondlevel, thirdlevel and anothersecondlevel are defined as items and attribute are their respective attribute - value pairs Valid characters for the items are a-z and A-Z plus any digit and underscore as second or further characters. Valid characters for the attributes are the same as for an item plus @ and * """ logger.debug("parse_yaml: Parsing file {}".format( os.path.basename(filename))) if config is None: config = collections.OrderedDict() items = shyaml.yaml_load(filename, ordered=True) if items is not None: remove_comments(items) remove_digits(items) remove_reserved(items) remove_keyword(items) remove_invalid(items) if addfilenames: logger.debug("parse_yaml: Add filename = {} to items".format( os.path.basename(filename))) _add_filenames_to_config(items, os.path.basename(filename)) config = merge(items, config) return config
def _initialize_holidays(self): """ Initialize the holidays according to etc/holidays.yaml for the current year and the two years to come """ if self.holidays is None: self._etc_dir = self._sh._etc_dir conf_filename = os.path.join(self._sh._etc_dir, 'holidays' + YAML_FILE) self.config = shyaml.yaml_load(conf_filename) location = self.config.get('location', None) # prepopulate holidays for following years this_year = self.today().year self.years = [this_year, this_year + 1, this_year + 2] if location: country = location.get('country', 'DE') prov = location.get('province', None) state = location.get('state', None) try: self.holidays = holidays.CountryHoliday(country, years=self.years, prov=prov, state=state) except KeyError as e: self.logger.error( "Error initializing self.holidays: {}".format(e)) try: self.public_holidays = holidays.CountryHoliday( country, years=self.years, prov=prov, state=state) except KeyError as e: self.logger.error( "Error initializing self.public_holidays: {}".format( e)) else: self.holidays = holidays.CountryHoliday('US', years=self.years, prov=None, state=None) self.public_holidays = holidays.CountryHoliday( 'US', years=self.years, prov=None, state=None) if self.holidays is not None: c_logtext = self.translate('not defined') c_logcount = '' count = self._add_custom_holidays() if count > 0: c_logcount = ' ' + str(count) c_logtext = self.translate('defined') defined_state = '' # Test if class of self.holiday has an attribute 'state' try: state = self.holidays.state except Exception as e: state = self.holidays.subdiv # Test if class of self.holiday has an attribute 'prov' try: prov = self.holidays.prov except Exception as e: prov = self.holidays.subdiv state = None if state is not None: defined_state = ", state'" + state + "'" self.log_msg = self.translate( "Using holidays for country '{country}', province '{province}'{state},{count} custom holiday(s) {defined}" ) self.log_msg = self.log_msg.format( country=self.holidays.country, province=prov, state=defined_state, count=c_logcount, defined=c_logtext) self.logger.info(self.log_msg) self.logger.info(self.translate('Defined holidays') + ':') for ft in sorted(self.holidays): self.logger.info(' - {}: {}'.format(ft, self.holidays[ft])) return
def __init__(self, smarthome): self._sh = smarthome global _scenes_instance if _scenes_instance is not None: import inspect curframe = inspect.currentframe() calframe = inspect.getouterframes(curframe, 2) logger.critical( "A second 'scenes' object has been created. There should only be ONE instance of class 'Scenes'!!! Called from: {} ({})" .format(calframe[1][1], calframe[1][3])) _scenes_instance = self self.items = Items.get_instance() self.logics = Logics.get_instance() self._scenes = {} self._learned_values = {} self._scenes_dir = smarthome._scenes_dir if not os.path.isdir(self._scenes_dir): logger.warning( "Directory scenes not found. Ignoring scenes.".format( self._scenes_dir)) return self._learned_values = {} # for item in smarthome.return_items(): for item in self.items.return_items(): if item.type() == 'scene': self.scene_file = os.path.join(self._scenes_dir, item.id()) scene_file_yaml = yaml.yaml_load(self.scene_file + '.yaml', ordered=False, ignore_notfound=True) if scene_file_yaml is not None: # Reading yaml file with scene definition for state in scene_file_yaml: actions = scene_file_yaml[state].get('actions', None) if actions is not None: if isinstance(actions, dict): actions = [actions] if isinstance(actions, list): for action in actions: if isinstance(action, dict): self._add_scene_entry( item, str(state), action.get('item', ''), str(action.get('value', '')), action.get('learn', ''), scene_file_yaml[state].get( 'name', '')) else: logger.warning( "Scene {}, state {}: action '{}' is not a dict" .format(item, state, action)) else: logger.warning( "Scene {}, state {}: actions are not a list" .format(item, state)) self._load_learned_values(str(item.id())) else: # Trying to read conf file with scene definition scene_conf_file = self.scene_file + '.conf' try: with open(scene_conf_file, 'r', encoding='UTF-8') as f: reader = csv.reader(f, delimiter=' ') for row in reader: if row == []: # ignore empty lines continue if row[0][0] == '#': # ignore comments continue self._add_scene_entry(item, row[0], row[1], row[2]) except Exception as e: logger.warning( "Problem reading scene file {0}: No .yaml or .conf file found with this name" .format(self.scene_file)) continue item.add_method_trigger(self._trigger)
def __init__(self, smarthome): self._sh = smarthome global _scenes_instance _scenes_instance = self self._scenes = {} self._learned_values = {} self._scenes_dir = smarthome.base_dir + '/scenes/' if not os.path.isdir(self._scenes_dir): logger.warning( "Directory scenes not found. Ignoring scenes.".format( self._scenes_dir)) return for item in smarthome.return_items(): if item.type() == 'scene': scene_file = os.path.join(self._scenes_dir, item.id()) scene_file_yaml = yaml.yaml_load(scene_file + '.yaml', ordered=False, ignore_notfound=True) if scene_file_yaml is not None: # Reading yaml file with scene definition for state in scene_file_yaml: actions = scene_file_yaml[state]['actions'] if isinstance(actions, dict): actions = [actions] if isinstance(actions, list): for action in actions: if isinstance(action, dict): self._add_scene_entry( item, str(state), action.get('item', ''), str(action.get('value', '')), action.get('learn', ''), scene_file_yaml[state].get('name', '')) else: logger.warning( "Scene {}, state {}: action '{}' is not a dict" .format(item, state, action)) else: logger.warning( "Scene {}, state {}: actions are not a list". format(item, state)) self._load_learned_values(str(item.id())) else: # Trying to read conf file with scene definition scene_conf_file = scene_file + '.conf' try: with open(scene_conf_file, 'r', encoding='UTF-8') as f: reader = csv.reader(f, delimiter=' ') for row in reader: if row == []: # ignore empty lines continue if row[0][0] == '#': # ignore comments continue self._add_scene_entry(item, row[0], row[1], row[2]) except Exception as e: logger.warning( "Problem reading scene file {0}: {1}".format( scene_file, e)) continue item.add_method_trigger(self._trigger)
def __init__(self, sh, addon_name, addon_type, classpath=''): self._sh = sh self._addon_name = addon_name.lower() self._addon_type = addon_type self._log_premsg = "{} '{}': ".format(addon_type, self._addon_name) # logger.warning(self._log_premsg+"classpath = '{}'".format( classpath ) ) if classpath == '': if addon_type == 'plugin': addon_type_dir = 'plugins' elif addon_type == 'module': addon_type_dir = 'modules' else: return self.relative_filename = os.path.join( addon_type_dir, self._addon_name, addon_type+YAML_FILE ) else: self.relative_filename = os.path.join( classpath.replace('.', os.sep), addon_type+YAML_FILE ) # logger.warning(self._log_premsg+"relative_filename = '{}'".format( self.relative_filename ) ) # read definitions from metadata file filename = os.path.join( self._sh.get_basedir(), self.relative_filename ) self.meta = shyaml.yaml_load(filename, ordered=True) self.parameters = None self._paramlist = [] self.itemdefinitions = None self._itemdeflist = [] if self.meta != None: # read paramter and item definition sections if self._addon_type == 'module': self.parameters = self.meta.get(META_MODULE_PARAMETER_SECTION) else: self.parameters = self.meta.get(META_PLUGIN_PARAMETER_SECTION) self.itemdefinitions = self.meta.get(META_PLUGIN_ITEMATTRIBUTE_SECTION) # test validity of paramter definition section if self.parameters is not None: self._paramlist = list(self.parameters.keys()) logger.info(self._log_premsg+"Metadata paramlist = '{}'".format( str(self._paramlist) ) ) if self.parameters is not None: self._test_definitions(self._paramlist, self.parameters) else: logger.info(self._log_premsg+"has no parameter definitions in metadata") # test validity of item definition section if self.itemdefinitions != None: self._itemdeflist = list(self.itemdefinitions.keys()) logger.info(self._log_premsg+"Metadata itemdeflist = '{}'".format( str(self._itemdeflist) ) ) if self.itemdefinitions is not None: self._test_definitions(self._itemdeflist, self.itemdefinitions) else: logger.info(self._log_premsg+"has no item definitions in metadata") # Read global metadata for addon if self.meta != None: self.addon_metadata = self.meta.get(addon_type) else: self.addon_metadata = None return
def __init__(self, sh, addon_name, addon_type, classpath=''): self._sh = sh self._addon_name = addon_name.lower() self._addon_type = addon_type self._paramlist = [] self._log_premsg = "{} '{}': ".format(addon_type, self._addon_name) # logger.warning(self._log_premsg+"classpath = '{}'".format( classpath ) ) if classpath == '': if addon_type == 'plugin': addon_type_dir = 'plugins' elif addon_type == 'module': addon_type_dir = 'modules' else: return self.relative_filename = os.path.join(addon_type_dir, self._addon_name, addon_type + YAML_FILE) else: self.relative_filename = os.path.join( classpath.replace('.', os.sep), addon_type + YAML_FILE) # logger.warning(self._log_premsg+"relative_filename = '{}'".format( self.relative_filename ) ) self.parameters = None filename = os.path.join(self._sh.get_basedir(), self.relative_filename) self.meta = shyaml.yaml_load(filename, ordered=True) if self.meta != None: if self._addon_type == 'module': self.parameters = self.meta.get(META_MODULE_PARAMETER_SECTION) else: self.parameters = self.meta.get(META_PLUGIN_PARAMETER_SECTION) if self.parameters != None: self._paramlist = list(self.parameters.keys()) logger.info( self._log_premsg + "Metadata paramlist = '{}'".format(str(self._paramlist))) # Test parameter definitions for validity for param in self._paramlist: logger.debug(self._log_premsg + "param = '{}'".format(str(param))) if self.parameters[param] != None: typ = str(self.parameters[param].get('type', FOO)).lower() # to be implemented: timeframe self.parameters[param]['listtype'] = '' if not (typ in META_DATA_TYPES): # test for list with specified datatype if typ.startswith('list(') and typ.endswith(')'): self.parameters[param]['type'] = 'list' subtyp = typ[5:] subtyp = subtyp[:-1].strip() if subtyp in META_DATA_TYPES: self.parameters[param]['listtype'] = subtyp else: self.parameters[param]['listtype'] = FOO else: logger.error( self._log_premsg + "Invalid definition in metadata file '{}': type '{}' for parameter '{}' -> using type '{}' instead" .format(self.relative_filename, typ, param, FOO)) self.parameters[param]['type'] = FOO else: # self.parameters[param]['type'] = FOO pass # Read global metadata for addon if self.meta != None: self.addon_metadata = self.meta.get(addon_type) else: self.addon_metadata = None
def parse_yaml(filename, config=None, addfilenames=False, parseitems=False, struct_dict={}): """ Load and parse a yaml configuration file and merge it to the configuration tree :param filename: Name of the configuration file :param config: Optional OrderedDict tree, into which the configuration should be merged :param addfilenames: x :param parseitems: x :param struct_dict: dictionary with stuct definitions (templates) for reading item tree :type filename: str :type config: bool :type addfilenames: bool :type parseitems: bool :type struct_dict: dict :return: The resulting merged OrderedDict tree :rtype: OrderedDict The config file should stick to the following setup: .. code-block:: yaml firstlevel: attribute1: xyz attribute2: foo attribute3: bar secondlevel: attribute1: abc attribute2: bar attribute3: foo thirdlevel: attribute1: def attribute2: barfoo attribute3: foobar anothersecondlevel: attribute1: and so on where firstlevel, secondlevel, thirdlevel and anothersecondlevel are defined as items and attribute are their respective attribute - value pairs Valid characters for the items are a-z and A-Z plus any digit and underscore as second or further characters. Valid characters for the attributes are the same as for an item plus @ and * """ if os.path.basename(filename).startswith('test_'): logger.info("parse_yaml: Parsing file {}".format( os.path.basename(filename))) if config is None: config = collections.OrderedDict() items = shyaml.yaml_load(filename, ordered=True) if items is not None: remove_comments(items, filename) remove_digits(items, filename) remove_reserved(items, filename) remove_keyword(items, filename) remove_invalid(items, filename) if addfilenames: #logger.debug("parse_yaml: Add filename = {} to items".format(os.path.basename(filename))) _add_filenames_to_config(items, os.path.basename(filename)) if parseitems: # test if file contains 'struct' attribute and merge all items into config #logger.debug("parse_yaml: Checking if file {} contains 'struct' attribute".format(os.path.basename(filename))) search_for_struct_in_items(items, struct_dict, config, os.path.basename(filename)) global special_listentry_found if special_listentry_found: remove_special_listentries(config, os.path.basename(filename)) special_listentry_found = False if not parseitems: # if not parsing items config = merge(items, config, os.path.basename(filename), 'Config-Tree') return config
def __init__(self, sh, addon_name, addon_type, classpath=''): self._sh = sh self._addon_name = addon_name.lower() self._addon_type = addon_type self._log_premsg = "{} '{}': ".format(addon_type, self._addon_name) # logger.warning(self._log_premsg+"classpath = '{}'".format( classpath ) ) if classpath == '': if addon_type == 'plugin': addon_type_dir = 'plugins' elif addon_type == 'module': addon_type_dir = 'modules' else: return self.relative_filename = os.path.join(addon_type_dir, self._addon_name, addon_type + YAML_FILE) else: self.relative_filename = os.path.join( classpath.replace('.', os.sep), addon_type + YAML_FILE) # logger.warning(self._log_premsg+"relative_filename = '{}'".format( self.relative_filename ) ) # read definitions from metadata file filename = os.path.join(self._sh.get_basedir(), self.relative_filename) self.meta = shyaml.yaml_load(filename, ordered=True) self.parameters = None self._paramlist = [] self.itemdefinitions = None self._itemdeflist = [] if self.meta != None: # read paramter and item definition sections if self._addon_type == 'module': self.parameters = self.meta.get(META_MODULE_PARAMETER_SECTION) else: self.parameters = self.meta.get(META_PLUGIN_PARAMETER_SECTION) self.itemdefinitions = self.meta.get( META_PLUGIN_ITEMATTRIBUTE_SECTION) # test validity of paramter definition section if self.parameters is not None: self._paramlist = list(self.parameters.keys()) logger.info( self._log_premsg + "Metadata paramlist = '{}'".format(str(self._paramlist))) if self.parameters is not None: self._test_definitions(self._paramlist, self.parameters) else: logger.info(self._log_premsg + "has no parameter definitions in metadata") # test validity of item definition section if self.itemdefinitions != None: self._itemdeflist = list(self.itemdefinitions.keys()) logger.info(self._log_premsg + "Metadata itemdeflist = '{}'".format( str(self._itemdeflist))) if self.itemdefinitions is not None: self._test_definitions(self._itemdeflist, self.itemdefinitions) else: logger.info(self._log_premsg + "has no item definitions in metadata") # Read global metadata for addon if self.meta != None: self.addon_metadata = self.meta.get(addon_type) else: self.addon_metadata = None return
def __init__(self, sh, addon_name, addon_type, classpath=''): self._sh = sh self._addon_name = addon_name.lower() self._addon_type = addon_type self._paramlist = [] self._log_premsg = "{} '{}': ".format(addon_type, self._addon_name) # logger.warning(self._log_premsg+"classpath = '{}'".format( classpath ) ) if classpath == '': if addon_type == 'plugin': addon_type_dir = 'plugins' elif addon_type == 'module': addon_type_dir = 'modules' else: return self.relative_filename = os.path.join( addon_type_dir, self._addon_name, addon_type+YAML_FILE ) else: self.relative_filename = os.path.join( classpath.replace('.', os.sep), addon_type+YAML_FILE ) # logger.warning(self._log_premsg+"relative_filename = '{}'".format( self.relative_filename ) ) self.parameters = None filename = os.path.join( self._sh.get_basedir(), self.relative_filename ) self.meta = shyaml.yaml_load(filename, ordered=True) if self.meta != None: if self._addon_type == 'module': self.parameters = self.meta.get(META_MODULE_PARAMETER_SECTION) else: self.parameters = self.meta.get(META_PLUGIN_PARAMETER_SECTION) if self.parameters != None: self._paramlist = list(self.parameters.keys()) logger.info(self._log_premsg+"Metadata paramlist = '{}'".format( str(self._paramlist) ) ) # Test parameter definitions for validity for param in self._paramlist: logger.debug(self._log_premsg+"param = '{}'".format( str(param) ) ) if self.parameters[param] != None: typ = str(self.parameters[param].get('type', FOO)).lower() # to be implemented: timeframe self.parameters[param]['listtype'] = '' if not (typ in META_DATA_TYPES): # test for list with specified datatype if typ.startswith('list(') and typ.endswith(')'): self.parameters[param]['type'] = 'list' subtyp = typ[5:] subtyp = subtyp[:-1].strip() if subtyp in META_DATA_TYPES: self.parameters[param]['listtype'] = subtyp else: self.parameters[param]['listtype'] = FOO else: logger.error(self._log_premsg+"Invalid definition in metadata file '{}': type '{}' for parameter '{}' -> using type '{}' instead".format( self.relative_filename, typ, param, FOO ) ) self.parameters[param]['type'] = FOO else: # self.parameters[param]['type'] = FOO pass # Read global metadata for addon if self.meta != None: self.addon_metadata = self.meta.get(addon_type) else: self.addon_metadata = None
def __init__(self, sh, addon_name, addon_type, classpath=''): """ Initialzes the metadata for an addon (plugin or module) from the definition file :param sh: SmartHomeNG main object :param addon_name: :param addon_type: 'plugin' or 'module' :param classpath: :type sh: object :type addon_name: str :type addon_type: str :type classpath: str """ self._sh = sh self._addon_name = addon_name.lower() self._addon_type = addon_type self._log_premsg = "{} '{}': ".format(addon_type, self._addon_name) # logger.warning(self._log_premsg+"classpath = '{}'".format( classpath ) ) if classpath == '': if addon_type == 'plugin': addon_type_dir = 'plugins' elif addon_type == 'module': addon_type_dir = 'modules' else: return self.relative_filename = os.path.join(addon_type_dir, self._addon_name, addon_type + YAML_FILE) else: self.relative_filename = os.path.join( classpath.replace('.', os.sep), addon_type + YAML_FILE) # logger.warning(self._log_premsg+"relative_filename = '{}'".format( self.relative_filename ) ) # read complete definitions from metadata file filename = os.path.join(self._sh.get_basedir(), self.relative_filename) self.meta = shyaml.yaml_load(filename, ordered=True) self.parameters = None self._paramlist = [] self.itemdefinitions = None self._itemdeflist = [] self.itemstructs = None self._itemstructlist = [] self.logic_parameters = None self._logic_paramlist = [] self.plugin_functions = None self._plugin_functionlist = [] if self.meta is not None: # read paramter and item definition sections if self._addon_type == 'module': self.parameters = self.meta.get(META_MODULE_PARAMETER_SECTION) self.itemstructs = self.meta.get(META_STRUCT_SECTION) else: self.parameters = self.meta.get(META_PLUGIN_PARAMETER_SECTION) self.itemdefinitions = self.meta.get( META_PLUGIN_ITEMATTRIBUTE_SECTION) self.itemstructs = self.meta.get(META_STRUCT_SECTION) self.logic_parameters = self.meta.get( META_PLUGIN_LOGIC_PARAMETER_SECTION) self.plugin_functions = self.meta.get( META_PLUGIN_FUNCTION_SECTION) # test validity of parameter definition section if self.parameters is not None: if self.parameters == 'NONE': self.parameters = None else: self._paramlist = list(self.parameters.keys()) logger.info(self._log_premsg + "Metadata paramlist = '{}'".format( str(self._paramlist))) if self.parameters is not None: self._test_definitions(self._paramlist, self.parameters) else: logger.debug(self._log_premsg + "has no parameter definitions in metadata") # test validity of item definition section if self.itemdefinitions is not None: if self.itemdefinitions == 'NONE': self.itemdefinitions = None else: self._itemdeflist = list(self.itemdefinitions.keys()) logger.info(self._log_premsg + "Metadata itemdeflist = '{}'".format( str(self._itemdeflist))) if self.itemdefinitions is not None: self._test_definitions(self._itemdeflist, self.itemdefinitions) else: logger.debug(self._log_premsg + "has no item definitions in metadata") # test validity of logic-parameter definition section if self.logic_parameters is not None: if self.logic_parameters == 'NONE': self.logic_parameters = None else: self._logic_paramlist = list(self.logic_parameters.keys()) logger.info(self._log_premsg + "Metadata logic_paramlist = '{}'".format( str(self._logic_paramlist))) if self.logic_parameters is not None: self._test_definitions(self._logic_paramlist, self.logic_parameters) else: logger.debug(self._log_premsg + "has no logic-parameter definitions in metadata") # test validity of plugin-function definition section if self.plugin_functions is not None: if self.plugin_functions == 'NONE': self.plugin_functions = None else: self._plugin_functionlist = list( self.plugin_functions.keys()) logger.info(self._log_premsg + "Metadata plugin_functionlist = '{}'".format( str(self._plugin_functionlist))) if self.plugin_functions is not None: # self._test_definitions(self._plugin_functionlist, self.plugin_functions) pass dummy = self.get_plugin_function_defstrings(with_type=False, with_default=False) dummy = self.get_plugin_function_defstrings(with_type=True, with_default=False) dummy = self.get_plugin_function_defstrings(with_type=False, with_default=True) dummy = self.get_plugin_function_defstrings(with_type=True, with_default=True) else: logger.debug(self._log_premsg + "has no plugin-function definitions in metadata") # test validity of structs definition section if self.itemstructs is not None: if self.itemstructs == 'NONE': self.itemstructs = None else: logger.info(self._log_premsg + "Metadata itemstructlist = '{}'".format( self._itemstructlist)) # for struct in self._itemstructlist: # for i in self.itemstructs[struct]: # self.itemstructs[struct][i] = dict(self.itemstructs[struct][i]) # for si in self.itemstructs[struct][i]: # if type(self.itemstructs[struct][i][si]) is collections.OrderedDict: # self.itemstructs[struct][i][si] = dict(self.itemstructs[struct][i][si]) # logger.info(self._log_premsg + "Metadata itemstruct '{}' = '{}'".format(struct, dict(self.itemstructs[struct]))) # if self.itemstructs is not None: ## self._test_definitions(self._itemdeflist, self.itemdefinitions) # pass else: logger.info(self._log_premsg + "has no item-struct definitions in metadata") # Read global metadata for addon (either 'plugin' or 'module' if self.meta is not None: self.addon_metadata = self.meta.get(addon_type) else: self.addon_metadata = None return