The Product Registry

Different LIFX devices have a range of capabilities. For example, the LIFX+ range have the ability to output Infrared light, and the Tile has a 2d matrix of zones.

You can query devices for their product id to work out what kind of device it is and use that to then determine what you can do with the device. This is done with the GetVersion message, which gives you a vendor and product. The vendor is always 1 to specify the device is a LIFX device. There may be additional vendor values in the future.

Photons provides a registry of the products that allow you to match the vendor and product to an object that tells you what capabilities are available.

You can get this object by doing something like:

from photons_messages import DeviceMessages
from photons_products import Products


async def my_script(sender, reference):
    async for pkt in sender(DeviceMessages.GetVersion(), reference):
        if pkt | DeviceMessages.StateVersion:
            cap = Products[pkt.vendor, pkt.product].cap
            have = "has" if cap.has_ir else "doesn't have"
            print(f"device {pkt.serial} {have} infrared ability")

Some capabilities are dependent on the firmware version, which you can get with the GetHostFirmware message. If you have a StateVersion and StateHostFirmware message then you can do something like:

from photons_app.tasks import task_register as task

from photons_messages import DeviceMessages
from photons_products import Products

from collections import defaultdict


@task
class has_multizone(task.Task):
    """Print if the device supports multizone"""
    target = task.requires_target()
    reference = task.provides_reference(special=True)

    async def execute_task(self, **kwargs):
        by_device = defaultdict(dict)

        async with self.target.session() as sender:
            async for pkt in sender(
                [DeviceMessages.GetVersion(), DeviceMessages.GetHostFirmware()], self.reference
            ):
                if pkt | DeviceMessages.StateVersion:
                    by_device[pkt.serial]["version"] = pkt
                elif pkt | DeviceMessages.StateHostFirmware:
                    by_device[pkt.serial]["firmware"] = pkt

            for serial, pkts in by_device.items():
                version = pkts["version"]
                firmware = pkts["firmware"]

                # Calling cap with the major and minor parts of the firmware version
                # will return a new capability object that then knows what
                # firmware is on the device.
                cap = Products[version.vendor, version.product].cap(
                    firmware.version_major, firmware.version_minor
                )

                if cap.has_extended_multizone:
                    print(f"device {serial} has extended multizone capability")
                elif cap.has_multizone:
                    print(f"device {serial} has multizone, but not extended multizone")
                else:
                    print(f"device {serial} doesn't have any multizone capability")


if __name__ == "__main__":
    __import__("photons_core").run("lan:has_multizone {@:1:}")

The problem with this script is you have to wait for all the devices to return values before you get any results. If you want to print the information as devices return information, you can use the gatherer:

from photons_app.tasks import task_register as task


@task
class has_multizone(task.Task):
    """Print if the device supports multizone"""
    target = task.requires_target()
    reference = task.provides_reference(special=True)

    async def execute_task(self, **kwargs):
        async with self.target.session() as sender:
            plans = sender.make_plans("capability")

            async for serial, complete, info in sender.gatherer.gather_per_serial(
                plans, self.reference
            ):
                if complete:
                    cap = info["capability"]["cap"]

                    if cap.has_extended_multizone:
                        print(f"device {serial} has extended multizone capability")
                    elif cap.has_multizone:
                        print(f"device {serial} has multizone, but not extended multizone")
                    else:
                        print(f"device {serial} doesn't have any multizone capability")


if __name__ == "__main__":
    __import__("photons_core").run("lan:has_multizone {@:1:}")

You can see the available capabilities and the products that photons knows about.