The Automation DSL can be used to create automations that are more complex than
those discussed in
[DSL guide - basic automations on Android](https://developers.home.google.com/apis/android/automation/dsl/basic).

## Sequential with multiple actions

![Sequential with multiple actions](https://developers.home.google.com/static/apis/images/apis-automation-dsl-sequential-multiple.svg)

An automation can do more than one thing. For example, in place of the single
`action` node, you could have multiple `action` nodes, which run in sequential
order:  

    automation {
      sequential {
        starter<_>(...)
        condition {...}
        action {...}
        action {...}
        action {...}
        }
    }

## Sequential with multiple parallel actions

![Sequential with multiple parallel actions](https://developers.home.google.com/static/apis/images/apis-automation-dsl-sequential-multiple-parallel.svg)

If you place multiple `action` nodes in a `parallel` node, the actions execute
concurrently.  

    automation {
      sequential {
        starter<_>(...)
        condition {...}
        parallel {
          action {...}
          action {...}
          action {...}
        }
      }
    }

If there are `action` nodes in the `sequential` node that come after the
`parallel` node, they wait to execute until all the nodes within the `parallel`
node have finished executing.
| **Key Point:** If you need several actions to occur in an automation, it may be preferable to place them in a `parallel` node. This is because running actions sequentially can lead to undesirable delays as each action waits for all the preceding actions to complete before starting.

## Delays

You can introduce pauses in your automations using the
[`delayFor`](https://developers.home.google.com/reference/kotlin/com/google/home/automation/DelayNodeDsl#delayFor(java.time.Duration))
keyword, which takes a
[`java.time.Duration`](https://developer.android.com/reference/java/time/Duration)
argument representing how long to pause before continuing execution. The pause
duration may be as short as five seconds or as long as 24 hours.

For example, to toggle a light four times with a five-second pause between each
toggle:  

    sequential {
      action(light, OnOffLightDevice) { command(OnOff.toggle()) }
      delayFor(Duration.ofSeconds(5))
      action(light, OnOffLightDevice) { command(OnOff.toggle()) }
      delayFor(Duration.ofSeconds(5))
      action(light, OnOffLightDevice) { command(OnOff.toggle()) }
      delayFor(Duration.ofSeconds(5))
      action(light, OnOffLightDevice) { command(OnOff.toggle()) }
    }

| **Warning:** `delayFor` *must* be in a `sequential` flow. If a `delayFor` is nested within a `parallel` flow at any level, it is ignored.

## Trigger suppression

Trigger suppression is a capability that allows your automation to ignore a
`starter` for a specified period of time after the initial triggering event. For
example, if the automation has a `starter` that's triggered by motion detection,
and if you specify a trigger suppression duration of five minutes, then when the
`starter` triggers, it won't trigger again for the next five minutes. This
prevents the automation from rapidly triggering over and over.

To apply trigger suppression to your automation, use the
[`suppressFor`](https://developers.home.google.com/reference/kotlin/com/google/home/automation/SuppressionNodeDsl#suppressFor(java.time.Duration))
keyword with a
[`java.time.Duration`](https://developer.android.com/reference/java/time/Duration)
argument representing how long to wait before responding to subsequent triggers.
The suppression duration may be as short as five seconds or as long as 24 hours.  

    automation {
      sequential {
        val starterNode = starter<_>(device, OccupancySensor, MotionDetection)
        suppressFor(Duration.ofMinutes(30))
        action(light, OnOffLightDevice) { command(OnOff.toggle()) }
    }

Note that trigger suppression affects all `starters` in an automation that
precede the `suppressFor`.

## Limit the number of executions

You can limit the number of times an automation is permitted to run.

For example, you might want to set up a one-time automation that runs the
vacuum while you're away from home for the day.

To do this, set the automation's
[`maxExecutionCount`](https://developers.home.google.com/reference/kotlin/com/google/home/automation/AutomationBuilder#maxExecutionCount(kotlin.Int))
metadata field.
The following example is an automation that can only execute once:  

```kotlin
automation {
  // The automation can only be executed once.
  maxExecutionCount = 1
  // When the door lock state changes
  sequential {
    val doorLockEvent = starter<_>(doorLock, DoorLockDevice, LockOperationEvent)
    // if the door is unlocked
    condition() {
      expression = (doorLockEvent.lockOperationType equals LockOperationTypeEnum.Unlock)
    }
    // turn the light on
    action(light, DimmableLightDevice) { command(OnOff.on()) }
  }
}
```

The automation is immediately deleted once it completes execution for the last
time and `maxExecutionCount` is reached. The automation's history entry remains
in the Google Home app (GHA) **Activity** tab, including the `automation_id`.

## Set trait attributes in an action

To set the value of a trait attribute:

1. Create an `update` node within an `action` node, including the relevant trait as an argument to the `update` node:  

       action(<var translate="no">deviceReference</var>, <var translate="no">deviceType</var>) {
         update(<var translate="no">trait</var>) {

         }
       }

2. Within the `update` node, for each attribute to be modified, use a mutator function, and pass it the new value. To form the name of the mutator function:
   1. Capitalize the name of the attribute
   2. Prefix it with the word `set`.

   For example, to update an attribute called `defaultMoveRate`, you'd use a mutator function called `setDefaultMoveRate`.

Note that an `update` node can have multiple mutator functions. Here's an
example where two attributes are updated:  

    action(device, Fan) {
      update(FanControl) {
        setPercentSetting(50u)
        setRockSetting(FanControlCluster.RockBitmap.rockUpDown)
      }
    }

| **Important:** Only trait attributes with an access type of `write` can be updated. Attributes with an access type of `read` cannot be updated.