Пример #1
0
class InfoPoints(enum.Enum):
    """
    Enum used to determine what information is required for what keys
    """

    # We need to know what kind of product the device is to get the label correctly
    VERSION = Point(DeviceMessages.GetVersion(), ["label", "product_id", "cap"], None)

    # We get Label from LIGHT_STATE for lights and from STATE_LABEL for non lights
    LIGHT_STATE = Point(
        LightMessages.GetColor(),
        ["label", "power", "hue", "saturation", "brightness", "kelvin"],
        10,
        # Non lights are unimportant enough at this time to risk sending too many messages to them
        condition=lambda device: device.product_type is not DeviceType.NON_LIGHT,
    )
    LABEL = Point(
        DeviceMessages.GetLabel(),
        ["label"],
        10,
        condition=lambda device: device.product_type is DeviceType.NON_LIGHT,
    )

    FIRMWARE = Point(DeviceMessages.GetHostFirmware(), ["firmware_version"], 300)
    GROUP = Point(DeviceMessages.GetGroup(), ["group_id", "group_name"], 60)
    LOCATION = Point(DeviceMessages.GetLocation(), ["location_id", "location_name"], 60)
Пример #2
0
class InfoPoints(enum.Enum):
    """
    Enum used to determine what information is required for what keys
    """
    LIGHT_STATE = Point(
        LightMessages.GetColor(),
        ["label", "power", "hue", "saturation", "brightness", "kelvin"])
    VERSION = Point(DeviceMessages.GetVersion(),
                    ["product_id", "product_identifier", "cap"])
    FIRMWARE = Point(DeviceMessages.GetHostFirmware(), ["firmware_version"])
    GROUP = Point(DeviceMessages.GetGroup(), ["group_id", "group_name"])
    LOCATION = Point(DeviceMessages.GetLocation(),
                     ["location_id", "location_name"])
Пример #3
0
class CapabilityPlan(Plan):
    """
    Return capability information for this device::

        {
          "cap": <capability object with filled out firmware version>,
          "product": <product object>,
          "firmware": <object with build/version_major/version_minor attributes>,
          "state_version": <the StateVersion packet we received from the device>
        }

    The capability and product objects come from the
    :ref:`registry <products_root>`.
    """

    messages = [DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion()]

    class Instance(Plan.Instance):
        def process(self, pkt):
            if pkt | DeviceMessages.StateHostFirmware:
                self.firmware = FirmwareInfo(
                    build=pkt.build,
                    version_major=pkt.version_major,
                    version_minor=pkt.version_minor,
                )
            elif pkt | DeviceMessages.StateVersion:
                self.version = pkt
            return hasattr(self, "firmware") and hasattr(self, "version")

        async def info(self):
            product = Products[self.version.vendor, self.version.product]
            cap = product.cap(self.firmware.version_major, self.firmware.version_minor)
            return {
                "cap": cap,
                "product": product,
                "firmware": self.firmware,
                "state_version": DeviceMessages.StateVersion.Payload.create(
                    self.version.payload.pack()
                ),
            }
Пример #4
0
class FirmwarePlan(Plan):
    """
    Return in a dictionary

    * build - The build timestamp of this firmware
    * version_major - the major component of the firmware version
    * version_minor - the minor component of the firmware version
    """

    messages = [DeviceMessages.GetHostFirmware()]

    class Instance(Plan.Instance):
        def process(self, pkt):
            if pkt | DeviceMessages.StateHostFirmware:
                self.firmware = FirmwareInfo(
                    build=pkt.build,
                    version_major=pkt.version_major,
                    version_minor=pkt.version_minor,
                )
                return True

        async def info(self):
            return self.firmware
Пример #5
0
            async for serial, cap in find_multizone(devices.serials, sender):
                assert serial not in got
                got[serial] = cap.has_extended_multizone

            assert got == {
                striplcm1.serial: False,
                striplcm2noextended.serial: False,
                striplcm2extended.serial: True,
            }

        async it "resends messages each time if we reset the gatherer", sender:
            async for serial, cap in find_multizone(devices.serials, sender):
                pass

            want = {
                device: [DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion()]
                for device in devices
            }
            self.compare_received(want)

            del sender.gatherer
            async for serial, cap in find_multizone(devices.serials, sender):
                pass

            want = {
                device: [DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion()]
                for device in devices
            }
            self.compare_received(want)

        async it "uses cached gatherer on the sender", sender:
Пример #6
0
            expected = {
                clean.serial: (True, {"zones": Skip}),
                switch.serial: (True, {"zones": Skip}),
                light1.serial: (True, {"zones": Skip}),
                light2.serial: (True, {"zones": Skip}),
                striplcm1.serial: (True, {"zones": [(i, c) for i, c in enumerate(zones1)]}),
                striplcm2noextended.serial: (
                    True,
                    {"zones": [(i, c) for i, c in enumerate(zones2)]},
                ),
                striplcm2extended.serial: (True, {"zones": [(i, c) for i, c in enumerate(zones3)]}),
            }
            assert got == expected

            expected = {
                clean: [DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion()],
                switch: [DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion()],
                light1: [DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion()],
                light2: [DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion()],
                striplcm1: [
                    DeviceMessages.GetHostFirmware(),
                    DeviceMessages.GetVersion(),
                    MultiZoneMessages.GetColorZones(start_index=0, end_index=255),
                ],
                striplcm2noextended: [
                    DeviceMessages.GetHostFirmware(),
                    DeviceMessages.GetVersion(),
                    MultiZoneMessages.GetColorZones(start_index=0, end_index=255),
                ],
                striplcm2extended: [
                    DeviceMessages.GetHostFirmware(),
Пример #7
0
            "group_id": "aa000000000000000000000000000000",
            "product_id": 27,
            "product_name": "LIFX A19",
            "product_type": "light",
            "group_name": "g1",
            "location_id": "bb000000000000000000000000000000",
            "location_name": "l1",
        }

        for device in V.devices:
            if device is V.d3:
                V.devices.store(device).assertIncoming(
                    DiscoveryMessages.GetService(),
                    LightMessages.GetColor(),
                    DeviceMessages.GetVersion(),
                    DeviceMessages.GetHostFirmware(),
                    DeviceMessages.GetGroup(),
                    DeviceMessages.GetLocation(),
                )
            elif device is V.d4:
                V.devices.store(device).assertIncoming(
                    DiscoveryMessages.GetService(),
                    DeviceMessages.GetVersion(),
                    LightMessages.GetColor(),
                    DeviceMessages.GetLabel(),
                )
            else:
                V.devices.store(device).assertIncoming(
                    DiscoveryMessages.GetService(),
                    DeviceMessages.GetVersion(),
                    LightMessages.GetColor(),
        async def checker():
            info = {"serial": V.fake_device.serial}

            await futs[1]
            assert V.device.info == info

            await asyncio.wait(all_futs)
            assert V.t.time == len(all_futs) - 1

            V.received(*msgs)

            info.update(
                {
                    "label": "kitchen",
                    "power": "off",
                    "hue": 0.0,
                    "saturation": 1.0,
                    "brightness": 1.0,
                    "kelvin": 3500,
                    "firmware_version": "2.80",
                    "product_id": 27,
                    "product_identifier": "lifx_a19",
                    "cap": [
                        "color",
                        "not_chain",
                        "not_ir",
                        "not_matrix",
                        "not_multizone",
                        "variable_color_temp",
                    ],
                    "group_id": "aa000000000000000000000000000000",
                    "group_name": "g1",
                }
            )
            assert V.device.info == info

            await asyncio.wait([Futs.color])
            V.received(
                LightMessages.GetColor(), keep_duplicates=True,
            )
            if V.t.time == 16:
                V.t.set(15)
            assert V.t.time == len(all_futs) + 10

            await asyncio.wait([Futs.group, Futs.location])
            V.received(
                *([LightMessages.GetColor()] * 3),
                DeviceMessages.GetGroup(),
                DeviceMessages.GetLocation(),
                keep_duplicates=True,
            )
            # First location was at t=4
            # We then wait until at least 64
            # 60 is at 12 rounds, and next location after that is after 5
            assert V.t.time >= 69

            assert V.device.point_futures[InfoPoints.LIGHT_STATE].result() == 61
            await asyncio.wait([Futs.color])
            V.received(
                LightMessages.GetColor(), keep_duplicates=True,
            )
            assert V.t.time <= 76

            await asyncio.wait([Futs.firmware])
            # First firmware was at t=2
            # So next refresh after 102
            # So needs a full cycle after that
            assert V.t.time >= 107

            V.received(
                LightMessages.GetColor(),
                LightMessages.GetColor(),
                DeviceMessages.GetHostFirmware(),
                keep_duplicates=True,
            )
Пример #9
0
        assert len(devices) > 0

        for device in devices:
            if device not in expected:
                assert False, f"No expectation for {device.serial}"

        for device, msgs in expected.items():
            assert device in devices
            devices.store(device).assertIncoming(*msgs, ignore=[DiscoveryMessages.GetService])
            devices.store(device).clear()

    async it "sets the default config", sender:
        expected = {
            light1: [
                DeviceMessages.GetHostFirmware(),
                DeviceMessages.GetVersion(),
                LightMessages.SetHevCycleConfiguration(indication=True, duration_s=3600),
            ],
            light2: [
                DeviceMessages.GetHostFirmware(),
                DeviceMessages.GetVersion(),
                LightMessages.SetHevCycleConfiguration(indication=True, duration_s=3600),
            ],
            light3: [DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion()],
        }
        await self.run_and_compare(
            sender, SetCleanConfig(indication=True, duration_s=3600), expected=expected
        )

Пример #10
0
        async it "complains if we have more than 16 colors in the palette", runner:
            with assertRaises(PhotonsAppError, "Palette can only be up to 16 colors", got=17):
                SetTileEffect("flame", palette=["red"] * 17)

        async it "can power on devices and set tile effect", runner:
            msg = SetTileEffect("flame")
            got = await runner.sender(msg, runner.serials)
            assert got == []

            for tile in tiles:
                assert tile.attrs.matrix_effect is TileEffectType.FLAME

            self.compare_received(
                {
                    nottile: [DeviceMessages.GetHostFirmware(), DeviceMessages.GetVersion()],
                    tile1: [
                        DeviceMessages.GetHostFirmware(),
                        DeviceMessages.GetVersion(),
                        LightMessages.SetLightPower(level=65535, duration=1),
                        TileMessages.SetTileEffect.empty_normalise(
                            type=TileEffectType.FLAME,
                            palette=default_tile_palette,
                            palette_count=len(default_tile_palette),
                        ),
                    ],
                    tile2: [
                        DeviceMessages.GetHostFirmware(),
                        DeviceMessages.GetVersion(),
                        LightMessages.SetLightPower(level=65535, duration=1),
                        TileMessages.SetTileEffect.empty_normalise(
Пример #11
0
        async def checker(ff):
            info = {"serial": V.fake_device.serial, "product_type": "unknown"}

            assert V.device.info == info
            await hp.wait_for_all_futures(
                *[
                    V.device.point_futures[kls]
                    for kls in InfoPoints
                    if kls is not InfoPoints.LIGHT_STATE
                ]
            )

            found = []
            for kls in list(InfoPoints):
                if kls is not InfoPoints.LIGHT_STATE:
                    found.append(V.device.point_futures[kls].result())
            assert found == [1, 2, 3, 4, 5]

            assert V.t.time == 5

            V.received(*msgs)

            info.update(
                {
                    "label": "switcharoo",
                    "firmware_version": "3.90",
                    "product_id": 89,
                    "product_name": "LIFX Switch",
                    "product_type": "non_light",
                    "cap": pytest.helpers.has_caps_list("buttons", "unhandled", "relays"),
                    "group_id": "aa000000000000000000000000000000",
                    "group_name": "g1",
                    "location_id": "bb000000000000000000000000000000",
                    "location_name": "l1",
                }
            )
            assert V.device.info == info

            await hp.wait_for_all_futures(Futs.label)
            V.received(DeviceMessages.GetLabel(), keep_duplicates=True)
            assert V.t.time == 12

            await hp.wait_for_all_futures(Futs.group, Futs.location)
            V.received(
                *([DeviceMessages.GetLabel()] * 5),
                DeviceMessages.GetGroup(),
                DeviceMessages.GetLocation(),
                keep_duplicates=True,
            )
            # First location was at t=5
            # We then wait another 60
            # 60 is at 12 rounds, and next location after that is after 5
            assert V.t.time == 65

            assert V.device.point_futures[InfoPoints.LABEL].result() == 62
            await hp.wait_for_all_futures(Futs.label)
            V.received(DeviceMessages.GetLabel(), keep_duplicates=True)
            # 62 + 10 = 72
            assert V.t.time == 72

            await hp.wait_for_all_futures(Futs.firmware)
            assert V.device.point_futures[InfoPoints.LABEL].result() == 102
            assert V.t.time == 103

            V.received(
                DeviceMessages.GetLabel(),
                DeviceMessages.GetLabel(),
                DeviceMessages.GetLabel(),
                DeviceMessages.GetHostFirmware(),
                keep_duplicates=True,
            )

            ff.cancel()
Пример #12
0
        async def checker(ff):
            info = {"serial": V.fake_device.serial, "product_type": "unknown"}

            assert V.device.info == info
            await hp.wait_for_all_futures(
                *[V.device.point_futures[kls] for kls in InfoPoints if kls is not InfoPoints.LABEL]
            )

            found = []
            for kls in list(InfoPoints):
                if kls is not InfoPoints.LABEL:
                    found.append(V.device.point_futures[kls].result())
            assert found == [1, 2, 3, 4, 5]

            assert V.t.time == 5

            V.received(*msgs)

            info.update(
                {
                    "label": "kitchen",
                    "power": "off",
                    "hue": 0.0,
                    "saturation": 0.0,
                    "brightness": 1.0,
                    "kelvin": 3500,
                    "firmware_version": "2.80",
                    "product_id": 27,
                    "product_name": "LIFX A19",
                    "product_type": "light",
                    "cap": pytest.helpers.has_caps_list("color", "variable_color_temp"),
                    "group_id": "aa000000000000000000000000000000",
                    "group_name": "g1",
                    "location_id": "bb000000000000000000000000000000",
                    "location_name": "l1",
                }
            )
            assert V.device.info == info

            await hp.wait_for_all_futures(Futs.color)
            V.received(LightMessages.GetColor(), keep_duplicates=False)
            assert V.t.time == 12

            await hp.wait_for_all_futures(Futs.group, Futs.location)
            V.received(
                *([LightMessages.GetColor()] * 5),
                DeviceMessages.GetGroup(),
                DeviceMessages.GetLocation(),
                keep_duplicates=True,
            )
            # First location was at t=5
            # We then wait another 60
            # 60 is at 12 rounds, and next location after that is after 5
            assert V.t.time == 65

            assert V.device.point_futures[InfoPoints.LIGHT_STATE].result() == 62
            await hp.wait_for_all_futures(Futs.color)
            V.received(LightMessages.GetColor(), keep_duplicates=True)
            # 62 + 10 = 72
            assert V.t.time == 72

            await hp.wait_for_all_futures(Futs.firmware)
            assert V.device.point_futures[InfoPoints.LIGHT_STATE].result() == 102
            assert V.t.time == 103

            V.received(
                LightMessages.GetColor(),
                LightMessages.GetColor(),
                LightMessages.GetColor(),
                DeviceMessages.GetHostFirmware(),
                keep_duplicates=True,
            )

            ff.cancel()
Пример #13
0
        for device in devices:
            if device not in expected:
                assert False, f"No expectation for {device.serial}"

        for device, msgs in expected.items():
            assert device in devices
            devices.store(device).assertIncoming(*msgs, ignore=[DiscoveryMessages.GetService])
            devices.store(device).clear()

    async it "sends the messages to devices with only correct capability", sender:

        msg = ForCapability(hev=LightMessages.GetHevCycle())

        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 = {