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)
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)
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
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)}")
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)
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)
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)
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}"')