Chapter 13. Advanced Interactions

You've already seen how to create simple Interactions between your devices using the Interaction Builder (Section 12.1, “Interaction Builder”). Much more sophisticated Interactions can be created using SwitchThat One's dedicated Interaction scripting language.

This section introduces the scripting language and explains how to write Interactions using the Advanced Interaction Editor. Some example Interactions are given in Section 13.4, “Examples”. There's also a reference guide to the Interactions scripting language: Appendix C, Interaction Reference

13.1. The Basics

13.1.1. Things and actions

The basic principle behind the SwitchThat One Interaction language is very straightforward: You perform an 'action' on a 'thing'. This is written as:

 thing.action

The 'thing' might one of your devices, a room, a shortcut or the current time. A 'thing' might also be a collection, such as all of your devices or rooms. Interactions are built around 'top level things' (see Section C.2, “Top level things” for a list of all top level things.) Let's look at a simple example:

 Devices

This is a 'collection' that refers to all of your devices. We can then retrieve a single device from the collection with:

 Devices['My light']

This now represents just the device called ‘My light’. You'll usually want to refer to a device by its name (which is case-sensitive), but you can also use its SwitchThat ID. You can find this ID by tapping more on the device's Configure page. This is how you'd refer to the device with SwitchThat ID 2:

 Devices[2]

Now that we have our 'thing', we'll want to do something to it. We can turn the 'My light' on by using the on action:

 Devices['My light'].on

Let's recap: Devices has a special meaning, and returns all your devices. As it's a collection, we use square brackets to return a single device called 'My light', and finally we called the action on to set the device's state to 'on'.

Actions that set the state of a device are often passed additional values. For example you might want to change the light's colour to a specific value:

 Devices['My light'].colour('red')
 Devices['My light'].colour(255,228,206)

There are also 'getter' actions, which end in a ?, and these actions let you query the state of a thing. For example we can ask whether a light is on, or find out its current colour:

 Devices['My light'].on?
 Devices['My light'].colour?

The results of these 'getter' actions can be used as input to the corresponding 'setter' actions, e.g.

 Devices['Light A'].on(Devices['Light B'].on?)
 Devices['Light A'].colour(Devices['Light B'].colour?)
 Devices['My light'].on(Devices['Motion sensor'].on?)

This last example illustrates how we can use the state of a motion sensor to control a light: if the motion sensor is 'on' (i.e. detects motion) the light will also be set to on.

There are many other actions that you can perform on a Device, and they are described in full in Section C.4, “Actions”.

13.1.2. Operators

As with other programming languages, Interactions can make use of operators. The following table shows the simple arithmetic and logical operators that can be used when writing an Interaction. Operators will only work with certain types of 'thing', and you should read Section C.5, “Operators” for full details on how operators can be used

Operator Description
a + b Add a and b
a - b Subtract b from a
a * b Multiply a and b
a / b Divide a by b
a div b Integer division of a by b
a == b True if a equals b
a != b True if a is different from b
a < b True if a is less than b
a <= b True if a is less than or equal to b
a > b True if a is greater than b
a >= b True if a is greater than or equal to b
!a 'Not a'. If a is true, then return false. If a is false return true

Table 13.1. Interaction Operators


If you've come across any other scripting languages before, you should start to feel comfortable with this very quickly!

Armed with the tables in Appendix C, Interaction Reference, you should be able to write useful Interactions. We've also collected together a set of example Interactions to help inspire you - take a look at the Section 13.4, “Examples”.

13.2. Using the Advanced Interaction Editor

Now that we've learned the basics, let's look how to write your own Interactions using the Advanced Interaction Editor. To start working with Advanced Interaction Editor tap Settings in the menu at the top of the screen, find the Interactions section and tap Write a new Interaction You'll now see the editor interface:

The Advanced Interaction Editor

The Advanced Interaction Editor


The Advanced Editor has a similar interface to Interaction Builder. The Interaction Name box is were you enter the name of your Interaction. Below Interaction Name are the If This and Then That boxes, and this is where you'll write your Interaction using the Interactions scripting language.

We'll look at how to write the If This and Then That part of an Interaction in more detail over the rest of this section.

13.2.1. If This

As with the Interaction Builder, the If This section is where you define an event to trigger your desired action. An If This event must evaluate to a Boolean, i.e. true or false. If true, it will trigger the Then That action.

Tip

You cannot perform actions that affect the state of things as part of your If This event. For example, an If This event cannot turn a device on or off. These are called 'side effects' and are not permitted in the If This rule.

Let's consider a simple example. If we want something to happen at the same time every evening, we can write the following in the If This box:

Now.hm becomes "19:30"

This should be read as 'when the current time, just considering hours and minutes, becomes 19:30' . Note that we use the operator 'becomes' , rather than '=', as we want the event to occur once as soon as the time is 19:30, and not for the whole duration of that minute.

Interactions are run approximately every second so the If This event should be quick to check and should not evaluate to true (and trigger the Then That event) more often than it needs to. For this reason, it's always better for the If This event to trigger once when the state of a thing changes, rather than for the entire period that the thing is in that state. As with the example above, ample, the If This event should trigger when a switch is turned on, rather than while it is on.

To help us achieve this, we can use becomes and also the changes and leaves operators. The following table gives some example If This events using these operators.

If This event Meaning
time.hour changes
Fires on the hour, every hour
time.nighttime? becomes true
Fires when it becomes nighttime
devices['Motion sensor'].on? becomes true
Fires when device 'Motion sensor' turns on (i.e. detects motion)
devices['Kitchen switch'].off? becomes true
Fires when device 'Kitchen switch' is turned off
Now.hm leaves "9:00"
Fires when the current time stops being 9:00, i.e. at 9:01.
time.minute div 5 changes
Fires once at 0:00, 0:05, 0:10, 0:15 ... 23:55
time.cumulative_seconds div 10 changes
Fires once every 10 seconds

Table 13.2. Some example If This events


Using becomes and changes also helps us avoid timing problems, as we cannot guarantee that the If This event of an Interaction will be evaluated precisely every second. Although the following If This rule will normally fire at the start of each minute:

   time.seconds == 0

Unfortunately there is no guarantee that the Interaction will be checked within the first second of every given minute. There is a small chance that it will be checked when time.seconds is 59, and again when time.seconds is 1. If this happens, the Interaction won't run. Instead, it is much safer to use an If This rule like:

  time.minutes changes

Which is guaranteed to fire at the start of every minute, within a second or so.

You can build more sophisticated If This events by making use of the and & or operators. For example, consider the following If This event:

 (time.hour > 20 or
 time.hour <  6) and
 devices['motion sensor'].on? becomes true

This will only fire when the 'motion sensor' device detects motion and the current time is after 8pm or before 6am.

Another advanced feature that you may find yourself requiring is being able to either smooth out events from an input device, or require an event to reach a threshold time before responding it. For this we provide the clamp and threshold operators, and you can find more details about them in Section 13.3.1, “The clamp and threshold operators”.

13.2.2. Then That

The Then That box is where you define the action you want to trigger when the If This event occurs. The basic approach is to pick a thing and specify an action that should happen to that thing. For example, to turn on a light, you could write the following in the Then That box:

 Devices['my light'].on

Or to turn off all the devices in the Kitchen:

 Rooms['Kitchen'].off

You can perform multiple actions, separating them with a ; e.g.

 devices['upstairs lamp'].on ; devices['downstairs lamp'].on ; devices['sonos'].play ;

Note that the final ; is optional.

For convenience most actions return the thing you call it on, allowing you to chain multiple actions. e.g.

  devices['sonos'].unmute().volume(25).play

You can see a full list of all the supported actions in Section C.4, “Actions”.

You can even use if - then - else expressions to adapt your Then That rules according to changing circumstances. For example, you might have an Interaction that switches your Kitchen Sonos player on at 6pm and plays BBC Radio 4. The Then That rule might be

  devices['Kitchen Sonos'].play_favourite('Radio 4')

But what if someone else is already listening to music on that player? You can modify the rule to account for this:

  if devices['Kitchen Sonos'].pause? 
  then devices['Kitchen Sonos'].play_favourite('Radio 4') 
  endif

Finally, note that the becomes, changes, leaves, clamp and threshold operators can't be used in a Then That rule.

13.3. More complicated Interactions

13.3.1. The clamp and threshold operators

The clamp and threshold operators are used to alter the way that your Interactions respond to input from devices. For example, you could use clamp or threshold to:

  • Make a light come on, and stay on, for 5 minutes if there is motion in the room

  • Make other lights in your house come on if the hall light is turned on and left on for a minimum period of time

  • Have the temperature stay over 21°C for 10 minutes before you turn off the heating

13.3.1.1. Using clamp

The clamp operator lets us persist the state of a device when an event is triggered.

Let's consider an example to help illustrate how this might be used. Imagine you have a motion sensor and want to use it to turn the light on automatically when you enter a room. However, you'd like the light stay on for 5 minutes and, once the 5 minutes is up, the light should turn off again (assuming motion is no longer detected.)

We can achieve this by 'clamping' the motion sensor to stay 'on' (i.e. detecting motion) for the desired time period. Our Interaction might look like this:

If This:

devices['Motion sensor'].on? clamp true for 5.minutes, false for 0.seconds changes

Then That:

devices['Landing light'].on(devices['Motion sensor'].on?);

The Interaction engine will continually check whether 'Motion sensor' is on (detecting motion). If this event becomes true, then it will stay true for at least 5 minutes. During this period, 'Motion sensor' is considered to be 'on' regardless of whether the device is detecting motion in the room. After 5 minutes, the clamp is set to false (returning the motion sensor to its default state) and then immediately released. If there is still motion in the room, the event will fire again, and the process will repeat.

To ensure this Interaction works as efficiently as possible, we add the changes operator to the end of the If This event, so that the Then That action only triggers when there's a change (in this case, when the motion is initially detected, and again at the end of the 5 minutes when the clamp is set to false.)

When the The That action is triggered, The device 'Landing light' is set to the current state of 'Motion sensor'. Thus, 'Landing light' is turned on when motion is first detected and stays on for 5 minutes. After 5 minutes, 'Landing light' will turn off again if there is no longer motion detected in the room. If there is still motion in the room, 'Landing light' will stay on and the process will repeat.

Note that there can be as many of the VALUE for TIME_PERIOD clauses as is required:

devices['Motion sensor'].on? clamp true for 5.minutes, false for 2.minutes, true for 5.minutes, 
                             false for 0.seconds changes

13.3.1.2. Using threshold

The threshold operator can be used to delay the triggering of the Then That action until the If This event has fired for some minimum period of time. If the threshold time isn't reached the Then That action will not be triggered at all.

For example, you might want your motion sensor to turn the light on only if it detects motion for a minimum of 20 seconds. This would avoid the light coming on unnecessarily if someone entered the room and left it again almost immediately.

Let's look at how this simple example might be written:

If This:

(devices['Motion sensor'].on? threshold for 20.seconds) becomes true

Then That:

devices['Landing light'].on

i.e. if 'Motion sensor' detects motion ('turns on') and stays on for 20 seconds then 'Landing light' is turned on.

As with clamp, there can be as many of the VALUE for TIME_PERIOD clauses as is required. This allows you to create some sophisticated Interactions:

If This:

(devices['thermostat'].temperature threshold    for 0.seconds,
                                             21 for 5.minutes,
                                             22 for 3.minutes,
                                             23 for 1 minute) >= 21 becomes true

Then That:

  alerts['email'].send('me@aol.com', 'Alert', 'The house is overheating')

13.4. Examples

This section provides some example Interactions to experiment with. You can use examples to help you get confident, and see what's possible.

Take a look at Appendix C, Interaction Reference for a full reference to the Interactions scripting language.

If This ... Then That ... Comment
time.hour changes
devices['light 2'].colour
(
 ['red', 'green', 'blue', 'purple'].pick
)
Let's have a different colour every hour!
time.minute div 5 changes
devices['light 2'].colour
  (random.random(256),
   random.random(256),
   random.random(256)) 
Let's frequently have a new random colour!
devices['light 1'].colour? changes
devices['light 2'].colour
(devices['light 1'].colour?)
Have 'light 2' track 'light 1's colour
time.nighttime?
  becomes true
devices['light 2'].on
Turn 'light 2' on as it becomes night time
(time+10.minutes).nighttime?
  becomes true
devices['light 2'].on
Turn 'light 2' on 10 minutes before dusk
(time.hour >= 20 or
 time.hour <  6) and
 devices['motion sensor'].on? becomes true
devices['bedside light'].blink
Blink bedside light if there's an intruder during the night
now.hour becomes 8
devices['sonos player'].play
Automatically play music at breakfast time
Random.random(100) == 0
devices['light 1'].toggle
Turn the light on/off at random to simulate occupancy

Table 13.3. Advanced Interaction Examples