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 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 list_(obj, path): """List the next stage.""" 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, min_depth=1, max_depth=1, empty=True): if len(path) and not isinstance(r.path[-1], int): continue print(r.path[-1], file=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 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 test_basic(): async with stdtest(test_0={"init": 125}, n=1, tocks=200) as st, st.client( 0 ) as client, Tester().run() as t: await st.run(f"knx server test localhost -h 127.0.0.1 -p {knx_mock.TCP_PORT}") await st.run("knx addr -t in -m power test 1/2/3 -a dest test.some.power") await st.run("knx addr -t in -m binary test 1/2/4 -a dest test.some.switch") await st.run("knx addr -t in -m percentU8 test 1/2/5 -a dest test.some.percent") await st.run("knx addr -t out -m power test 2/3/4 -a src test.some.other.power") await st.run("knx addr -t out -m binary test 2/3/5 -a src test.some.other.switch") await st.run("knx addr -t out -m percentU8 test 2/3/6 -a src test.some.other.percent") knx = await KNXroot.as_handler(client) await st.run("data get -rd_ :", do_stdout=False) evt = anyio.create_event() await st.tg.spawn( partial(task, client, client._cfg.knx, knx["test"]["localhost"], evt=evt) ) await evt.wait() se = t.exposed_sensor("some_sensor", "1/2/3", value_type="power") sw = t.switch("some_switch", "1/2/4") sp = t.exposed_sensor("some_percent", "1/2/5", value_type="percentU8") te = t.sensor("some_other_sensor", "2/3/4", value_type="power") tw = t.binary_sensor("some_other_switch", "2/3/5") tp = t.sensor("some_other_percent", "2/3/6", value_type="percentU8") assert te.sensor_value.value is None assert tw.state.value == 2 # None assert tp.sensor_value.value is None await anyio.sleep(2.5) await se.set(42) await sw.set_on() await sp.set(18) await client.set(P("test.some.other.power"), 33) await client.set(P("test.some.other.switch"), True) await client.set(P("test.some.other.percent"), 68) await anyio.sleep(2.5) await st.run("data get -rd_ :", do_stdout=False) assert te.sensor_value.value == 33 assert tw.state.value == 1 assert tp.sensor_value.value == 68 ve = await client.get(P("test.some.power")) vw = await client.get(P("test.some.switch")) vp = await client.get(P("test.some.percent")) assert ve.value == 42 assert vw.value == 1 assert vp.value == 18
async def test_basic(): # no autojump async with stdtest( test_0={"init": 125}, n=1, tocks=200) as st, st.client(0) as client, Tester().run() as t: await st.run(f"akumuli server test -h 127.0.0.1 -p {TCP_PORT}") await st.run("akumuli set test.foo.bar test.one.two whatever foo=bar") aki = await AkumuliRoot.as_handler(client) await st.tg.spawn(task, client, client._cfg.akumuli, aki["test"]) await anyio.sleep(0.5) await client.set(P("test.one.two"), value=42) await anyio.sleep(0.5) await aki["test"].flush() n = 0 async for x in t.get_data("whatever", tags={}, t_start=time() - 1000, t_end=time() + 1000): n += 1 assert x[0] == 42 assert abs(time() - x[1].timestamp()) < 10 assert n == 1 pass
async def list_(obj, path): """Emit the state as a YAML file.""" path = P(path) await data_get(obj, obj.cfg.akumuli.prefix + path)
async def test_split(autojump_clock): # pylint: disable=unused-argument async with test_server() as s: async with s.test_client() as c1, s.test_client() as c2: await c1.set(P("test.a.b.c"), value=123) res = await c2.get(P("test.a.b.c")) assert res.value == 123
async def test_basic(autojump_clock): # pylint: disable=unused-argument async with test_client() as c: await c.set(P("test.a.b.c"), value=123) res = await c.get(P("test.a.b.c")) assert res.value == 123