def test_cfg_multiple_filters(): a = validate_cfg({ 'test': True, 'filter': { 'thing_type': 'bla' }, 'channels': [{ 'filter': { 'channel_uid': 'channel_filter' } }] }) assert a is not None b = validate_cfg([{ 'test': True, 'filter': [{ 'thing_type': 'bla' }], 'channels': [{ 'filter': [{ 'channel_uid': 'channel_filter' }] }] }]) assert b is not None # compare str because we have different instances of the filter class assert str(a) == str(b)
def test_cfg_item_builder(): c = validate_cfg({ 'test': True, 'filter': {}, 'create items': [{ 'type': 'Switch', 'name': '{thing_uid}' }], 'channels': [{ 'filter': {}, 'link items': [{ 'type': 'Number', 'name': '{thing_uid}' }], }] }) a = list(c[0].get_items({'thing_uid': 'replaced_uid'})) assert a[0].type == 'Switch' assert a[0].name == 'replaced_uid' a = list(c[0].channels[0].get_items({'thing_uid': 'replaced_uid'})) assert a[0].type == 'Number' assert a[0].name == 'replaced_uid'
def test_thing_cfg_types(): assert validate_cfg({ 'test': True, 'filter': {}, 'thing config': { 1: 0, 2: 'str', 'Group1': ['asdf'] }, })
def test_cfg_optional(): assert validate_cfg({ 'test': True, 'filter': {}, })
def test_cfg_err(): assert None is validate_cfg({'test': True, 'filter1': {}}, 'filename') assert None is validate_cfg({'test': True, 'filter1': {}})
async def update_thing_config(self, path: Path, data=None): # we have to check the naming structure because we get file events for the whole folder _name = path.name.lower() if not _name.startswith('thing_') or not _name.endswith('.yml'): return None # only load if we don't supply the data if data is None: data = await async_get_things() # remove created items self.created_items.pop(path.name, None) created_items = self.created_items.setdefault(path.name, set()) # shedule cleanup self.do_cleanup.reset() # output file output_file = path.with_suffix('.items') if output_file.is_file(): output_file.unlink() # we also get events when the file gets deleted if not path.is_file(): log.debug(f'File {path} does not exist -> skipping Thing configuration!') return None log.debug(f'Loading {path}!') # load the config file yml = HABApp.parameters.parameter_files._yml_setup with path.open(mode='r', encoding='utf-8') as file: try: cfg = yml.load(file) except Exception as e: HABAppError(log).add_exception(e).dump() return None # validate configuration cfg = validate_cfg(cfg, path.name) if cfg is None: return None # if one entry has test set we show an overview of all the things if any(map(lambda x: x.test, cfg)): log_overview(data, THING_ALIAS, 'Thing overview') # process each thing part in the cfg for cfg_entry in cfg: test: bool = cfg_entry.test things = list(apply_filters(cfg_entry.filter, data, test)) # show a warning we found no Things if not things: log_warning(log, f'No things matched for {cfg_entry.filter}') continue # update thing configuration if cfg_entry.thing_config: await update_thing_cfg(cfg_entry.thing_config, things, test) try: # item creation for every thing create_items = {} shown_types = set() for thing in things: thing_context = {k: thing.get(alias, '') for k, alias in THING_ALIAS.items()} # create items without channel for item_cfg in cfg_entry.get_items(thing_context): name = item_cfg.name if name in create_items: raise ValueError(f'Duplicate item: {name}') create_items[name] = item_cfg # Channel overview, only if we have something configured if test and cfg_entry.channels: __thing_type = thing_context['thing_type'] if __thing_type not in shown_types: shown_types.add(__thing_type) log_overview(thing['channels'], CHANNEL_ALIAS, heading=f'Channels for {__thing_type}') # do channel things for channel_cfg in cfg_entry.channels: channels = apply_filters(channel_cfg.filter, thing['channels'], test) for channel in channels: channel_context = {k: channel.get(alias, '') for k, alias in CHANNEL_ALIAS.items()} channel_context.update(thing_context) for item_cfg in channel_cfg.get_items(channel_context): item_cfg.link = channel['uid'] name = item_cfg.name if name in create_items: raise ValueError(f'Duplicate item: {name}') create_items[name] = item_cfg # newline only if we create logs if test and (cfg_entry.create_items or cfg_entry.channels): log.info('') except InvalidItemNameError as e: HABAppError(log).add_exception(e).dump() continue # Create all items for item_cfg in create_items.values(): created = await create_item(item_cfg, test) if created: created_items.add(item_cfg.name) self.do_cleanup.reset() create_items_file(output_file, create_items)