예제 #1
0
    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)
예제 #2
0
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)
예제 #3
0
 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)
예제 #4
0
        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)
예제 #5
0
 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)
예제 #6
0
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)
예제 #7
0
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)
예제 #8
0
    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)
예제 #9
0
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)
예제 #10
0
        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)
예제 #11
0
 async def gen(serial, sender, **kwargs):
     assert serial in (light1.serial, light2.serial)
     yield Pipeline([DeviceMessages.GetPower(), DeviceMessages.SetLabel(label="wat")])
예제 #12
0
 async def gen(serial, sender, **kwargs):
     yield Pipeline([DeviceMessages.GetPower(), DeviceMessages.SetLabel(label="wat")])
예제 #13
0
        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))
예제 #14
0
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():
예제 #15
0
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")
예제 #16
0
 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)