def using(kls, state, keep_brightness=False, transition_color=False, **kwargs): transformer = kls() has_color_options = transformer.has_color_options(state) if "power" not in state and not has_color_options: return [] if state.get("power") == "on" and has_color_options: return transformer.power_on_and_color( state, keep_brightness=keep_brightness, transition_color=transition_color) msgs = [] if "power" in state: msgs.append(transformer.power_message(state)) if has_color_options: msgs.append(transformer.color_message(state, keep_brightness)) if len(msgs) == 1: return msgs[0] return Pipeline(*msgs)
async def apply_zone(applier, target, afr, serial, theme, overrides): length = None msg = MultiZoneMessages.GetColorZones(start_index=0, end_index=255) async for pkt, _, _ in target.script(msg).run_with(serial, afr): if pkt | MultiZoneMessages.StateMultiZone: length = pkt.zones_count if length is None: log.warning( hp.lc("Couldn't work out how many zones the light had", serial=serial)) return messages = [] for (start_index, end_index), hsbk in applier(length).apply_theme(theme): messages.append( MultiZoneMessages.SetColorZones(start_index=start_index, end_index=end_index, hue=hsbk.hue, saturation=hsbk.saturation, brightness=hsbk.brightness, kelvin=hsbk.kelvin, duration=overrides.get( "duration", 1), res_required=False, ack_required=True)) set_power = LightMessages.SetLightPower(level=65535, duration=overrides.get( "duration", 1)) pipeline = Pipeline(*messages, spread=0.005) await target.script([set_power, pipeline]).run_with_all(serial, afr)
def script(self, raw): """Return us a ScriptRunnerIterator for the given `raw` against this `target`""" items = list(self.simplify(raw)) if len(items) > 1: items = Pipeline(*items) else: items = items[0] return ScriptRunnerIterator(items, target=self)
def receiver(reference, *states): if not states: return current_state = states[0].as_dict()["payload"] power_message = None if "power" not in state else self.power_message( state) msg_dict = dict(state) h, s, b, k = Parser.hsbk(state.get("color", None), overrides=state) msg_dict.update({ "hue": h, "saturation": s, "brightness": b, "kelvin": k }) final_overrides = dict(msg_dict) pipeline = [] reset = False now_off = current_state["power"] in (None, 0) if now_off: overrides = dict(msg_dict) overrides["brightness"] = 0 if "duration" in overrides: del overrides["duration"] msg = Parser.color_to_msg(None, overrides=overrides) msg.target = reference msg.ack_required = True msg.res_required = False reset = True pipeline.append(msg) if power_message is not None: want_off = power_message.level == 0 if now_off ^ want_off: power_message.target = reference pipeline.append(power_message) if keep_brightness or (reset and "brightness" not in state): final_overrides["brightness"] = current_state["brightness"] msg = Parser.color_to_msg(None, overrides=final_overrides) msg.target = reference msg.ack_required = True msg.res_required = False pipeline.append(msg) yield Pipeline(*pipeline)
async def finding_loop(self): """ Endless loop of finding devices on the network and doing a spaced out information discovery of those devices. """ getter = [e.value.msg for e in InfoPoints] pipeline = Pipeline(*getter, spread=self.repeat_spread, short_circuit_on_error=True) repeater = Repeater(pipeline, min_loop_time=self.information_search_interval) await self.send_to_device(FoundSerials(), repeater)
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 apply_tile(applier, target, afr, serial, theme, overrides): from photons_tile_paint.orientation import Orientation as O, reorient from photons_tile_paint.animation import orientations_from chain = [] orientations = {} async for pkt, _, _ in target.script( TileMessages.GetDeviceChain()).run_with(serial, afr): if pkt | TileMessages.StateDeviceChain: for tile in tiles_from(pkt): chain.append(tile) orientations = orientations_from(pkt) if chain is None: log.warning( hp.lc("Couldn't work out how many tiles the light had", serial=serial)) return coords_and_sizes = [((t.user_x, t.user_y), (t.width, t.height)) for t in chain] messages = [] for i, (hsbks, coords_and_size) in enumerate( zip( applier.from_user_coords(coords_and_sizes).apply_theme(theme), coords_and_sizes)): colors = [{ "hue": overrides.get("hue", hsbk.hue), "saturation": overrides.get("saturation", hsbk.saturation), "brightness": overrides.get("brightness", hsbk.brightness), "kelvin": overrides.get("kelvin", hsbk.kelvin) } for hsbk in hsbks] colors = reorient(colors, orientations.get(i, O.RightSideUp)) messages.append( TileMessages.SetState64(tile_index=i, length=1, x=0, y=0, width=coords_and_size[1][0], duration=overrides.get("duration", 1), colors=colors, res_required=False, ack_required=True)) set_power = LightMessages.SetLightPower(level=65535, duration=overrides.get( "duration", 1)) pipeline = Pipeline(*messages, spread=0.005) await target.script([set_power, pipeline]).run_with_all(serial, afr)
async def add_new_device(self, target, msgs=None): """ A new device was found, send all our information gathering messages to it and put the resulting State messages on the queue for processing. """ if msgs is None: msgs = [] for e in InfoPoints: msgs.append(e.value.msg) pipeline = Pipeline(*msgs, spread=0.2) serial = binascii.hexlify(target).decode() await self.send_to_device(serial, pipeline)
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)
def receiver(serial, current_state): want_brightness = color_message.brightness if color_message.set_brightness else None pipeline = [] currently_off = current_state.power == 0 if currently_off: clone = color_message.clone() clone.period = 0 clone.brightness = 0 clone.set_brightness = True clone.set_hue = 0 if transition_color else clone.set_hue clone.set_saturation = 0 if transition_color else clone.set_saturation clone.set_kelvin = 0 if transition_color else clone.set_kelvin clone.target = serial pipeline.append(clone) clone = power_message.clone() clone.target = serial pipeline.append(clone) set_color = color_message.clone() set_color.target = serial if currently_off: set_color.brightness = (current_state.brightness if want_brightness is None else want_brightness) set_color.set_brightness = True elif want_brightness is not None: set_color.brightness = want_brightness set_color.set_brightness = True pipeline.append(set_color) return Pipeline(*pipeline, synchronized=True)
async def gen(serial, sender, **kwargs): assert serial in (light1.serial, light2.serial) yield Pipeline([DeviceMessages.GetPower(), DeviceMessages.SetLabel(label="wat")])
async def gen(serial, sender, **kwargs): yield Pipeline([DeviceMessages.GetPower(), DeviceMessages.SetLabel(label="wat")])
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 = Pipeline( 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: print("\t", type(p.payload), repr(p.payload))
def loop_time(): return asyncio.get_event_loop().time() describe "Repeater": async it "repeats messages", runner: for use_pipeline in (True, False): pipeline = [ DeviceMessages.SetPower(level=0), LightMessages.SetColor(hue=0, saturation=0, brightness=1, kelvin=4500), ] if use_pipeline: pipeline = Pipeline(*pipeline) msg = Repeater(pipeline, min_loop_time=0) def no_errors(err): assert False, f"Got an error: {err}" got = defaultdict(list) async for pkt in runner.sender(msg, FoundSerials(), error_catcher=no_errors): got[pkt.serial].append(pkt) if all(len(pkts) >= 6 for pkts in got.values()): break assert all(serial in got for serial in runner.serials), got for pkts in got.values():
from collections import defaultdict import asyncio import mock import time import uuid describe AsyncTestCase, "Pipeline": async it "specifies has_children as True": self.assertIs(Pipeline.has_children, True) async it "takes in messages": msg1 = mock.Mock(name="msg1") msg2 = mock.Mock(name="msg2") msg3 = mock.Mock(name="msg3") pipeline = Pipeline(msg1, msg2, msg3) self.assertEqual(pipeline.children, (msg1, msg2, msg3)) describe "simplified": async it "uses the simplifier on each child and returns a new Pipeline with simplified children": result = mock.Mock(name="result") FakePipeline = mock.Mock(name="Pipeline", return_value=result) c1 = mock.Mock(name="c1") c2 = mock.Mock(name="c2") c3 = mock.Mock(name="c3") o1 = mock.Mock(name="o1") o2 = mock.Mock(name="o2") o3 = mock.Mock(name="o3") o4 = mock.Mock(name="o4")
async def doit(): async for info in self.target.script(Pipeline(msg2, msg3, msg4)).run_with([d.target for d in afr.devices], afr): results.append(info)