예제 #1
0
파일: addon.py 프로젝트: delfick/photons
class find_devices(task.Task):
    """
    List the devices that can be found on the network::

        lifx lan:find_devices

    You can specify a different broadcast address by saying::

        lifx lan:find_devices _ 192.168.0.255

    Otherwise it will use the default broadcast address for the target you are
    using. (i.e. the lan target by default broadcasts to 255.255.255.255)

    You can find specific devices by specifying a reference::

        lifx lan:find_devices match:label=kitchen
    """

    target = task.requires_target()
    artifact = task.provides_artifact()
    reference = task.provides_reference(special=True)

    async def execute_task(self, **kwargs):
        broadcast = True
        if self.artifact is not sb.NotSpecified:
            broadcast = self.artifact

        async with self.target.session() as sender:
            _, serials = await self.reference.find(sender,
                                                   timeout=20,
                                                   broadcast=broadcast)
            for serial in serials:
                print(serial)
예제 #2
0
class attr_actual(task.Task):
    """
    Same as the attr command but prints out the actual values on the replies rather than transformed values
    """

    target = task.requires_target()
    artifact = task.provides_artifact()
    reference = task.provides_reference(special=True)

    async def execute_task(self, **kwargs):
        protocol_register = self.collector.configuration["protocol_register"]

        if self.artifact is sb.NotSpecified:
            raise BadOption(
                f"Please specify what you want to get\nUsage: {sys.argv[0]} <target>:attr_actual <reference> <attr_to_get>"
            )

        kls = find_packet(protocol_register, self.artifact, "")
        if kls is None:
            raise BadOption(
                "Sorry, couldn't a class for this message", prefix="", want=self.artifact
            )

        extra = self.photons_app.extra_as_json

        if "extra_payload_kwargs" in kwargs:
            extra.update(kwargs["extra_payload_kwargs"])

        def lines(pkt, indent="    "):
            for field in pkt.Meta.all_names:
                val = pkt[field]
                if isinstance(val, list):
                    yield f"{indent}{field}:"
                    for item in val:
                        ind = f"{indent}    "
                        ls = list(lines(item, ind))
                        first = list(ls[0])
                        first[len(indent) + 2] = "*"
                        ls[0] = "".join(first)
                        yield from ls
                else:
                    yield f"{indent}{field}: {pkt.actual(field)}"

        msg = kls.create(extra)
        async for pkt in self.target.send(msg, self.reference, **kwargs):
            print()
            print(f"""{"=" * 10}: {pkt.serial}""")
            for line in lines(pkt):
                print(line)
예제 #3
0
class AnimationTask(task.Task):
    target = task.requires_target()
    artifact = task.provides_artifact()
    reference = task.provides_reference()

    animation_kls = NotImplemented
    animation_name = None

    async def execute_task(self, **kwargs):
        if self.reference == "help":
            print_help(animation_kls=self.animation_kls,
                       animation_name=self.animation_name)
            return

        self.reference = self.collector.reference_object(self.reference)
        return await self.run_animation(**kwargs)

    @property
    def run_options(self):
        return {}

    @property
    def message_timeout(self):
        return 1

    def error_catcher(self, e):
        log.error(e)

    async def run_animation(self, **kwargs):
        try:
            with self.collector.photons_app.using_graceful_future(
            ) as final_future:
                async with self.target.session() as sender:
                    runner = AnimationRunner(
                        sender,
                        self.reference,
                        self.run_options,
                        final_future=final_future,
                        message_timeout=self.message_timeout,
                        error_catcher=self.error_catcher,
                    )

                    async with runner:
                        await runner.run()
        except Finish:
            pass
예제 #4
0
class attr(task.Task):
    """
    Send a message to your bulb and print out all the replies.

    ``target:attr d073d5000000 GetHostFirmware``
    """

    target = task.requires_target()
    artifact = task.provides_artifact()
    reference = task.provides_reference(special=True)

    async def execute_task(self, **kwargs):
        protocol_register = self.collector.configuration["protocol_register"]

        if self.artifact is sb.NotSpecified:
            raise BadOption(
                f"Please specify what you want to get\nUsage: {sys.argv[0]} <target>:attr <reference> <attr_to_get>"
            )

        kls = find_packet(protocol_register, self.artifact, "")
        if kls is None:
            raise BadOption(
                "Sorry, couldn't a class for this message", prefix="", want=self.artifact
            )

        extra = self.photons_app.extra_as_json

        if "extra_payload_kwargs" in kwargs:
            extra.update(kwargs["extra_payload_kwargs"])

        msg = kls.create(extra)
        async with self.target.session() as sender:
            found, serials = await self.reference.find(sender, timeout=20)
            self.reference.raise_on_missing(found)

            msg = kls.create(extra)
            async for pkt in sender(msg, serials, **kwargs):
                if len(serials) == 1:
                    print(repr(pkt.payload))
                else:
                    print(f"{pkt.serial}: {repr(pkt.payload)}")
예제 #5
0
class tile_effect(task.Task):
    """
    Set an animation on your tile!

    ``lan:tile_effect d073d5000001 <type> -- '{<options>}'``

    Where type is one of the available effect types:

    OFF
        Turn of the animation off

    MORPH
        Move through a perlin noise map, assigning pixel values from a
        16-color palette

    FLAME
        A flame effect

    For effects that take in a palette option, you may specify palette as
    ``[{"hue": 0, "saturation": 1, "brightness": 1, "kelvin": 2500}, ...]``

    or as ``[[0, 1, 1, 2500], ...]`` or as ``[[0, 1, 1], ...]``

    or as ``["red", "hue:100 saturation:1", "blue"]``
    """

    target = task.requires_target()
    artifact = task.provides_artifact()
    reference = task.provides_reference(special=True)

    async def execute_task(self, **kwargs):
        options = self.photons_app.extra_as_json

        if self.artifact is sb.NotSpecified:
            raise PhotonsAppError(
                "Please specify type of effect with --artifact")

        await self.target.send(SetTileEffect(self.artifact, **options),
                               self.reference)
예제 #6
0
class multizone_effect(task.Task):
    """
    Set an animation on your multizone device

    ``lan:multizone_effect d073d5000001 <type> -- '{<options>}'``

    Where type 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 of the effect
      - duration: duration in seconds the effect will run.
      - direction: either "left" or "right" (default: "right")

    Example:
        ``{"speed": 5, "duration": 0, "direction": "left"}``

    """

    target = task.requires_target()
    artifact = task.provides_artifact()
    reference = task.provides_reference(special=True)

    async def execute_task(self, **kwargs):
        options = self.photons_app.extra_as_json

        if self.artifact is sb.NotSpecified:
            raise PhotonsAppError(
                "Please specify type of effect with --artifact")

        await self.target.send(SetZonesEffect(self.artifact, **options),
                               self.reference)
예제 #7
0
class set_color(task.Task):
    """
    Change specified bulb to specified colour

    ``target:set_color d073d50000 red -- '{"hue": 205}'``

    The format of this task is ``<reference> <color> -- <overrides>`` where
    overrides is optional.

    The color may be any valid color specifier.
    """

    target = task.requires_target()
    artifact = task.provides_artifact()
    reference = task.provides_reference(special=True)

    async def execute_task(self, **kwargs):
        overrides = self.photons_app.extra_as_json

        if self.artifact is sb.NotSpecified:
            raise PhotonsAppError("Please specify a color as artifact")

        msg = ColourParser.msg(self.artifact, overrides)
        await self.target.send(msg, self.reference)
예제 #8
0
파일: addon.py 프로젝트: delfick/photons
class find_ips(task.Task):
    """
    List the ips of the devices that can be found on the network

        lifx lan:find_ips

    You can specify a different broadcast address by saying::

        lifx lan:find_ips 192.168.0.255

    Options include:

    cli_output - default True
        Print "{serial}: {ip}" for each device found

        Note that if you choose settings_output or env_output then this will
        default to False. Explicitly setting it to true will turn it on.

    settings_output - default False
        Print yaml output that you can copy into a lifx.yml

    env_output - default False
        Print an ENV variable you can copy into your terminal to set these
        ips as a HARDCODED_DISCOVERY for future commands.
    """

    target = task.requires_target()
    artifact = task.provides_artifact()
    reference = task.provides_reference(special=True)

    async def execute_task(self, **kwargs):
        broadcast = True
        if self.artifact is not sb.NotSpecified:
            broadcast = self.artifact

        options = sb.set_options(
            cli_output=sb.defaulted(sb.boolean(), None),
            env_output=sb.defaulted(sb.boolean(), False),
            settings_output=sb.defaulted(sb.boolean(), False),
        ).normalise(Meta.empty(), self.collector.photons_app.extra_as_json)

        if options["env_output"] is False and options[
                "settings_output"] is False:
            if options["cli_output"] is None:
                options["cli_output"] = True

        env_output = options["env_output"]
        cli_output = options["cli_output"]
        settings_output = options["settings_output"]

        ips = {}

        async with self.target.session() as sender:
            found, serials = await self.reference.find(sender,
                                                       timeout=20,
                                                       broadcast=broadcast)
            for serial in serials:
                services = found[binascii.unhexlify(serial)]
                if Services.UDP in services:
                    ip = services[Services.UDP].host
                    ips[serial] = ip

        sorted_ips = sorted(ips.items(),
                            key=lambda item: ipaddress.ip_address(item[1]))

        if cli_output:
            for serial, ip in sorted_ips:
                print(f"{serial}: {ip}")

        if cli_output and (env_output or settings_output):
            print()

        if env_output:
            print(f"export HARDCODED_DISCOVERY='{json.dumps(sorted_ips)}'")
            if settings_output:
                print()

        if settings_output:
            print("discovery_options:")
            print("  hardcoded_discovery:")

            for serial, ip in sorted_ips:
                print(f'    {serial}: "{ip}"')