async def attr_(obj, bus, group, vars_, eval_, path_): """Set/get/delete an attribute on a given KNX element. `--eval` without a value deletes the attribute. """ group = (int(x) for x in group.split("/")) if group else () path = Path(bus, *group) if len(path) != 4: raise click.UsageError("Group address must be 3 /-separated elements.") res = await obj.client.get(obj.cfg.knx.prefix + path, nchain=obj.meta or 1) if vars_ or eval_ or path_: res = await node_attr(obj, obj.cfg.knx.prefix + path, vars_, eval_, path_, res=res) if obj.meta: yprint(res, stream=obj.stdout) else: if not obj.meta: res = res.value yprint(res, stream=obj.stdout)
async def addr(obj, bus, group, typ, mode, attr): """Set/get/delete device settings. This is a shortcut for the "attr" command.""" group = (int(x) for x in group.split("/")) path = Path(bus, *group) if len(path) != 4: raise click.UsageError("Group address must be 3 /-separated elements.") res = await obj.client.get(obj.cfg.knx.prefix + path, nchain=obj.meta or 1) val = res.get("value", attrdict()) if typ == "-": res = await obj.client.delete(obj.cfg.knx.prefix + path, nchain=obj.meta) if obj.meta: yprint(res, stream=obj.stdout) return if typ: attr = (("type", typ), ) + attr if mode: attr = (("mode", mode), ) + attr for k, v in attr: if k in {"src", "dest"}: v = P(v) else: try: v = int(v) except ValueError: try: v = float(v) except ValueError: pass val[k] = v await _attr(obj, (), val, path, False, res)
async def dump(obj, path): """Emit the current state as a YAML file.""" res = {} path = P(path) if len(path) > 4: raise click.UsageError("Only up to four path elements allowed") async for r in obj.client.get_tree(obj.cfg.knx.prefix + path, nchain=obj.meta, max_depth=4 - len(path)): # pl = len(path) + len(r.path) rr = res if r.path: for rp in r.path: rr = rr.setdefault(rp, {}) rr["_"] = r if obj.meta else r.value yprint(res, stream=obj.stdout)
async def server_(obj, name, host, port, delete): """ Configure a server. No arguments: list them. """ if not name: if host or port or delete: raise click.UsageError("Use a server name to set parameters") async for r in obj.client.get_tree(obj.cfg.akumuli.prefix, min_depth=1, max_depth=1): print(r.path[-1], file=obj.stdout) return elif len(name) > 1: raise click.UsageError("Only one server allowed") name = name[0] if host or port: if delete: raise click.UsageError( "You can't delete and set at the same time.") value = attrdict() if host: value.host = host if port: if port == "-": value.port = NotGiven else: value.port = int(port) elif delete: res = await obj.client.delete_tree(obj.cfg.akumuli.prefix + name, nchain=obj.meta) if obj.meta: yprint(res, stream=obj.stdout) return else: value = None res = await node_attr(obj, obj.cfg.akumuli.prefix | name, ("server", ), value) if obj.meta: yprint(res, stream=obj.stdout)
async def attr_(obj, attr, value, path, eval_, path_): """Set/get/delete an attribute on a given akumuli element. `--eval` without a value deletes the attribute. """ path = P(path) if path_ and eval_: raise click.UsageError("split and eval don't work together.") if value and not attr: raise click.UsageError("Values must have locations ('-a ATTR').") if path_: value = P(value) res = await node_attr(obj, obj.cfg.akumuli.prefix + path, P(attr), value, eval_=eval_) if obj.meta: yprint(res, stream=obj.stdout)
async def set_(obj, path, source, mode, attr, series, tags): """Set/delete part of a series. \b path: the name of this copy command. Unique path, non-empty. source: the element with the data. unique path, non-empty. series: the Akumuli series to write to. tags: any number of "name=value" Akumuli tags to use for the series. A series of '-' deletes. """ path = P(path) attr = P(attr) source = P(source) mode = getattr(DS, mode) tagged = {} if series == "-": if tags: raise click.UsageError("You can't add tags when deleting") series = None await obj.client.delete(obj.cfg.akumuli.prefix + path) return if not tags: raise click.UsageError("You can't write to a series without tags") for x in tags: try: k, v = x.split("=", 2) except ValueError: raise click.UsageError("Tags must be key=value") from None tagged[k] = v val = dict(source=source, series=series, tags=tagged, mode=mode.name) if attr: val["attr"] = attr res = await obj.client.set(obj.cfg.akumuli.prefix + path, val) if obj.meta: yprint(res, stream=obj.stdout)
async def _attr(obj, attr, value, path, eval_, res=None): # Sub-attr setter. # Special: if eval_ is True, an empty value deletes. A mapping replaces instead of updating. if res is None: res = await obj.client.get(obj.cfg.knx.prefix + path, nchain=obj.meta or 1) try: val = res.value except AttributeError: res.chain = None if eval_: if value is None: pass ## value = res_delete(res, attr) else: value = path_eval(value) if isinstance(value, Mapping): # replace pass ## value = res_delete(res, attr) value = value._update(attr, value=value) else: value = res_update(res, attr, value=value) else: if value is None: if not attr and obj.meta: val = res else: val = res_get(res, attr) yprint(val, stream=obj.stdout) return value = res_update(res, attr, value=value) res = await obj.client.set(obj.cfg.knx.prefix + path, value=value, nchain=obj.meta, chain=res.chain) if obj.meta: yprint(res, stream=obj.stdout)