示例#1
0
async def doit():
    msg = LightMessages.GetColor()
    async for pkt, _, _ in lan_target.script(msg).run_with(FoundSerials()):
        hsbk = " ".join("{0}={1}".format(key, pkt.payload[key])
                        for key in ("hue", "saturation", "brightness",
                                    "kelvin"))
        print("{0}: {1}".format(pkt.serial, hsbk))
示例#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})
示例#3
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)
示例#4
0
    def transition(self, state, keep_brightness=False):
        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)

        getter = LightMessages.GetColor(ack_required=False, res_required=True)
        return Decider(getter, receiver, [LightMessages.LightState])
示例#5
0
async def doit(collector):
    lan_target = collector.resolve_target("lan")

    msg = LightMessages.GetColor()
    async for pkt in lan_target.send(msg, FoundSerials()):
        hsbk = " ".join("{0}={1}".format(key, pkt.payload[key])
                        for key in ("hue", "saturation", "brightness",
                                    "kelvin"))
        print("{0}: {1}".format(pkt.serial, hsbk))
示例#6
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"])
示例#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 []
async def doit(collector):
    lan_target = collector.resolve_target("lan")

    getter = [DeviceMessages.GetLabel(), LightMessages.GetColor()]

    info = defaultdict(dict)
    async for pkt in lan_target.send(getter, FoundSerials()):
        if pkt | DeviceMessages.StateLabel:
            info[pkt.serial]["label"] = pkt.label
        elif pkt | LightMessages.LightState:
            hsbk = " ".join("{0}={1}".format(key, pkt[key])
                            for key in ("hue", "saturation", "brightness",
                                        "kelvin"))
            info[pkt.serial]["hsbk"] = hsbk

    for serial, details in info.items():
        print(f"{serial}: {details['label']}: {details['hsbk']}")
async def doit():
    getter = [DeviceMessages.GetLabel(), LightMessages.GetColor()]

    def found(serial, *states):
        info = {"label": "", "hsbk": ""}
        for s in states:
            if s | DeviceMessages.StateLabel:
                info["label"] = s.label
            elif s | LightMessages.LightState:
                info["hsbk"] = " ".join("{0}={1}".format(key, s.payload[key])
                                        for key in ("hue", "saturation",
                                                    "brightness", "kelvin"))
        print("{0}: {1}: {2}".format(serial, info["label"], info["hsbk"]))
        return []

    msg = Decider(getter, found,
                  [DeviceMessages.StateLabel, LightMessages.LightState])
    await lan_target.script(msg).run_with_all(FoundSerials())
示例#10
0
                "/v1/lifx/command",
                {
                    "command": "transform",
                    "args": {"transform": {"power": "on", "color": "blue"}, "timeout": 0.2},
                },
                json_output=expected,
            )

        for device in devices:
            io = device.io["MEMORY"]
            if device.attrs.label == "tv":
                devices.store(device).assertNoSetMessages()
            elif not device.cap.is_light:
                assert (
                    devices.store(device).count(
                        Events.UNHANDLED(device, io, pkt=LightMessages.GetColor())
                    )
                    == 1
                )
            elif device.serial in ("d073d5000001", "d073d5000003"):
                devices.store(device).count(
                    Events.INCOMING(
                        device, io, pkt=ColourParser.msg("blue", overrides={"res_required": False})
                    )
                ) == 1
            else:
                for pkt in [
                    ColourParser.msg("blue", overrides={"brightness": 0, "res_required": False}),
                    DeviceMessages.SetPower(level=65535, res_required=False),
                    ColourParser.msg("blue", overrides={"brightness": 0.5, "res_required": False}),
                ]:
示例#11
0
            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(),
                    DeviceMessages.GetVersion(),
                    MultiZoneMessages.GetExtendedColorZones(),
                ],
            }

            for device in devices:
示例#12
0
        assert ss == sorted(V.serials)
        for device in V.devices:
            V.devices.store(device).assertIncoming(DiscoveryMessages.GetService())
            V.devices.store(device).clear()

        reference = DeviceFinder.from_kwargs(label="kitchen")
        found, ss = await reference.find(V.sender, timeout=5)
        reference.raise_on_missing(found)
        assert sorted(list(found)) == sorted(binascii.unhexlify(s)[:6] for s in ss)
        assert ss == []

        for device in V.devices:
            expected = [
                DiscoveryMessages.GetService(),
                DeviceMessages.GetVersion(),
                LightMessages.GetColor(),
            ]
            if device is V.devices["d4"]:
                expected.append(DeviceMessages.GetLabel)
            V.devices.store(device).assertIncoming(*expected)
            V.devices.store(device).clear()

        await V.d3.change_one("label", "kitchen", event=None)
        reference = DeviceFinder.from_kwargs(label="kitchen")
        found, ss = await reference.find(V.sender, timeout=5)
        reference.raise_on_missing(found)
        assert sorted(list(found)) == sorted(binascii.unhexlify(s)[:6] for s in ss)
        assert ss == [V.d3.serial]

        for device in V.devices:
            expected = [
示例#13
0
            power_message = transformer.power_message(state)

            assert color_message is not None
            assert power_message is not None

            await runner.reset_devices()
            expected = {device: [power_message, color_message] for device in runner.devices}
            await self.transform(runner, state, expected=expected)

    describe "When power on and need color":

        async it "sets power on if it needs to", runner:
            state = {"color": "blue", "power": "on"}
            expected = {
                light1: [
                    LightMessages.GetColor(),
                    ColourParser.msg("blue", overrides={"brightness": 0}),
                    DeviceMessages.SetPower(level=65535),
                    ColourParser.msg(
                        "blue", overrides={"brightness": light1.attrs.color.brightness}
                    ),
                ],
                light2: [LightMessages.GetColor(), ColourParser.msg("blue")],
                light3: [LightMessages.GetColor(), ColourParser.msg("blue")],
            }
            await self.transform(runner, state, expected=expected)

        async it "sets power on if it needs to with duration", runner:
            state = {"color": "blue brightness:0.3", "power": "on", "duration": 10}
            expected = {
                light1: [
        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,
            )
                for p, f in s.device.point_futures.items():
                    if p in points:
                        assert f.done() and f.result() == points[p]
                    else:
                        assert not f.done()

        return V()

    async it "can match against a fltr", V:
        V.t.add(1)

        assert await V.matches(None)
        V.received()

        assert await V.matches(Filter.from_kwargs(label="kitchen"))
        V.received(LightMessages.GetColor())
        V.assertTimes({InfoPoints.LIGHT_STATE: 1})
        V.t.add(5)

        assert not (await V.matches(Filter.from_kwargs(label="den")))
        V.received()
        V.assertTimes({InfoPoints.LIGHT_STATE: 1})
        V.t.add(2)

        assert not (await V.matches(Filter.from_kwargs(label="attic", refresh_info=True)))
        V.received(LightMessages.GetColor())
        V.assertTimes({InfoPoints.LIGHT_STATE: 8})
        V.t.add(1)

        assert not (await V.matches(Filter.from_kwargs(group_name="aa", cap=["matrix"])))
        V.received(DeviceMessages.GetVersion(), DeviceMessages.GetGroup())
示例#16
0
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)

        # by having power_on and get_color in an array we are sending both at the same time
        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()
    @pytest.fixture()
    async def finder(self, sender):
        async with Finder(sender) as finder:
            yield finder

    async it "can match against a fltr", sender, finder, fake_time, final_future:
        V = VBase(fake_time, sender, finder, final_future)
        await V.choose_device("light")
        V.t.add(1)

        assert await V.matches(None)
        V.received()

        assert await V.matches(Filter.from_kwargs(label="kitchen"))
        V.received(LightMessages.GetColor())
        V.assertTimes({InfoPoints.LIGHT_STATE: 1, InfoPoints.VERSION: 1})
        V.t.add(5)

        assert not (await V.matches(Filter.from_kwargs(label="den")))
        V.received()
        V.assertTimes({InfoPoints.LIGHT_STATE: 1, InfoPoints.VERSION: 1})
        V.t.add(2)

        assert not (await V.matches(Filter.from_kwargs(label="attic", refresh_info=True)))
        V.received(LightMessages.GetColor())
        V.assertTimes({InfoPoints.LIGHT_STATE: 8, InfoPoints.VERSION: 1})
        V.t.add(1)

        assert not (await V.matches(Filter.from_kwargs(group_name="aa", cap=["matrix"])))
        V.received(DeviceMessages.GetGroup())
            found, ss = await reference.find(runner.sender, timeout=5)
            reference.raise_on_missing(found)
            assert sorted(list(found)) == sorted(binascii.unhexlify(s)[:6] for s in ss)
            assert ss == sorted(V.serials)
            for device in V.devices:
                device.compare_received([])
                device.reset_received()

            reference = DeviceFinder.from_kwargs(label="kitchen")
            found, ss = await reference.find(runner.sender, timeout=5)
            reference.raise_on_missing(found)
            assert sorted(list(found)) == sorted(binascii.unhexlify(s)[:6] for s in ss)
            assert ss == []

            for device in V.devices:
                device.compare_received([LightMessages.GetColor()])
                device.reset_received()

            V.d3.attrs.label = "kitchen"
            reference = DeviceFinder.from_kwargs(label="kitchen")
            found, ss = await reference.find(runner.sender, timeout=5)
            reference.raise_on_missing(found)
            assert sorted(list(found)) == sorted(binascii.unhexlify(s)[:6] for s in ss)
            assert ss == [V.d3.serial]

            for device in V.devices:
                device.compare_received([LightMessages.GetColor()])
                device.reset_received()

            reference = DeviceFinder.from_kwargs(cap="matrix")
            found, ss = await reference.find(runner.sender, timeout=5)
示例#20
0
        return assertUnhandled

    async it "responds to label messages", device, assertResponse:
        await assertResponse(DeviceMessages.GetLabel(), [DeviceMessages.StateLabel(label="")])
        await assertResponse(
            DeviceMessages.SetLabel(label="sam"),
            [DeviceMessages.StateLabel(label="sam")],
            label="sam",
        )
        await assertResponse(
            DeviceMessages.GetLabel(), [DeviceMessages.StateLabel(label="sam")], label="sam"
        )

    async it "replies to light messages with a StateUnhandled packet", device, assertUnhandled:
        await assertUnhandled(LightMessages.GetColor())
        await assertUnhandled(LightMessages.GetLightPower())


describe "LightState":

    @pytest.fixture()
    def device(self):
        device = devices["a19"]
        devices.store(device).assertAttrs(label="", power=0, color=hp.Color(0, 0, 1, 3500))
        return device

    @pytest.fixture()
    def assertResponse(self, device, **attrs):
        return makeAssertResponse(device, **attrs)
        async def checker(ff, l):
            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=True)
            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

            # Now we remove knowledge of the device
            # And expect the information loop to end

            assert V.device.serial in V.sender.found

            async with V.fake_device.offline():
                with assertRaises(FoundNoDevices):
                    await FoundSerials().find(V.sender, timeout=1)

            assert V.device.serial not in V.sender.found

            assert not l.done()

            # This will timeout if it hasn't ended
            await l

            ff.cancel()
示例#22
0
            )

        async it "responds to Color messages", device:

            def light_state(label, power, hue, saturation, brightness, kelvin):
                return LightMessages.LightState.empty_normalise(
                    label=label,
                    power=power,
                    hue=hue,
                    saturation=saturation,
                    brightness=brightness,
                    kelvin=kelvin,
                )

            await device.assertResponse(
                LightMessages.GetColor(), [light_state("", 0, 0, 0, 1, 3500)]
            )

            await device.assertResponse(
                DeviceMessages.SetLabel(label="bob"),
                [DeviceMessages.StateLabel(label="bob")],
                label="bob",
            )
            await device.assertResponse(
                LightMessages.GetColor(), [light_state("bob", 0, 0, 0, 1, 3500)]
            )

            await device.assertResponse(
                DeviceMessages.SetPower(level=300), [DeviceMessages.StatePower(level=0)], power=300
            )
            await device.assertResponse(