Exemplo n.º 1
0
    async def execute_task(self, **kwargs):
        extra = self.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 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,
                        )

        await self.target.send(FromGenerator(gen), self.reference)
Exemplo n.º 2
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.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 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,
                    )

    await target.send(FromGenerator(gen), reference)
Exemplo n.º 3
0
def PowerToggle(duration=1, **kwargs):
    """
    Returns a valid message that will toggle the power of devices used against it.

    For example:

    .. code-block:: python

        await target.send(PowerToggle(), ["d073d5000001", "d073d5000001"])
    """
    async def gen(reference, sender, **kwargs):
        get_power = DeviceMessages.GetPower()
        async for pkt in sender(get_power, reference, **kwargs):
            if pkt | DeviceMessages.StatePower:
                if pkt.level == 0:
                    yield LightMessages.SetLightPower(level=65535,
                                                      res_required=False,
                                                      duration=duration,
                                                      target=pkt.serial)
                else:
                    yield LightMessages.SetLightPower(level=0,
                                                      res_required=False,
                                                      duration=duration,
                                                      target=pkt.serial)

    return FromGenerator(gen)
Exemplo n.º 4
0
    async def matches(self, sender, fltr, collections, points=None):
        if fltr is None:
            return True

        pts = points
        if pts is None:
            pts = list(self.points_from_fltr(fltr))

        async def gen(reference, sender, **kwargs):
            for e in pts:
                if e.value.condition and not e.value.condition(self):
                    continue
                if self.final_future.done():
                    return
                if not self.point_futures[e].done():
                    yield e.value.msg

        msg = FromGenerator(gen, reference_override=self.serial)
        async for pkt in sender(msg, self.serial, limit=self.limit):
            if pkt | CoreMessages.StateUnhandled:
                continue
            point = self.set_from_pkt(pkt, collections)
            self.point_futures[point].reset()
            self.point_futures[point].set_result(time.time())

        # Without the information loop we ask for all the messages before getting replies
        # And so the switch doesn't respond to LIGHT_STATE
        # And it doesn't know to send LABEL yet
        # So we force that to happen!
        if points is None and InfoPoints.LABEL in pts and self.product_type is DeviceType.NON_LIGHT:
            if self.label is sb.NotSpecified:
                await self.matches(sender, fltr, collections, points=[InfoPoints.LABEL])

        return self.matches_fltr(fltr)
Exemplo n.º 5
0
        def make_secondary_msg(i, m):
            async def gen(reference, sender, **kwargs):
                with alter_called(("secondary", i)):
                    async with hp.tick(0.1) as ticks:
                        async for _ in ticks:
                            called.append(("secondary", i))
                            yield DeviceMessages.SetPower(level=0)

            return FromGenerator(gen, reference_override=True)
Exemplo n.º 6
0
        def make_primary_msg(m):
            async def gen(reference, sender, **kwargs):
                with alter_called("primary"):
                    async with hp.tick(0.3) as ticks:
                        async for i, _ in ticks:
                            called.append(("primary", i))
                            yield make_secondary_msg(i, m)

            return FromGenerator(gen, reference_override=True)
Exemplo n.º 7
0
    def power_on_and_color(self,
                           state,
                           keep_brightness=False,
                           transition_color=False):
        power_message = self.power_message(state)
        color_message = self.color_message(state, keep_brightness)

        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(reference, sender, **kwargs):
            get_color = LightMessages.GetColor(ack_required=False,
                                               res_required=True)

            async for pkt in sender(get_color, reference, **kwargs):
                if pkt | LightMessages.LightState:
                    yield receiver(pkt.serial, pkt.payload)

        return FromGenerator(gen)
Exemplo n.º 8
0
    async def assertScript(self, runner, gen, *, generator_kwargs=None, expected, **kwargs):
        msg = FromGenerator(gen, **(generator_kwargs or {}))
        await runner.sender(msg, runner.serials, **kwargs)

        assert len(runner.devices) > 0

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

            device.compare_received(expected[device])
Exemplo n.º 9
0
    async def execute_task(self, **kwargs):
        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)

        async for pkt in self.target.send(FromGenerator(gen), self.reference):
            print(pkt.serial)
            for tile in tiles_from(pkt):
                print("    ", repr(tile))
Exemplo n.º 10
0
    def apply_scene(scene):
        transformer = Transformer()

        async def gen(reference, sender, **kwargs):
            for state in scene.values():
                if "power" in state:
                    yield transformer.power_message(state)
                if "color" in state:
                    yield transformer.color_message(state,
                                                    keep_brightness=False)

        return FromGenerator(gen)
Exemplo n.º 11
0
def SetZones(colors, power_on=True, reference=None, **options):
    """
    Set colors on all found multizone devices. This will use the extended
    multizone messages if they are supported by the device to increase
    reliability and speed of application.

    Usage looks like:

    .. code-block:: python

        msg = SetZones([["red", 10], ["blue", 10]], zone_index=1, duration=1)
        await target.send(msg, reference)

    By default the devices will be powered on. If you don't want this to happen
    then pass in power_on=False

    If you want to target a particular device or devices, pass in a reference.

    The options to this helper include:

    colors - [[color_specifier, length], …]
        For example, ``[[“red”, 1], [“blue”, 3], [“hue:100 saturation:0.5”, 5]]``

    zone_index - default 0
        An integer representing where on the device to start the colors

    duration - default 1
        Application duration

    overrides - default None
        A dictionary containing hue, saturation, brightness and kelvin for overriding colors with
    """
    async def gen(ref, sender, **kwargs):
        r = ref if reference is None else reference

        plans = {"set_zones": SetZonesPlan(colors, **options)}
        async for serial, _, messages in sender.gatherer.gather(
                plans, r, **kwargs):
            if messages is not Skip:
                if power_on:
                    yield LightMessages.SetLightPower(
                        level=65535,
                        target=serial,
                        duration=options.get("duration", 1),
                        ack_required=True,
                        res_required=False,
                    )

                yield messages

    return FromGenerator(gen)
Exemplo n.º 12
0
    async def execute_task(self, **kwargs):
        async def gen(reference, sender, **kwargs):
            plans = sender.make_plans("capability")
            async for serial, _, info in sender.gatherer.gather(plans, reference):
                print(f"Turning off effects for {serial}")

                yield LightMessages.SetWaveformOptional(res_required=False, target=serial)

                if info["cap"].has_multizone:
                    yield SetZonesEffect("OFF", power_on=False)
                elif info["cap"].has_matrix:
                    yield SetTileEffect("OFF", power_on=False)

        await self.target.send(FromGenerator(gen), self.reference)
Exemplo n.º 13
0
    async def assertScript(self, sender, gen, *, generator_kwargs=None, expected, **kwargs):
        msg = FromGenerator(gen, **(generator_kwargs or {}))
        await sender(msg, devices.serials, **kwargs)

        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()
Exemplo n.º 14
0
async def get_device_chain(collector, target, reference, **kwargs):
    """
    Get the devices in your chain
    """
    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)

    async for pkt in target.send(FromGenerator(gen), reference):
        print(pkt.serial)
        for tile in tiles_from(pkt):
            print("    ", repr(tile))
Exemplo n.º 15
0
    def script(self, raw):
        """Return us a ScriptRunner for the given `raw` against this `target`"""
        items = list(self.simplify(raw))
        if not items:
            items = None
        elif len(items) > 1:
            original = items

            async def gen(*args, **kwargs):
                for item in original:
                    yield item

            items = list(self.simplify(FromGenerator(gen, reference_override=True)))[0]
        else:
            items = items[0]
        return self.script_runner_kls(items, target=self)
Exemplo n.º 16
0
    def msg(kls, options):
        if not isinstance(options, Options):
            options = Options.FieldSpec().normalise(Meta(options, []), options)

        async def gen(reference, sender, **kwargs):
            serials = []
            canvases = []
            combined_canvas = Canvas()

            plans = sender.make_plans("parts")
            async for serial, _, info in sender.gatherer.gather(plans, reference, **kwargs):
                serials.append(serial)
                for part in info:
                    if part.device.cap.has_chain:
                        combined_canvas.add_parts(part)
                    else:
                        nxt = Canvas()
                        nxt.add_parts(part)
                        canvases.append(nxt)

            if combined_canvas:
                canvases.append(combined_canvas)

            msgs = []

            if options.power_on:
                for serial in serials:
                    msgs.append(
                        LightMessages.SetLightPower(
                            level=65535,
                            duration=options.duration,
                            target=serial,
                            res_required=False,
                        )
                    )

            for canvas in canvases:
                Applier(canvas, options.colors).apply()

                for msg in canvas.msgs(
                    options.override_layer, duration=options.duration, acks=True
                ):
                    msgs.append(msg)

            yield msgs

        return FromGenerator(gen)
Exemplo n.º 17
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 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)

    async for pkt in target.send(FromGenerator(gen), 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.º 18
0
    async def matches(self, sender, fltr, collections):
        if fltr is None:
            return True

        async def gen(reference, sender, **kwargs):
            for e in self.points_from_fltr(fltr):
                if self.final_future.done():
                    return
                if not self.point_futures[e].done():
                    yield e.value.msg

        msg = FromGenerator(gen, reference_override=self.serial)
        async for pkt in sender(msg, self.serial, limit=self.limit):
            point = self.set_from_pkt(pkt, collections)
            self.point_futures[point].reset()
            self.point_futures[point].set_result(time.time())

        return self.matches_fltr(fltr)
Exemplo n.º 19
0
async def doit(collector):
    lan_target = collector.resolve_target("lan")

    def e(error):
        log.error(error)

    def apply_scene(scene):
        transformer = Transformer()

        async def gen(reference, sender, **kwargs):
            for state in scene.values():
                if "power" in state:
                    yield transformer.power_message(state)
                if "color" in state:
                    yield transformer.color_message(state,
                                                    keep_brightness=False)

        return FromGenerator(gen)

    scripts = []
    for scene in scenes:
        for serial, options in scene.items():
            options["target"] = serial
        max_duration = max(
            [options.get("duration", 1) for options in scene.values()])
        scripts.append((max_duration, apply_scene(scene)))

    async def gen(reference, sender, **kwargs):
        while True:
            for max_duration, script in scripts:
                start = time.time()
                r = yield script
                await r
                diff = max_duration - (time.time() - start)
                await asyncio.sleep(diff)

    apply_scenes = FromGenerator(gen)

    await lan_target.send(apply_scenes,
                          message_timeout=1,
                          error_catcher=e,
                          find_timeout=10)
Exemplo n.º 20
0
        async def gen(reference, sender, **kwargs):
            async def inner_gen(level, reference, sender2, **kwargs2):
                assert sender is sender2
                del kwargs2["error_catcher"]
                kwargs1 = dict(kwargs)
                del kwargs1["error_catcher"]
                assert kwargs1 == kwargs2
                assert reference in devices.serials
                yield DeviceMessages.SetPower(level=level)

            get_power = DeviceMessages.GetPower()
            async for pkt in sender(get_power, reference, **kwargs):
                if pkt.serial == light1.serial:
                    level = 1
                elif pkt.serial == light2.serial:
                    level = 2
                elif pkt.serial == light3.serial:
                    level = 3
                else:
                    assert False, f"Unknown serial: {pkt.serial}"

                yield FromGenerator(partial(inner_gen, level), reference_override=pkt.serial)
Exemplo n.º 21
0
    async def refresh_information_loop(self, sender, time_between_queries,
                                       collections):
        points = iter(itertools.cycle(list(InfoPoints)))

        time_between_queries = time_between_queries or {}

        refreshes = {}
        for e in InfoPoints:
            if e.value.refresh is None:
                refreshes[e] = None
            else:
                refreshes[e] = time_between_queries.get(
                    e.name, e.value.refresh)

        async def gen(reference, sender, **kwargs):
            async for _ in hp.tick(1):
                if self.final_future.done():
                    return

                e = next(points)
                fut = self.point_futures[e]

                if fut.done():
                    refresh = refreshes[e]
                    if refresh is None:
                        continue

                    if time.time() - fut.result() < refresh:
                        continue

                yield e.value.msg

        msg = FromGenerator(gen, reference_override=self.serial)
        async for pkt in sender(msg, self.serial, limit=self.limit):
            point = self.set_from_pkt(pkt, collections)
            self.point_futures[point].reset()
            self.point_futures[point].set_result(time.time())
Exemplo n.º 22
0
    async def _refresh_information_loop(self, sender, time_between_queries, collections):
        points = iter(itertools.cycle(list(InfoPoints)))
        nxt = next(points)

        def should_send_point(point):
            if point.value.condition and not point.value.condition(self):
                return False

            fut = self.point_futures[point]

            if not fut.done():
                return True

            refresh = refreshes[point]
            if refresh is None:
                return False

            if time.time() - fut.result() < refreshes[point]:
                return False

            return True

        def find_point():
            nonlocal nxt
            started = nxt

            if should_send_point(nxt):
                e = nxt
                nxt = next(points)
                return e

            while True:
                nxt = next(points)
                if nxt is started:
                    return

                if should_send_point(nxt):
                    e = nxt
                    nxt = next(points)
                    return e

        time_between_queries = time_between_queries or {}

        refreshes = {}
        for e in InfoPoints:
            if e.value.refresh is None:
                refreshes[e] = None
            else:
                refreshes[e] = time_between_queries.get(e.name, e.value.refresh)

        async def gen(reference, sender, **kwargs):
            async with hp.tick(
                1,
                final_future=self.final_future,
                name=f"Device({self.serial})::refresh_information_loop[tick]",
            ) as ticks:
                async for info in ticks:
                    if self.final_future.done():
                        return

                    e = find_point()
                    if e is None:
                        continue

                    if self.serial not in sender.found:
                        break

                    t = yield e.value.msg
                    await t

        msg = FromGenerator(gen, reference_override=self.serial)
        async for pkt in sender(msg, self.serial, limit=self.limit, find_timeout=5):
            if pkt | CoreMessages.StateUnhandled:
                continue
            point = self.set_from_pkt(pkt, collections)
            self.point_futures[point].reset()
            self.point_futures[point].set_result(time.time())
Exemplo n.º 23
0
def SetZonesEffect(effect,
                   power_on=True,
                   power_on_duration=1,
                   reference=None,
                   **options):
    """
    Set an effect on your multizone devices

    Where effect is one of the available effect types:

    OFF
        Turn the animation off

    MOVE
        A moving animation

    Options include:

    * offset
    * speed
    * duration

    Usage looks like:

    .. code-block:: python

        msg = SetZonesEffect("MOVE", speed=1)
        await target.send(msg, reference)

    By default the devices will be powered on. If you don't want this to happen
    then pass in ``power_on=False``

    If you want to target a particular device or devices, pass in reference.
    """
    typ = effect
    if type(effect) is str:
        for e in MultiZoneEffectType:
            if e.name.lower() == effect.lower():
                typ = e
                break

    if typ is None:
        available = [e.name for e in MultiZoneEffectType]
        raise PhotonsAppError("Please specify a valid type",
                              wanted=effect,
                              available=available)

    options["type"] = typ
    options["res_required"] = False
    set_effect = MultiZoneMessages.SetMultiZoneEffect.empty_normalise(
        **options)

    async def gen(ref, sender, **kwargs):
        r = ref if reference is None else reference

        plans = sender.make_plans("capability")
        async for serial, _, info in sender.gatherer.gather(
                plans, r, **kwargs):
            if info["cap"].has_multizone:
                if power_on:
                    yield LightMessages.SetLightPower(
                        level=65535,
                        target=serial,
                        duration=power_on_duration,
                        ack_required=True,
                        res_required=False,
                    )

                msg = set_effect.clone()
                msg.target = serial
                yield msg

    return FromGenerator(gen)
Exemplo n.º 24
0
    async it "Can get results", sender:

        async def gen(reference, sender, **kwargs):
            yield DeviceMessages.GetPower(target=light1.serial)
            yield DeviceMessages.GetPower(target=light2.serial)
            yield DeviceMessages.GetPower(target=light3.serial)

        expected = {
            light1: [DeviceMessages.GetPower()],
            light2: [DeviceMessages.GetPower()],
            light3: [DeviceMessages.GetPower()],
        }

        got = defaultdict(list)
        async for pkt in sender.transport_target.send(FromGenerator(gen), devices.serials):
            got[pkt.serial].append(pkt)

        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()

            if expected[device]:
                assert len(got[device.serial]) == 1
Exemplo n.º 25
0
def SetZonesEffect(effect,
                   power_on=True,
                   power_on_duration=1,
                   reference=None,
                   **options):
    """
    Set an effect on your multizone devices

    Where effect is one of the available effect types:

    OFF
        Turn the animation off

    MOVE
        A moving animation

    Options include:

    * speed: duration in seconds to complete one cycle
    * duration: in seconds or specify 0 (the default) to run until manually stopped
    * direction: either "left" or "right" (default: "right")

    Usage looks like:

    .. code-block:: python

        msg = SetZonesEffect("MOVE", speed=1, duration=10, direction="left")
        await target.send(msg, reference)

    By default the devices will be powered on. If you don't want this to happen
    then pass in ``power_on=False``

    If you want to target a particular device or devices, pass in reference.
    """

    typ = effect
    if type(effect) is str:
        for e in MultiZoneEffectType:
            if e.name.lower() == effect.lower():
                typ = e
                break

    if typ is None:
        available = [e.name for e in MultiZoneEffectType]
        raise PhotonsAppError("Please specify a valid type",
                              wanted=effect,
                              available=available)

    options["type"] = typ
    options["res_required"] = False

    direction = options.pop("direction", None)
    if isinstance(direction, str):
        direction = Direction.__members__.get(direction.upper())
    if isinstance(direction, Direction):
        options["parameters"] = {"speed_direction": direction}

    set_effect = MultiZoneMessages.SetMultiZoneEffect.create(**options)

    async def gen(ref, sender, **kwargs):
        r = ref if reference is None else reference

        plans = sender.make_plans("capability")
        async for serial, _, info in sender.gatherer.gather(
                plans, r, **kwargs):
            if info["cap"].has_multizone:
                if power_on:
                    yield LightMessages.SetLightPower(
                        level=65535,
                        target=serial,
                        duration=power_on_duration,
                        ack_required=True,
                        res_required=False,
                    )

                msg = set_effect.clone()
                msg.target = serial
                yield msg

    return FromGenerator(gen)
Exemplo n.º 26
0
def SetTileEffect(effect,
                  power_on=True,
                  power_on_duration=1,
                  reference=None,
                  **options):
    """
    Set an effect on your tiles

    Where effect is one of the available effect types:

    OFF
        Turn the animation off

    FLAME
        A flame effect

    MORPH
        A Morph effect

    Options include:

    * speed
    * duration
    * palette

    Usage looks like:

    .. code-block:: python

        msg = SetTileEffect("MORPH", palette=["red", "blue", "green"])
        await target.send(msg, reference)

    By default the devices will be powered on. If you don't want this to happen
    then pass in ``power_on=False``.

    If you want to target a particular device or devices, pass in reference.
    """
    typ = effect
    if type(effect) is str:
        for e in TileEffectType:
            if e.name.lower() == effect.lower():
                typ = e
                break

    if typ is None:
        available = [e.name for e in TileEffectType]
        raise PhotonsAppError("Please specify a valid type",
                              wanted=effect,
                              available=available)

    options["type"] = typ
    options["res_required"] = False

    if "palette" not in options:
        options["palette"] = default_tile_palette

    if len(options["palette"]) > 16:
        raise PhotonsAppError("Palette can only be up to 16 colors",
                              got=len(options["palette"]))

    options["palette"] = list(make_hsbks([c, 1] for c in options["palette"]))
    options["palette_count"] = len(options["palette"])

    set_effect = TileMessages.SetTileEffect.create(**options)

    async def gen(ref, sender, **kwargs):
        r = ref if reference is None else reference

        ps = sender.make_plans("capability")
        async for serial, _, info in sender.gatherer.gather(ps, r, **kwargs):
            if info["cap"].has_matrix:
                if power_on:
                    yield LightMessages.SetLightPower(
                        level=65535,
                        target=serial,
                        duration=power_on_duration,
                        ack_required=True,
                        res_required=False,
                    )

                msg = set_effect.clone()
                msg.target = serial
                yield msg

    return FromGenerator(gen)
Exemplo n.º 27
0
    async it "Can get results", runner:

        async def gen(reference, sender, **kwargs):
            yield DeviceMessages.GetPower(target=light1.serial)
            yield DeviceMessages.GetPower(target=light2.serial)
            yield DeviceMessages.GetPower(target=light3.serial)

        expected = {
            light1: [DeviceMessages.GetPower()],
            light2: [DeviceMessages.GetPower()],
            light3: [DeviceMessages.GetPower()],
        }

        got = defaultdict(list)
        async for pkt in runner.target.send(FromGenerator(gen), runner.serials):
            got[pkt.serial].append(pkt)

        assert len(runner.devices) > 0

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

            device.compare_received(expected[device])

            assert len(got[device.serial]) == 1
            assert got[device.serial][0] | DeviceMessages.StatePower

    async it "Sends all the messages that are yielded", runner:
Exemplo n.º 28
0
                    Events.ATTRIBUTE_CHANGE(device2, [ChangeAttr.test("power", 0)], True),
                    Events.OUTGOING(
                        device2, io2, pkt=CoreMessages.Acknowledgement(), replying_to=msg
                    ),
                    Events.OUTGOING(device2, io2, pkt=reply, replying_to=msg),
                ]

            async it "is possible to cleanly stop", V, sender, FakeTime, MockedCallLater:
                original = DeviceMessages.EchoRequest(echoing=b"hi", ack_required=False)

                async def gen(sd, reference, **kwargs):
                    async with hp.tick(0, min_wait=0) as ticks:
                        async for _ in ticks:
                            await (yield original)

                msg = FromGenerator(gen, reference_override=True)

                got = []
                with FakeTime() as t:
                    async with MockedCallLater(t, precision=0.01):
                        async with sender(msg, V.device.serial) as pkts:
                            async for pkt in pkts:
                                got.append(pkt)
                                if len(got) == 5:
                                    raise pkts.StopPacketStream()

                assert len(got) == 5
                expected = (DeviceMessages.EchoResponse, {"echoing": b"hi"})
                reply = expected[0].create(**expected[1])
                pytest.helpers.assertSamePackets(got, *[expected] * 5)