async def gen(reference, sender, **kwargs): get_power = DeviceMessages.GetPower() async for pkt in sender(get_power, reference, **kwargs): if pkt | DeviceMessages.StatePower: if pkt.level == 0: yield DeviceMessages.SetPower(level=65535, target=pkt.serial) else: yield DeviceMessages.SetPower(level=0, target=pkt.serial)
def setup(self): self.log_args = (PhotonsAppError("stuff happens", one=1),) self.log_kwargs = { "pkt": DeviceMessages.SetPower(level=65535), "other": [1, 2], "more": True, }
async def start(self, serial, info, target, afr): errors = [] plans = ["chain"] if info.get("initial") is None: info["initial"] = {"colors": [], "power": 65535} plans.append("colors") plans.append("power") plans = make_plans(*plans) gatherer = Gatherer(target) got = await gatherer.gather_all(plans, serial, afr, error_catcher=errors) if errors: return errors, info chain = got[serial][1]["chain"] power = got[serial][1].get("power") colors = got[serial][1].get("colors") if power is not None: info["initial"]["power"] = power["level"] if colors is not None: info["initial"]["colors"] = colors pixel_coords = user_coords_to_pixel_coords(chain["coords_and_sizes"]) info["coords"] = [top_left for top_left, _ in pixel_coords] info["reorient"] = chain["reorient"] if info.get("pixels") is None: canvas = Canvas() def dcf(i, j): return Color(0, 0, 0, 3500) canvas.default_color_func = dcf length = len(info["coords"]) self.style_maker.set_canvas(canvas, length) info["pixels"], info["color_pixels"] = make_rgb_and_color_pixels( canvas, length) msgs = [DeviceMessages.SetPower(level=65535)] msgs.extend( canvas_to_msgs( canvas, coords_for_horizontal_line, duration=1, acks=True, reorient=info["reorient"], )) await target.script(msgs).run_with_all(serial, afr, error_catcher=errors) return errors, info
async def inner_gen(level, reference, sender2, **kwargs2): assert sender is sender2 del kwargs2["error_catcher"] kwargs1 = dict(kwargs) del kwargs1["error_catcher"] assert kwargs1 == kwargs2 assert reference in devices.serials yield DeviceMessages.SetPower(level=level)
def power_message(self, state): power_level = 65535 if state["power"] == "on" else 0 if state.get("duration") in (sb.NotSpecified, "", 0, None): return DeviceMessages.SetPower(level=power_level, res_required=False) else: return LightMessages.SetLightPower(level=power_level, duration=state["duration"], res_required=False)
async def execute(self): fltr = chp.filter_from_matcher(self.matcher, self.refresh) result = chp.ResultBuilder() afr = await self.finder.args_for_run() reference = self.finder.find(filtr=fltr) serials = await tile_serials_from_reference(self.target, reference, afr) if not serials: raise FoundNoDevices("Didn't find any tiles") await self.target.script(DeviceMessages.SetPower(level=65535) ).run_with_all(serials, afr, error_catcher=result.error) result.result["results"]["tiles"] = await tile_dice( self.target, serials, afr, error_catcher=result.error) return result
async def doit(collector): lan_target = collector.resolve_target("lan") parser = argparse.ArgumentParser() parser.add_argument("--reference", default="_") parser.add_argument("--brightness", type=float, default=1) args = parser.parse_args() reference = collector.reference_object(args.reference) power_on = DeviceMessages.SetPower(level=65535) spread = 1 color_names = [ "blue", "red", "orange", "yellow", "cyan", "green", "blue", "purple", "pink" ] color_msgs = [ ColourParser.msg( name, overrides={ "res_required": False, "duration": spread, "brightness": args.brightness, }, ) for name in color_names ] colors = Pipeline(*color_msgs, spread=spread, synchronized=True) pipeline = Pipeline(power_on, Repeater(colors, min_loop_time=len(color_names)), synchronized=True) def e(error): log.error(error) await lan_target.send(pipeline, reference, message_timeout=1, error_catcher=e)
async def restore(self, serial, initial, target, afr): msgs = [DeviceMessages.SetPower(level=initial["power"])] for i, colors in enumerate(initial["colors"]): msgs.append( TileMessages.Set64( tile_index=i, length=1, width=8, x=0, y=0, colors=colors, res_required=False, ack_required=True, )) def errors(e): log.error(hp.lc("Error restoring tile", serial=serial, error=e)) await target.script(msgs).run_with_all(serial, afr, error_catcher=errors)
async def doit(): async with lan_target.session() as afr: # By using a pipeline we can introduce a wait time between successful sending of colors colors = Pipeline(*color_msgs, spread=spread, synchronized=True) # by having power_on and get_color in an array we are sending both at the same time # without waiting for the other to get a reply first # We use a pipeline so that the power is turned on before we start the colors pipeline = Pipeline([power_on, get_color], colors, synchronized=True) original_colors = {} async for pkt, _, _ in lan_target.script(pipeline).run_with( FoundSerials(), afr): # We set res_required on the colors to False on line 20 # Which means only the ``get_color`` messages will return a LightState # We use this to record what the color of the light was before the rainbow if pkt | LightMessages.LightState: color = "kelvin:{kelvin} hue:{hue} saturation:{saturation} brightness:{brightness}" original_colors[pkt.target] = (pkt.power, color.format( **pkt.payload.as_dict())) await asyncio.sleep(spread) msgs = [] for target, (level, color) in original_colors.items(): msg1 = Parser.color_to_msg(color, overrides={"duration": spread}) msg2 = DeviceMessages.SetPower(level=level) # By setting the target directly on the message we don't have to # provide the references to the run_with_all call for msg in (msg1, msg2): msg.target = target msg.res_required = False msgs.append(msg) # We share the afr we got from target.session() so that we don't have to search for the ips of the lights again await lan_target.script(msgs).run_with_all(None, afr)
) async it "has set commands", devices, server: expected = {"results": {device.serial: "ok" for device in devices}} await server.assertCommand( "/v1/lifx/command", {"command": "set", "args": {"pkt_type": "SetPower", "pkt_args": {"level": 0}}}, json_output=expected, ) for device in devices: io = device.io["MEMORY"] assert ( devices.store(device).count( Events.INCOMING(device, io, pkt=DeviceMessages.SetPower(level=0)) ) == 1 ) devices.store(device).clear() # With an offline light bathroom_light = devices["d073d5000002"] async with bathroom_light.offline(): expected["results"]["d073d5000002"] = { "error": { "message": "Timed out. Waiting for reply to a packet", "sent_pkt_type": 21, "source": mock.ANY, "sequence": mock.ANY, },
light1.serial: (True, {"hev_status": Skip}), clean.serial: ( True, { "hev_status": { "current": { "active": False, }, "last": {"result": LightLastHevCycleResult.SUCCESS}, } }, ), } async it "works with different last result", sender, m: await sender(DeviceMessages.SetPower(level=65535), clean.serial) await sender(LightMessages.SetHevCycle(enable=True, duration_s=2000), clean.serial) await m.add(22) got = await self.gather(sender, [clean.serial, light1.serial], "hev_status") assert got == { light1.serial: (True, {"hev_status": Skip}), clean.serial: ( True, { "hev_status": { "current": { "active": True, "duration_s": 2000, "remaining": 1978, "last_power": 65535,
d.start = pytest.helpers.AsyncMock(name="start") d.finish = pytest.helpers.AsyncMock(name="finish") with assertRaises(ValueError, "NOPE"): async with WithDevices(devices): for d in devices: d.start.assert_called_once_with() assert len(d.finish.mock_calls) == 0 raise ValueError("NOPE") for d in devices: d.finish.assert_called_once_with() describe "pktkeys": it "can get us deduped keys to represent the packets": msg1 = DeviceMessages.SetPower(level=65535, source=1, sequence=2, target="d073d501") msg2 = DeviceMessages.SetLabel(label="bob", source=3, sequence=4, target="d073d502") msg3 = DeviceMessages.SetLabel(label="bob", source=5, sequence=6, target="d073d503") keys = pktkeys([msg1, msg2, msg3]) assert keys == [(1024, 21, '{"level": 65535}'), (1024, 24, '{"label": "bob"}')] it "can be told to keep duplicates": msg1 = DeviceMessages.SetPower(level=65535, source=1, sequence=2, target="d073d501") msg2 = DeviceMessages.SetLabel(label="bob", source=3, sequence=4, target="d073d502") msg3 = DeviceMessages.SetLabel(label="bob", source=5, sequence=6, target="d073d503") keys = pktkeys([msg1, msg2, msg3], keep_duplicates=True) assert keys == [ (1024, 21, '{"level": 65535}'), (1024, 24, '{"label": "bob"}'),
expected = { a19: [DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion()], clean: [ DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion(), LightMessages.GetHevCycle(), ], ir: [DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion()], } await self.assertScript(sender, msg, expected=expected) async it "can send message to groups", sender: msg = ForCapability(**{"ir,hev": DeviceMessages.SetPower(level=65535)}) expected = { a19: [DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion()], clean: [ DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion(), DeviceMessages.SetPower(level=65535), ], ir: [ DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion(), DeviceMessages.SetPower(level=65535), ], }
assert got[device.serial][0] | DeviceMessages.StatePower async it "Sends all the messages that are yielded", sender: async def gen(reference, sender, **kwargs): get_power = DeviceMessages.GetPower() async for pkt in sender(get_power, reference, **kwargs): if pkt | DeviceMessages.StatePower: if pkt.level == 0: yield DeviceMessages.SetPower(level=65535, target=pkt.serial) else: yield DeviceMessages.SetPower(level=0, target=pkt.serial) expected = { light1: [DeviceMessages.GetPower(), DeviceMessages.SetPower(level=65535)], light2: [DeviceMessages.GetPower(), DeviceMessages.SetPower(level=0)], light3: [DeviceMessages.GetPower(), DeviceMessages.SetPower(level=65535)], } await self.assertScript(sender, gen, expected=expected) async it "does not ignore exception in generator", sender: error = Exception("NOPE") async def gen(reference, sender, **kwargs): raise error yield DeviceMessages.GetPower() expected = {light1: [], light2: [], light3: []} with assertRaises(BadRun, _errors=[error]):
async def doit(): color_msg = Parser.color_to_msg("blue") on_msg = DeviceMessages.SetPower(level=65535) script = lan_target.script([color_msg, on_msg]) await script.run_with_all(FoundSerials())
describe "can send over memory": @pytest.fixture() async def device(self, final_future, make_device): device = make_device() async with device.session(final_future): yield device @pytest.fixture() async def sender(self, final_future, device): configuration = {"final_future": final_future, "protocol_register": protocol_register} async with MemoryTarget.create(configuration, {"devices": [device]}).session() as sender: yield sender async it "can send and receive messages using memory target", sender, device: pkts = await sender(DeviceMessages.SetPower(level=65535), device.serial) assert len(pkts) == 1 pkt = pkts[0] assert pkt | DeviceMessages.StatePower assert pkt.level == 0 pkts = await sender(DeviceMessages.GetPower(), device.serial) assert len(pkts) == 1 pkt = pkts[0] assert pkt | DeviceMessages.StatePower assert pkt.level == 65535 pkts = await sender(DeviceMessages.SetPower(level=0, res_required=False), device.serial) assert len(pkts) == 0 pkts = await sender(DeviceMessages.GetPower(), device.serial)
assert not e.handled assert e.replies == [reply1, reply2] e.add_replies([reply3, reply4]) assert not e.handled assert e.replies == [reply1, reply2, reply3, reply4] e.add_replies(reply5) assert not e.handled assert e.replies == [reply1, reply2, reply3, reply4, reply5] it "modifies args and kwargs for console output", EKLS, device, io: e = EKLS( device, io, pkt=DeviceMessages.SetPower(source=2, sequence=1, target=None, level=65535), bts="aa", addr=("somewhere", "nice"), ) assertConsoleOutput( e, "2021-05-16 11:00:01.650000+1000 -> d073d5001337(LCM2_A19:2,80) INCOMING", f" || packet = SetPower(ack=True,res=True,source={e.pkt.source},sequence=1,target=000000000000)", " ^^ level: 65535", " :: bts = 'aa'", " :: io = 'TEST_IO'", " :: addr = ('somewhere', 'nice')", ) e = EKLS( device,
async def doit(collector): lan_target = collector.resolve_target("lan") color_msg = ColourParser.msg("blue") on_msg = DeviceMessages.SetPower(level=65535) await lan_target.send([color_msg, on_msg], FoundSerials())
from photons_colour import Parser import asyncio collector = library_setup() lan_target = collector.configuration['target_register'].resolve("lan") color_names = [ "blue", "red", "orange", "yellow", "cyan", "green", "blue", "purple", "pink" ] spread = 2 power_on = DeviceMessages.SetPower(level=65535) get_color = LightMessages.GetColor() color_msgs = [ Parser.color_to_msg(name, overrides={ "res_required": False, "duration": spread }) for name in color_names ] async def doit(): async with lan_target.session() as afr: # By using a pipeline we can introduce a wait time between successful sending of colors colors = Pipeline(*color_msgs, spread=spread, synchronized=True)
) await runner.sender(msg, runner.serials) assert len(runner.devices) > 0 for device in runner.devices: if device not in expected: assert False, f"No expectation for {device.serial}" device.compare_received(expected[device]) async it "returns an empty list if no power or color options": assert Transformer.using({}) == [] async it "Uses SetPower if no duration", runner: msg = DeviceMessages.SetPower(level=0, res_required=False) expected = {device: [msg] for device in runner.devices} await self.transform(runner, {"power": "off"}, expected=expected) await runner.reset_devices() msg = DeviceMessages.SetPower(level=65535, res_required=False) expected = {device: [msg] for device in runner.devices} await self.transform(runner, {"power": "on"}, expected=expected) async it "uses SetLightPower if we have duration", runner: msg = LightMessages.SetLightPower(level=0, duration=100, res_required=False) expected = {device: [msg] for device in runner.devices} await self.transform(runner, {"power": "off", "duration": 100}, expected=expected) await runner.reset_devices() msg = LightMessages.SetLightPower(level=65535, duration=20, res_required=False)
wait = hp.create_future() async def see_request(event): if event | DeviceMessages.SetPower: called.append(event.pkt.serial) if len(called) == 3 and not wait.done(): wait.set_result(True) await asyncio.sleep(0) await wait isr1 = light1.io["MEMORY"].packet_filter.intercept_see_request(see_request) isr2 = light2.io["MEMORY"].packet_filter.intercept_see_request(see_request) isr3 = light3.io["MEMORY"].packet_filter.intercept_see_request(see_request) msgs = [ DeviceMessages.SetPower(level=0), LightMessages.SetColor(hue=0, saturation=0, brightness=1, kelvin=4500), ] got = defaultdict(list) with isr1, isr2, isr3: async for pkt in sender(msgs, reference): print(pkt.serial, type(pkt.payload)) got[pkt.serial].append(pkt) assert all(serial in got for serial in devices.serials), got for serial, pkts in got.items(): print(f"GOT: {serial}") for p in pkts:
async def gen(reference, sender, **kwargs): with alter_called(("secondary", i)): async with hp.tick(0.1) as ticks: async for _ in ticks: called.append(("secondary", i)) yield DeviceMessages.SetPower(level=0)
) await device.assertResponse( DeviceMessages.SetLabel(label="sam"), [DeviceMessages.StateLabel(label="sam")], label="sam", ) await device.assertResponse( DeviceMessages.GetLabel(), [DeviceMessages.StateLabel(label="sam")], label="sam" ) async it "responds to power messages", device: await device.assertResponse( DeviceMessages.GetPower(), [DeviceMessages.StatePower(level=0)] ) await device.assertResponse( DeviceMessages.SetPower(level=200), [DeviceMessages.StatePower(level=0)], power=200 ) await device.assertResponse( DeviceMessages.GetPower(), [DeviceMessages.StatePower(level=200)], power=200 ) async it "responds to light power messages", device: await device.assertResponse( DeviceMessages.GetPower(), [DeviceMessages.StatePower(level=0)] ) await device.assertResponse( LightMessages.SetLightPower(level=200), [LightMessages.StateLightPower(level=0)], power=200, ) await device.assertResponse(