Exemplo n.º 1
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)
Exemplo n.º 2
0
    async def execute(self):
        fltr = chp.filter_from_matcher(self.matcher, self.refresh)
        details = await self.finder.info_for(filtr=fltr)

        msgs = []
        for serial, info in details.items():
            msgs.append(DeviceMessages.GetPower(target=serial))

            if "multizone" in info["cap"]:
                msgs.append(
                    MultiZoneMessages.GetColorZones(start_index=0, end_index=255, target=serial)
                )
            elif "chain" in info["cap"]:
                msgs.append(
                    TileMessages.Get64(tile_index=0, length=5, x=0, y=0, width=8, target=serial)
                )
            else:
                msgs.append(LightMessages.GetColor(target=serial))

        state = defaultdict(dict)
        afr = await self.finder.args_for_run()
        async for pkt, _, _ in self.target.script(msgs).run_with(
            None, afr, multiple_replies=True, first_wait=0.5
        ):
            if pkt | DeviceMessages.StatePower:
                state[pkt.serial]["power"] = pkt.level != 0
            elif pkt | LightMessages.LightState:
                hsbk = f"kelvin:{pkt.kelvin} saturation:{pkt.saturation} brightness:{pkt.brightness} hue:{pkt.hue}"
                state[pkt.serial]["color"] = hsbk
            elif pkt | MultiZoneMessages.StateMultiZone:
                if "zones" not in state[pkt.serial]:
                    state[pkt.serial]["zones"] = {}
                for i, zi in enumerate(range(pkt.zone_index, pkt.zone_index + 8)):
                    c = pkt.colors[i]
                    state[pkt.serial]["zones"][zi] = [c.hue, c.saturation, c.brightness, c.kelvin]
            elif pkt | TileMessages.State64:
                if "chain" not in state[pkt.serial]:
                    state[pkt.serial]["chain"] = {}
                colors = [[c.hue, c.saturation, c.brightness, c.kelvin] for c in pkt.colors]
                state[pkt.serial]["chain"][pkt.tile_index] = colors

        scene = []
        for serial, info in sorted(state.items()):
            if "zones" in info:
                info["zones"] = [hsbk for _, hsbk in sorted(info["zones"].items())]
            if "chain" in info:
                info["chain"] = [hsbks for _, hsbks in sorted(info["chain"].items())]

            scene.append({"matcher": {"serial": serial}, **info})

        if self.just_return:
            return scene

        args = {
            "uuid": self.uuid,
            "scene": scene,
            "label": self.label,
            "description": self.description,
        }
        return await self.executor.execute(self.path, {"command": "scene_change", "args": args})
Exemplo n.º 3
0
async def tile_dice(target, serials, afr, **kwargs):
    canvas = Canvas()

    def default_color_func(i, j):
        if j == -3:
            return Color(0, 1, 0.4, 3500)
        return Color(0, 0, 0, 3500)

    canvas.set_default_color_func(default_color_func)

    numbers = ["1", "2", "3", "4", "5"]
    characters = [dice[n] for n in numbers]
    color = Color(100, 1, 1, 3500)
    put_characters_on_canvas(canvas, characters, coords_for_horizontal_line, color)

    orientations = {}
    async for pkt, _, _ in target.script(TileMessages.GetDeviceChain()).run_with(
        serials, afr, **kwargs
    ):
        if pkt | TileMessages.StateDeviceChain:
            orientations[pkt.serial] = orientations_from(pkt)

    made, _ = make_rgb_and_color_pixels(canvas, 5)

    msgs = []
    for serial in serials:
        os = orientations.get(serial)
        for msg in canvas_to_msgs(
            canvas, coords_for_horizontal_line, duration=1, acks=True, orientations=os
        ):
            msg.target = serial
            msgs.append(msg)

    await target.script(msgs).run_with_all(None, afr, **kwargs)
    return made
Exemplo n.º 4
0
async def get_device_chain(collector, target, reference, **kwargs):
    """
    Get the devices in your chain
    """
    async for pkt, _, _ in target.script(
            TileMessages.GetDeviceChain()).run_with(reference):
        if pkt | TileMessages.StateDeviceChain:
            print(pkt.serial)
            for tile in tiles_from(pkt):
                print("   ", repr(tile))
Exemplo n.º 5
0
async def get_tile_positions(collector, target, reference, **kwargs):
    """
    Get the positions of the tiles in your chain.

    ``lan:get_tile_positions d073d5f09124``
    """
    async for pkt, _, _ in target.script(
            TileMessages.GetDeviceChain()).run_with(reference):
        print(pkt.serial)
        for tile in tiles_from(pkt):
            print(f"\tuser_x: {tile.user_x}, user_y: {tile.user_y}")
        print("")
Exemplo n.º 6
0
 async def gen(reference, sender, **kwargs):
     ps = sender.make_plans("capability")
     async for serial, _, info in sender.gatherer.gather(
             ps, reference, **kwargs):
         if info["cap"].has_matrix:
             for i, (user_x, user_y) in enumerate(positions):
                 yield TileMessages.SetUserPosition(
                     tile_index=i,
                     user_x=user_x,
                     user_y=user_y,
                     res_required=False,
                     target=serial,
                 )
Exemplo n.º 7
0
        def messages(self):
            if not self.is_light:
                return Skip

            if self.zones is Zones.SINGLE:
                return [LightMessages.GetColor()]

            elif self.zones is Zones.MATRIX:
                return [
                    TileMessages.Get64(
                        x=0, y=0, tile_index=0, length=255, width=self.deps["chain"]["width"]
                    )
                ]

            else:
                return []
Exemplo n.º 8
0
            def chain_msgs(self, overrides):
                power_message = self.power_message(overrides)
                if power_message:
                    yield power_message

                duration = self.determine_duration(overrides)
                for i, lst in enumerate(self.chain):
                    colors = self.colors_from_hsbks(lst, overrides)
                    yield TileMessages.Set64(
                        tile_index=i,
                        length=1,
                        x=0,
                        y=0,
                        width=8,
                        duration=duration,
                        colors=colors,
                        res_required=False,
                    )
Exemplo n.º 9
0
    async def change(self, serial, tile_index, left_x, top_y, target, afr):
        if serial not in self.serials:
            return {"serial": serial, "data": None}

        user_x = (left_x + 4) / 8
        user_y = (top_y - 4) / 8

        msg = TileMessages.SetUserPosition(tile_index=tile_index,
                                           user_x=user_x,
                                           user_y=user_y,
                                           res_required=False)

        errors = []
        await target.script(msg).run_with_all(serial,
                                              afr,
                                              error_catcher=errors,
                                              message_timeout=5)
        hp.async_as_background(
            self.highlight(serial,
                           tile_index,
                           target,
                           afr,
                           error_catcher=[],
                           message_timeout=3))

        if errors:
            return {"serial": serial, "data": None}

        plans = make_plans(chain=ChainPlan(refresh=True))
        gatherer = Gatherer(target)

        got = await gatherer.gather_all(plans,
                                        serial,
                                        afr,
                                        error_catcher=errors,
                                        message_timeout=5)

        if serial in got and got[serial][0]:
            pixel_coords = user_coords_to_pixel_coords(
                got[serial][1]["chain"]["coords_and_sizes"])
            self.serials[serial]["coords"] = [xy for xy, _ in pixel_coords]

        return {"serial": serial, "data": self.info_for_browser(serial)}
Exemplo n.º 10
0
async def set_tile_positions(collector, target, reference, **kwargs):
    """
    Set the positions of the tiles in your chain.

    ``lan:set_tile_positions d073d5f09124 -- '[[0, 0], [-1, 0], [-1, 1]]'``
    """
    extra = collector.configuration["photons_app"].extra_as_json
    positions = sb.listof(sb.listof(sb.float_spec())).normalise(
        Meta.empty(), extra)
    if any(len(position) != 2 for position in positions):
        raise PhotonsAppError(
            "Please enter positions as a list of two item lists of user_x, user_y"
        )

    async with target.session() as afr:
        for i, (user_x, user_y) in enumerate(positions):
            msg = TileMessages.SetUserPosition(tile_index=i,
                                               user_x=user_x,
                                               user_y=user_y,
                                               res_required=False)
            await target.script(msg).run_with_all(reference, afr)
Exemplo n.º 11
0
    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)
Exemplo n.º 12
0
    def __init__(self):
        self.targets_cache = LRU(1000)
        self.source_bits_cache = LRU(10)
        self.duration_bits_cache = LRU(10)

        self.cache = ProtocolColor.Meta.cache

        msg = TileMessages.SetState64(
              source = 0
            , sequence = 0
            , target = None
            , res_required = False
            , ack_required = True

            , tile_index = 0
            , length = 1
            , x = 0
            , y = 0
            , width = 8
            , duration = 0
            , colors = [{"hue": 0, "saturation": 0, "brightness": 0, "kelvin": 3500}]
            )

        self.frame_header_start = msg.frame_header.pack()[:-32]

        self.frame_address_with_acks_middle = msg.frame_address.pack()[64:-8]
        msg.ack_required = False
        self.frame_address_without_acks_middle = msg.frame_address.pack()[64:-8]

        self.protocol_header_packd = msg.protocol_header.pack()

        # tile_index, width, duration and colors are variable
        self.payload_middle = msg.payload.pack()[8:-8 -32 - (64 * 64)]

        self.uint8_bits = {val: self.bits(T.Uint8, val) for val in range(256)}

        self.width_bits = self.uint8_bits
        self.sequence_bits = self.uint8_bits
        self.tile_index_bits = self.uint8_bits
Exemplo n.º 13
0
    async def tile_msgs(self):
        coords_and_sizes = None
        async for _, _, info in self.gather(self.make_plans("chain")):
            reorient = info["reorient"]
            coords_and_sizes = info["coords_and_sizes"]

        if not coords_and_sizes:
            log.warning(
                hp.lc("Couldn't work out how many zones the device had", serial=self.serial)
            )
            return

        applied = self.aps["2d"].from_user_coords(coords_and_sizes).apply_theme(self.theme)
        for i, (hsbks, coords_and_size) in enumerate(zip(applied, coords_and_sizes)):
            colors = reorient(
                i,
                [
                    {
                        "hue": self.options.overrides.get("hue", hsbk.hue),
                        "saturation": self.options.overrides.get("saturation", hsbk.saturation),
                        "brightness": self.options.overrides.get("brightness", hsbk.brightness),
                        "kelvin": self.options.overrides.get("kelvin", hsbk.kelvin),
                    }
                    for hsbk in hsbks
                ],
            )

            yield TileMessages.Set64(
                tile_index=i,
                length=1,
                x=0,
                y=0,
                width=coords_and_size[1][0],
                duration=self.options.duration,
                colors=colors,
                res_required=False,
                ack_required=True,
            )
Exemplo n.º 14
0
    async def fill(self, random_orientations=False):
        msgs = []
        if self.background_option.type == "current":
            msgs.append(
                TileMessages.GetState64.empty_normalise(tile_index=0,
                                                        length=255,
                                                        x=0,
                                                        y=0,
                                                        width=8))

        msgs.append(TileMessages.GetDeviceChain())

        async for pkt, _, _ in self.target.script(msgs).run_with(
                self.serials, self.afr):
            serial = pkt.serial

            if pkt | TileMessages.State64:
                self.info_by_serial[serial].states.append(
                    (pkt.tile_index, pkt))

            elif pkt | TileMessages.StateDeviceChain:
                if self.coords is None:
                    coords = []
                    for tile in tiles_from(pkt):
                        coords.append(((tile.user_x, tile.user_y),
                                       (tile.width, tile.height)))
                    self.info_by_serial[
                        serial].coords = user_coords_to_pixel_coords(coords)

                orientations = orientations_from(pkt)
                if random_orientations:
                    self.info_by_serial[serial].orientations = {
                        i: random.choice(list(O.__members__.values()))
                        for i in orientations
                    }
                else:
                    self.info_by_serial[serial].orientations = orientations
Exemplo n.º 15
0
        assert part.height == height

        assert part.left == (2 * 8)
        assert part.right == (2 * 8) + 5

        assert part.top == 3 * 8
        assert part.bottom == (3 * 8) - 10

        part._set_64.update({"source": 0, "sequence": 1})
        real_set_64 = TileMessages.Set64(
            x=0,
            y=0,
            length=1,
            tile_index=5,
            colors=[],
            duration=0,
            ack_required=False,
            width=5,
            res_required=False,
            target=V.device.serial,
            source=0,
            sequence=1,
        )
        assert part._set_64.pack()[36 * 8 :] == real_set_64.payload.pack()

    it "can be used as a key in dictionary", V:
        dct = {V.part: 1}
        assert dct[V.part] == 1
        assert dct[(V.device, V.part.part_number)] == 1
        assert dct[(V.device.serial, V.part.part_number)] == 1

    it "can be compared for equality", V:
Exemplo n.º 16
0
            got = await self.gather(sender, serials, "colors")

            assert got[switch.serial][1]["colors"] is Skip
            assert got[light1.serial][1]["colors"] == tile_expected
            assert got[light2.serial][1]["colors"] == [[hp.Color(100, 0.5, 0.8, 2500)]]
            assert got[striplcm1.serial][1]["colors"] == [expectedlcm1]
            assert got[striplcm2extended.serial][1]["colors"] == [expectedlcm2]

            expected = {
                clean: [],
                switch: [DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion()],
                light1: [
                    DeviceMessages.GetHostFirmware(),
                    DeviceMessages.GetVersion(),
                    TileMessages.GetDeviceChain(),
                    TileMessages.Get64(length=255, tile_index=0, width=8, x=0, y=0),
                ],
                light2: [
                    DeviceMessages.GetHostFirmware(),
                    DeviceMessages.GetVersion(),
                    LightMessages.GetColor(),
                ],
                striplcm1: [
                    DeviceMessages.GetHostFirmware(),
                    DeviceMessages.GetVersion(),
                    MultiZoneMessages.GetColorZones(start_index=0, end_index=255),
                ],
                striplcm2noextended: [],
                striplcm2extended: [
                    DeviceMessages.GetHostFirmware(),
Exemplo n.º 17
0
describe "Matrix":

    @pytest.fixture
    def device(self):
        device = devices["tile"]
        devices.store(device).assertAttrs(matrix_effect=TileEffectType.OFF)
        return device

    @pytest.fixture()
    def assertResponse(self, device, **attrs):
        return makeAssertResponse(device, **attrs)

    async it "responds to changing user position", device, assertResponse:
        await assertResponse(
            TileMessages.SetUserPosition(tile_index=1, user_x=0, user_y=1),
            [],
        )
        assert device.attrs.chain[1].user_x == 0
        assert device.attrs.chain[1].user_y == 1

        await assertResponse(
            TileMessages.SetUserPosition(tile_index=1, user_x=3, user_y=4),
            [],
        )
        assert device.attrs.chain[1].user_x == 3
        assert device.attrs.chain[1].user_y == 4

        await assertResponse(
            TileMessages.SetUserPosition(tile_index=2, user_x=4, user_y=5),
            [],
Exemplo n.º 18
0
    describe "MatrixResponder":

        @pytest.fixture
        async def device(self):
            device = Device(
                chp.ProductResponder.from_product(Products.LCM3_TILE), chp.MatrixResponder()
            )

            async with device:
                device.assertAttrs(matrix_effect=TileEffectType.OFF)
                yield device

        async it "responds to tile effect messages", device:
            await device.assertResponse(
                TileMessages.GetTileEffect(),
                [
                    TileMessages.StateTileEffect.empty_normalise(
                        type=TileEffectType.OFF, palette_count=0, parameters={}
                    )
                ],
            )
            await device.assertResponse(
                TileMessages.SetTileEffect(
                    type=TileEffectType.FLAME, palette_count=1, palette=[chp.Color(1, 0, 1, 3500)]
                ),
                [
                    TileMessages.StateTileEffect.empty_normalise(
                        type=TileEffectType.OFF, palette_count=0, parameters={}, palette=[]
                    )
                ],
Exemplo n.º 19
0
 async def gen(reference, sender, **kwargs):
     ps = sender.make_plans("capability")
     async for serial, _, info in sender.gatherer.gather(
             ps, reference, **kwargs):
         if info["cap"].has_matrix:
             yield TileMessages.GetDeviceChain(target=serial)
Exemplo n.º 20
0
 def setter(**kwargs):
     return TileMessages.Set64(
         length=1, x=0, y=0, width=8, res_required=False, **kwargs
     )
Exemplo n.º 21
0
 def messages(self):
     if self.zones is Zones.MATRIX:
         return [TileMessages.GetDeviceChain()]
     elif self.zones is Zones.LINEAR:
         return [MultiZoneMessages.GetColorZones(start_index=0, end_index=0)]
     return []
Exemplo n.º 22
0
 def messages(self):
     if self.zones is Zones.MATRIX:
         return [TileMessages.GetDeviceChain()]
     return []
Exemplo n.º 23
0
 def messages(self):
     if self.is_multizone:
         return [MultiZoneMessages.GetMultiZoneEffect()]
     elif self.is_matrix:
         return [TileMessages.GetTileEffect()]
     return Skip
Exemplo n.º 24
0
    async def highlight(self,
                        serial,
                        tile_index,
                        target,
                        afr,
                        error_catcher=None,
                        message_timeout=3):
        if serial not in self.serials or self.serials[serial][
                "highlightlock"].locked():
            return

        async with self.serials[serial]["highlightlock"]:
            if serial not in self.serials:
                return

            passed = 0
            row = -1
            pixels = self.serials[serial]["color_pixels"][tile_index]
            reorient = self.serials[serial]["reorient"]

            while passed < 2 and not afr.stop_fut.done():
                colors = []
                for i in range(8):
                    if row < i:
                        start = i * 8
                        colors.extend(pixels[start:start + 8])
                    else:
                        colors.extend([{
                            "hue": 0,
                            "saturation": 0,
                            "brightness": 0,
                            "kelvin": 3500
                        }] * 8)

                msg = TileMessages.Set64(
                    tile_index=tile_index,
                    length=1,
                    x=0,
                    y=0,
                    width=8,
                    colors=reorient(tile_index, colors),
                    res_required=False,
                    ack_required=False,
                )

                await target.script(msg).run_with_all(serial,
                                                      afr,
                                                      error_catcher=[])
                await asyncio.sleep(0.075)

                if passed == 0:
                    row += 3
                    if row > 7:
                        passed += 1
                else:
                    row -= 3
                    if row < 0:
                        passed += 1

            if not afr.stop_fut.done():
                msg = TileMessages.Set64(
                    tile_index=tile_index,
                    length=1,
                    x=0,
                    y=0,
                    width=8,
                    colors=reorient(tile_index, pixels),
                    res_required=False,
                    ack_required=True,
                )
                await target.script(msg).run_with_all(serial,
                                                      afr,
                                                      error_catcher=[],
                                                      message_timeout=1)