The Collector
Photons creates a collector
object when instantiated. The collector
is responsible for reading configuration and loading all available Photons
module functionality.
The collector
has several useful attributes:
- configuration
This is a dictionary-like object that contains all the configuration objects created by Photons.
run_coro_as_main(coro)
Runs a co-routine as the main Photons task. Handles initial setup and final cleanup when the co-routine ends or the script is stopped.
- photons_app
The
photons_app
object contains several useful attributes:using_graceful_future()
A context manager that yields a graceful future. This is used by the GracefulTask.
- extra
The JSON string provided after the
--
on the command line. For example, the commandlifx lan:transform -- '{"power": "off"}'
results inphotons_app.extra
containing the string'{"power": "off"}'
.- extra_as_json
A Python dictionary created from
json.loads(self.extra)
. Using the example above,photons_app.extra_as_json
is the Python dictionary{"power": "off"}
.- final_future
A future that is cancelled when the application needs to shutdown.
- cleaners
An array of async functions called when Photons shuts down.
resolve_target(name)
This returns the target with name
name
. See Targets for information on how to create custom targets that are resolved with this function.reference_object(reference)
This accepts a reference or an array of serial numbers e.g.
["d073d5000001", "d073d5000002"]
and it’ll return a special reference object that discovers the specified devices.See the page on using special reference objects for more information on using these objects.
The configuration object
Photons reads configuration from files and creates a merged dictionary of the combined configuration from all specified files.
The configuration object includes several registered converters used to transform values on the object to make them more useful.
By default, the following attributers are available:
configuration["photons_app"]
This is where
collector.photons_app
comes from.configuration["target_register"]
This is the “target register” and holds all the targets in your configuration. To use it you say
configuration["target_register"].resolve("nameoftarget")
or you can use the shortcut on the collector,collector.resolve_target("nameoftarget")
. In your configuration you can reference different targets with{targets.nameoftarget}
.configuration["protocol_register"]
This is the register for all the protocol messages. You only need this if you’re making a target object programmatically, but you can say:
from photons_transport.targets import LanTarget from photons_messages import protocol_register final_future = "<an asyncio.Future that stops sessions from the target when canceled>" my_target = LanTarget.create( {"final_future": final_future, "protocol_register": protocol_register}, {"default_broadcast": "192.168.0.255"}, )
configuration["reference_resolver_register"]
This object knows how to create a Special reference object from a reference,
configuration["reference_resolver_register"].reference_object("d03d75000001")
or you can use the shortcut on the collector as mentioned above,collector.reference_object("d073d5000001")
You can add your own objects by creating a hook that will be loaded when Photons started, and then adding your configuration to the collector.
from photons_app.formatter import MergedOptionStringFormatter
from photons_app.tasks import task_register as task
from photons_transport.targets.base import Target
from photons_messages import DeviceMessages
from delfick_project.norms import dictobj, sb
from delfick_project.addons import addon_hook
class Options(dictobj.Spec):
target = dictobj.Field(format_into=sb.typed(Target), default="{targets.lan}")
message_timeout = dictobj.Field(sb.integer_spec, default=30)
@addon_hook()
def __lifx__(collector, *args, **kwargs):
collector.register_converters(
{
"example_script_options": Options.FieldSpec(
formatter=MergedOptionStringFormatter
)
}
)
@task
class turn_off(task.Task):
"""Turn off devices"""
target = task.requires_target()
reference = task.provides_reference(special=True)
async def execute_task(self, **kwargs):
options = collector.configuration["example_script_options"]
async with options.self.target.session() as sender:
await sender(
DeviceMessages.SetPower(level=0),
self.reference,
message_timeout=options.message_timeout,
)
if __name__ == "__main__":
__import__("photons_core").run("turn_off {@:1:}")
Here, our Options has two attributes: target and message_timeout. target
is
a Target object that defaults to the lan target, and message_timeout is an
integer with a default value of 30.
Then in the __lifx__
hook we say that example_script_options
in your
configuration gets normalised into one of these objects.
So you could say in configuration:
---
example_script_options:
target: "{targets.mytarget}"
kmessage_timeout: 10
targets:
mytarget:
type: lan
options:
default_broadcast: 192.168.0.255
And it’ll use you mytarget
target to turn off your lights using a message
timeout of 10
seconds.
See spec helpers and the dictobj
You can also make your options mandatory by saying:
@addon_hook()
def __lifx__(collector, *args, **kwargs):
collector.register_converters(
{
"example_script_options": sb.required(
Options.FieldSpec(formatter=MergedOptionStringFormatter)
)
}
)
You can then run your script by saying something like python turn_off.py
to
turn off all your lights or python turn_off.py match:label=den
to turn off
your light with the label of den
.