Пример #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
 async def respond(s, event):
     if event | DeviceMessages.GetPower:
         event.set_replies(DeviceMessages.StatePower(level=s.device_attrs.power))
     elif event | DeviceMessages.SetPower:
         event.set_replies(DeviceMessages.StatePower(level=s.device_attrs.power))
         await s.device_attrs.attrs_apply(
             s.device_attrs.attrs_path("power").changer_to(event.pkt.level), event=event
         )
Пример #3
0
        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 DeviceMessages.SetPower(level=65535, target=pkt.serial)
                    else:
                        yield DeviceMessages.SetPower(level=0, target=pkt.serial)
Пример #4
0
 async def gen(sd, reference, **kwargs):
     assert await (
         yield DeviceMessages.EchoRequest(echoing=b"hi", target=V.device.serial)
     )
     assert not await (
         yield DeviceMessages.EchoRequest(echoing=b"hi", target=V.device2.serial)
     )
     for i in range(5):
         assert await (
             yield DeviceMessages.EchoRequest(echoing=b"hi", target=V.device.serial)
         )
Пример #5
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"])
Пример #6
0
    async def respond(self, device, pkt, source):
        if pkt | DeviceMessages.GetGroup:
            yield DeviceMessages.StateGroup(
                group=device.attrs.group.uuid,
                label=device.attrs.group.label,
                updated_at=device.attrs.group.updated_at,
            )

        elif pkt | DeviceMessages.GetLocation:
            yield DeviceMessages.StateLocation(
                location=device.attrs.location.uuid,
                label=device.attrs.location.label,
                updated_at=device.attrs.location.updated_at,
            )
Пример #7
0
 async def respond(s, event):
     if event | DeviceMessages.GetPower:
         event.set_replies(DeviceMessages.StatePower(level=s.device_attrs.power))
     if event | DeviceMessages.GetLabel:
         event.ignore_request()
     elif event | DeviceMessages.SetPower:
         event.set_replies(DeviceMessages.StatePower(level=s.device_attrs.power))
         await s.device_attrs.attrs_apply(
             s.device_attrs.attrs_path("power").changer_to(event.pkt.level),
             event=None,
         )
     elif event | DiscoveryMessages.GetService:
         event.set_replies(
             DiscoveryMessages.StateService(service=Services.UDP, port=56700),
             DiscoveryMessages.StateService(service=Services.UDP, port=76500),
         )
Пример #8
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})
Пример #9
0
 def setup(self):
     self.log_args = (PhotonsAppError("stuff happens", one=1),)
     self.log_kwargs = {
         "pkt": DeviceMessages.SetPower(level=65535),
         "other": [1, 2],
         "more": True,
     }
Пример #10
0
    async def start(self, serial, info, target, afr):
        errors = []

        plans = ["chain"]
        if info.get("initial") is None:
            info["initial"] = {"colors": [], "power": 65535}
            plans.append("colors")
            plans.append("power")

        plans = make_plans(*plans)
        gatherer = Gatherer(target)

        got = await gatherer.gather_all(plans,
                                        serial,
                                        afr,
                                        error_catcher=errors)
        if errors:
            return errors, info

        chain = got[serial][1]["chain"]
        power = got[serial][1].get("power")
        colors = got[serial][1].get("colors")

        if power is not None:
            info["initial"]["power"] = power["level"]
        if colors is not None:
            info["initial"]["colors"] = colors

        pixel_coords = user_coords_to_pixel_coords(chain["coords_and_sizes"])
        info["coords"] = [top_left for top_left, _ in pixel_coords]
        info["reorient"] = chain["reorient"]

        if info.get("pixels") is None:
            canvas = Canvas()

            def dcf(i, j):
                return Color(0, 0, 0, 3500)

            canvas.default_color_func = dcf

            length = len(info["coords"])
            self.style_maker.set_canvas(canvas, length)
            info["pixels"], info["color_pixels"] = make_rgb_and_color_pixels(
                canvas, length)

            msgs = [DeviceMessages.SetPower(level=65535)]
            msgs.extend(
                canvas_to_msgs(
                    canvas,
                    coords_for_horizontal_line,
                    duration=1,
                    acks=True,
                    reorient=info["reorient"],
                ))
            await target.script(msgs).run_with_all(serial,
                                                   afr,
                                                   error_catcher=errors)

        return errors, info
Пример #11
0
 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)
Пример #12
0
async def doit(collector):
    lan_target = collector.resolve_target("lan")

    async for pkt in lan_target.send(DeviceMessages.GetVersion(),
                                     FoundSerials()):
        if pkt | DeviceMessages.StateVersion:
            product = Products[pkt.vendor, pkt.product]
            print(f"{pkt.serial}: {product.as_dict()}")
Пример #13
0
 async def __anext__(self):
     self.index += 1
     if self.index == 0:
         return (
             DeviceMessages.StatePower(level=0, target="d073d5000001"),
             ("192.168.0.1", 56700),
             "192.168.0.1",
         )
     elif self.index == 1:
         return (
             DeviceMessages.StateHostFirmware(
                 build=0, version_major=1, version_minor=2, target="d073d5000002"
             ),
             ("`92.168.0.2", 56700),
             "192.168.0.2",
         )
     else:
         raise StopAsyncIteration
Пример #14
0
    def power_message(self, state):
        power_level = 65535 if state["power"] == "on" else 0

        if state.get("duration") in (sb.NotSpecified, "", 0, None):
            return DeviceMessages.SetPower(level=power_level,
                                           res_required=False)
        else:
            return LightMessages.SetLightPower(level=power_level,
                                               duration=state["duration"],
                                               res_required=False)
Пример #15
0
    def make_response(self, pkt, protocol):
        self.received.append(pkt)

        if pkt | LightMessages.GetInfrared:
            return LightMessages.StateInfrared(brightness=self.infrared)

        if pkt | LightMessages.GetColor:
            return LightMessages.LightState(
                  hue = self.hue
                , saturation = self.saturation
                , brightness = self.brightness
                , kelvin = self.kelvin
                , label = self.label
                , power = self.power
                )

        elif pkt | DeviceMessages.GetVersion:
            return DeviceMessages.StateVersion(
                  vendor = self.vendor_id
                , product = self.product_id
                , version = 0
                )

        elif pkt | DeviceMessages.GetHostFirmware:
            return DeviceMessages.StateHostFirmware(
                  version = self.firmware_version
                , build = self.firmware_build_time
                )

        elif pkt | DeviceMessages.GetGroup:
            return DeviceMessages.StateGroup(
                  group = self.group
                , label = self.group_label
                , updated_at = self.group_updated_at
                )

        elif pkt | DeviceMessages.GetLocation:
            return DeviceMessages.StateLocation(
                  location = self.location
                , label = self.location_label
                , updated_at = self.location_updated_at
                )
Пример #16
0
 async def __anext__(self):
     self.index += 1
     if self.index == 0:
         return (
             DeviceMessages.StatePower(level=0, target="d073d5000001"),
             ("192.168.0.1", 56700),
             "192.168.0.1",
         )
     elif self.index == 1:
         self.kwargs["error_catcher"](PhotonsAppError("failure", serial="d073d5000002"))
         raise StopAsyncIteration
Пример #17
0
async def tile_serials_from_reference(reference, sender):
    """
    Given a reference, return all the serials that has a ``has_matrix`` capability
    """
    serials = []

    async for pkt in sender(DeviceMessages.GetVersion(), reference):
        if pkt | DeviceMessages.StateVersion:
            if Products[pkt.vendor, pkt.product].cap.has_matrix:
                serials.append(pkt.serial)

    return serials
Пример #18
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()
                ),
            }
Пример #19
0
                async def write(s, transport, bts, original_message):
                    called.append("write")

                    pkt = Messages.unpack(bts, protocol_register=protocol_register)

                    res = DeviceMessages.EchoResponse(
                        source=pkt.source, sequence=pkt.sequence, target=pkt.target, echoing=b"pong"
                    )

                    loop = asyncio.get_event_loop()
                    bts = res.pack().tobytes()
                    addr = ("fake://device", 56700)
                    loop.call_soon(s.session.sync_received_data, bts, addr)
Пример #20
0
class LabelPlan(Plan):
    """Return the label of this device"""

    messages = [DeviceMessages.GetLabel()]
    default_refresh = 5

    class Instance(Plan.Instance):
        def process(self, pkt):
            if pkt | DeviceMessages.StateLabel:
                self.label = pkt.label
                return True

        async def info(self):
            return self.label
Пример #21
0
class AddressPlan(Plan):
    """
    Return the ``(ip, port)`` for this device
    """

    messages = [DeviceMessages.EchoRequest(echoing=b"get_remote_addr")]

    class Instance(Plan.Instance):
        def process(self, pkt):
            self.address = pkt.Information.remote_addr
            return True

        async def info(self):
            return self.address
Пример #22
0
async def tile_serials_from_reference(target, reference, afr):
    """
    Given a reference, return all the serials that has a ``has_chain`` capability
    """
    serials = []

    async for pkt, _, _ in target.script(DeviceMessages.GetVersion()).run_with(
            reference, afr):
        if pkt | DeviceMessages.StateVersion:
            cap = capability_for_ids(pkt.product, pkt.vendor)
            if cap.has_chain:
                serials.append(pkt.serial)

    return serials
Пример #23
0
 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)
Пример #24
0
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']}")
Пример #25
0
class VersionPlan(Plan):
    """
    Return in a dictionary:

    * vendor: The vendor id of the device.
    * product: The product id of the device.
    """

    messages = [DeviceMessages.GetVersion()]

    class Instance(Plan.Instance):
        def process(self, pkt):
            if pkt | DeviceMessages.StateVersion:
                self.dct = pkt.payload.as_dict()
                return True

        async def info(self):
            return self.dct
Пример #26
0
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())
Пример #27
0
    async def respond(self, event):
        if event | DeviceMessages.GetLabel:
            event.add_replies(self.state_for(DeviceMessages.StateLabel))

        elif event | DeviceMessages.GetPower:
            event.add_replies(self.state_for(DeviceMessages.StatePower))

        elif event | DeviceMessages.SetLabel:
            await self.change_one("label", event.pkt.label, event=event)
            event.add_replies(self.state_for(DeviceMessages.StateLabel))

        elif event | DeviceMessages.SetPower:
            event.add_replies(self.state_for(DeviceMessages.StatePower))
            await self.change_one("power", event.pkt.level, event=event)

        elif event | DeviceMessages.EchoRequest:
            event.add_replies(
                DeviceMessages.EchoResponse(echoing=event.pkt.echoing))
Пример #28
0
async def do_apply_theme(target, reference, afr, options):
    aps = appliers[options.theme]

    theme = Theme()
    for color in options.colors:
        theme.add_hsbk(color.hue, color.saturation, color.brightness,
                       color.kelvin)

    tasks = []
    async for pkt, _, _ in target.script(DeviceMessages.GetVersion()).run_with(
            reference, afr):
        serial = pkt.serial
        capability = capability_for_ids(pkt.product, pkt.vendor)
        if capability.has_multizone:
            log.info(hp.lc("Found a strip", serial=serial))
            t = hp.async_as_background(
                apply_zone(aps["1d"], target, afr, pkt.serial, theme,
                           options.overrides))
        elif capability.has_chain:
            log.info(hp.lc("Found a tile", serial=serial))
            t = hp.async_as_background(
                apply_tile(aps["2d"], target, afr, pkt.serial, theme,
                           options.overrides))
        else:
            log.info(hp.lc("Found a light", serial=serial))
            t = hp.async_as_background(
                apply_light(aps["0d"], target, afr, pkt.serial, theme,
                            options.overrides))

        tasks.append((serial, t))

    results = {}

    for serial, t in tasks:
        try:
            await t
        except Exception as error:
            results[serial] = error
        else:
            results[serial] = "ok"

    return results
Пример #29
0
class PowerPlan(Plan):
    """
    Return in a dictionary:

    * level: The current power level on the device
    * on: ``False`` if the level is 0, otherwise ``True``
    """

    messages = [DeviceMessages.GetPower()]
    default_refresh = 1

    class Instance(Plan.Instance):
        def process(self, pkt):
            if pkt | DeviceMessages.StatePower:
                self.level = pkt.level
                self.on = pkt.level > 0
                return True

        async def info(self):
            return {"level": self.level, "on": self.on}
Пример #30
0
    async def execute(self):
        fltr = chp.filter_from_matcher(self.matcher, self.refresh)

        result = chp.ResultBuilder()
        afr = await self.finder.args_for_run()
        reference = self.finder.find(filtr=fltr)

        serials = await tile_serials_from_reference(self.target, reference,
                                                    afr)
        if not serials:
            raise FoundNoDevices("Didn't find any tiles")

        await self.target.script(DeviceMessages.SetPower(level=65535)
                                 ).run_with_all(serials,
                                                afr,
                                                error_catcher=result.error)

        result.result["results"]["tiles"] = await tile_dice(
            self.target, serials, afr, error_catcher=result.error)

        return result