A Gentle Plugin Formula Tutorial

Cynical Plugin Formulas - A Gentle Introduction #

Not everyone aspires to be a Python programmer. If you don’t know Python and have little interest in changing that, you’re not completely out of luck. You just have accept that a certain amount of magic happens here, and your job is to come up with working incantations without getting burned. So to speak.

We will write examples like this:

what you put into a dynamic field   # -> what value the plugin uses

If you want to follow along, you can use any dynamic field of any Cynical Plugin.

You know what happens if you just type some text into a field - you get what you type:

"Hello, there!" # -> Hello, there!

and that works just fine with a dynamic field, the kind that can contain a formula. To make the field do something surprising, you need to start with an equal sign =:

=12345		# -> 12345

The leading equal sign gets eaten, and the rest of the text gets taken to be the formula. Of course, 12345 is, well, 12345. Strings must be enclosed in single or double quotes:

='Just some text'	# -> Just some text

which produces exactly the same result as just typing in the string without the quotation marks. This is also how you deal with an actual string that begins with an equal sign:

="===> Great!"		# -> ===> Great!

Did you ever try to put a newline character into an Indigo field, though? With a dash of Python, it’s easy:

='Here comes the end:\nVerily!"		# -> Here comes the end <newline>Verily!

This is called a string escape sequence, and it lets you put all kinds of funny characters into a string - even invisible binary ones.

Variables #

Indigo has variables. Let’s say you have a name variable containing your name, Jane. How do you get a variable into a string? Like this:

=name		# -> Jane

Simple, no? If you change the value of name, the effective value of the field will magically change to match. Now this is useful.

Of course, we can also do calculations:

=6*12		# -> 72

Arithmetic is easy. So are string calculations:

="Hello, \" + name + "!"		# -> Hello, Jane!

The “+” operator concatenates string values. It also adds up numbers; that’s just how it works. So you need to pay attention to what kinds of values you work with. Python is apt to surprise you at times:

=2*name		# - JaneJane

Multiplying a string with a number repeats it. Just be prepared to be amazed at times.

There are many other operators for calculations. If Python has it, you can use it. And not just operators, the entire language. One very useful trick is “formatted strings”:

=f"Hello, {name}! You have {bottle_count} bottles!"		# -> Hello, Jane! You have 17 bottles!

This is just a different way to put together string values. If you want to learn more about Python operators and how they work, check out the official python tutorial.

Functions #

Python has functions, and they work just fine in plugin formulas:

=len(name)		# -> 4

calculates the length (in characters) of Jane. It can tell you how many things are contained in just about anything. Other functions are attached to things (they’re called methods when they do that), like

=name.upper()		# -> JANE

which puts Jane in ALL CAPS. To use those, you’ll have to find out what they’re called and what you put between those parentheses though, so you’ll either have to look that up or ask a friend who knows Python. You can get pretty complicated, like so:

="high!" if temperature > 72 else f"normal {temperature}"	# -> normal (67)

and you can probably figure out what happens when it gets hot.

Objects #

Don’t get scared now. Objects don’t bite. Often.

Playing with constants and variables is fun, but often you need the value of something inside Indigo itself:

=indigo.server.version		# -> 5.1.2

In Python, you dig inside things by writing their name, appending a dot and then saying what part of the object you mean. In this case, the name indigo contains stuff made by the Indigo programmers for us. Among that stuff is indigo.server, an object that represents Indigo itself to the plugin. And one of the attributes of indigo.server is its version. Check out the indigo scripting tutorial for some ideas of what you can use.

And we’re just barely getting started here. The name plugin refers to the plugin itself. It contains all kinds of useful things, like its version:

=plugin.version		# -> 3.1.0

In fact, plugin is the plugin object the Indigo documentation talks about. If the plugin has a preference field called main_calendar, then =plugin.main_calendar will get it for you.

Devices #

Let’s say the plugin has a device called countdown, and that device has a state called count. Then you can say

=devices.countdown.count		# -> 56

and you’ll get the value of the count of the countdown device. If the field you’re typing into belongs to an action, and that action is for a particular device, then you can just say device for that, and you might fill in a set counter action’s value field with

=device.count + 1		# -> 57

to increment it by as much as you like.

The same approach also works if count is a configuration field. And if that field is itself dynamic, we’ll evaluate it for you. Neat, huh?

That “dot” naming only works if the device’s name is a regular Python name with no funny characters like spaces. There’s a different way to name recaltricant devices with odd names:

=devices["My Counter!"].count		# -> 56

Those square brackets let you use any value as the name. If you happen to know the id number for a device, you can use it instead of the name. In fact, you can even calculate the name:

=devices[f"location {counter}"].count		# -> 56

might get the count state or configuration field of the “Living Room counter” device - as long as it belongs to the plugin you’re talking to. (Indigo won’t let you mess with another plugin’s devices without some special preparations.)

Modules #

You can even talk directly to the operating system that Indigo is running on. Much of Python’s power lies in its library of modules containing interesting things. In plugin formulas, you just start with the module name and keep going:

=time.asctime()		# -> Sat Jun 16 00:36:35 2012

to get the current time as a string. Or perhaps

=os.getenv("HOME")		# -> /Users/jane

to get the path (on the server) to the user’s home directory. (That’s the user running Indigo, not necessarily you.) Or even, somewhat precariously, =open(’/Users/joe/Desktop/testfile’).read()" # -> testing, testing

which produces the (entire) content of a text file on disk. The possibilities are endless; the limit is your imagination. That, and your patience in figuring out that Python thing…