Guia de DSL para iOS

Use o guia a seguir para entender como vários nós da DSL de automação podem ser usados para criar uma automação.

Todo o DSL de automação é colocado em um único nó automation. O nó automation forma o limite entre o contexto externo da linguagem Swift e o contexto DSL incorporado.

Fluxo sequencial

O fluxo sequencial é o tipo padrão de fluxo de automação.

Exemplo de DSL sequencial

Confira um modelo de DSL de automação muito básico que usa um fluxo sequencial formado por uma ativação, uma condição e uma ação:

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {
  starter(...)
  condition {...}
  action {...}
}

Isso pode ser refinado adicionando outros nós.

Starter

Os nós de ativação definem as circunstâncias iniciais que ativam uma automação. Por exemplo, uma mudança de estado ou valor. Uma automação precisa ter pelo menos um iniciador. Caso contrário, ela vai falhar na validação. Para adicionar mais de um iniciador a uma automação, use um nó select.

Starter com base no atributo de traço

Ao declarar um nó inicializador baseado em um atributo de traço, especifique:

  • o dispositivo
  • o tipo de dispositivo ao qual o atributo pertence
  • o traço
starter(
  thermostat,
  Matter.TemperatureSensorDeviceType.self,
  Matter.TemperatureMeasurementTrait.self
)

O parâmetro de tipo de dispositivo é obrigatório porque permite especificar qual tipo de dispositivo a automação aborda. Por exemplo, um dispositivo pode ser composto por um FanDeviceType e um HeatingCoolingUnitDeviceType, ambos contendo o traço OnOffTrait. Ao especificar o tipo de dispositivo, não há ambiguidade sobre qual parte do dispositivo aciona a automação.

Ação inicial com base no evento

Ao declarar um nó inicializador baseado em um evento, especifique:

  • o dispositivo
  • o tipo de dispositivo ao qual o atributo pertence
  • o evento
starter(
  doorbell,
  Google.GoogleDoorbellDeviceType.self,
  Google.DoorbellPressTrait.DoorbellPressedEvent
)

Ativação com base em uma estrutura e um evento, com parâmetros

Alguns eventos podem ter parâmetros. Portanto, eles também precisam ser incluídos no iniciador.

Por exemplo, esta ativação usa o ScheduledEvent do TimeTrait para ativar a automação às 7h:

typealias TimeTrait = Google.TimeTrait

let earlyMorning = starter(
  structure,
  TimeTrait.ScheduledEvent.self
) {
  TimeTrait.ScheduledEvent.clockTime(TimeOfDay(hours: 7, minutes: 0))
}

Acionador manual

Um ativador manual é um tipo especial de ativador que permite que o usuário execute a automação manualmente.

Ao declarar um iniciador manual:

  • Não especifique um tipo de característica ou dispositivo.
  • Forneça um elemento de interface que chame Automation.execute().

Ao colocar um inicializador manual em um fluxo select com outro inicializador, o manual substitui o outro:

select {
  manualStarter()
  starter(
    thermostat,
    Matter.TemperatureSensorDeviceType.self,
    Matter.TemperatureMeasurementTrait.self
  )
}

Todos os nós condition que seguem um ativador manual serão avaliados e podem bloquear a execução da automação, dependendo da expressão condition.

Como separar um ativador manual de um condicional

Uma maneira de estruturar a automação para que os nós condition não bloqueiem uma automação ativada com um ativador manual é colocar o outro ativador em um fluxo sequencial separado com o condition:

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {

  select {
    sequential {
      starter(...)
      condition {...}
    }
    sequential {
      manualStarter()
    }
  }
  action {...}

}

Fazer referência ao valor de um atributo

Para usar o valor de um atributo em uma expressão, use a seguinte sintaxe.

Com um stateReader:

typealias TimeTrait = Google.TimeTrait

let time = stateReader(structure, TimeTrait.self)
time
let currTime = time.currentTime

Com um starter:

typealias LaundryWasherDeviceType = Matter.LaundryWasherDeviceType
typealias OnOffTrait = Google.OnOffTrait

let starterNode = starter(device1, LaundryWasherDeviceType.self, OnOffTrait.self)
starterNode
condition {
  starterNode.onOff.equals(true)
}

Nós e expressões de condição

Um nó de condição representa um ponto de decisão que determina se a automação continua ou não. Uma automação pode ter vários nós condition. Se a expressão de qualquer nó condition for avaliada como false, a execução de toda a automação será encerrada.

Em um nó condition, é possível combinar vários critérios de condição usando vários operadores, desde que a expressão seja avaliada como um único valor booleano. Se o valor resultante for true, a condição será atendida e a automação continuará a execução do próximo nó. Se for false, a automação vai parar de ser executada nesse ponto.

As expressões são formadas de maneira semelhante às expressões em Swift e podem conter valores primitivos, como números, caracteres, strings e booleanos, além de valores de tipo enumerado. O agrupamento de subexpressões com parênteses permite controlar a ordem em que elas são avaliadas.

Confira um exemplo de condition que combina várias subexpressões em uma única expressão:

condition {
  let exp1 = starterNode.lockState.equals(.unlocked)
  let exp2 = stateReaderNode.lockState.equals(true)
  let exp3 = occupancySensingDevice.occupied.notEquals(0)
  (exp1.and(exp2)).or(exp3)
}

É possível fazer referência ao valor de um recurso acessado por um ativador:

typealias OnOffTrait = Matter.OnOffTrait

let starterNode = starter(device, OnOffTrait.self)
starterNode
condition {
  starterNode.onOff.equals(true)
}
val starterNode = starter<_>(device, OnOff)
condition() { expression = starterNode.onOff equals true }

stateReader

A outra maneira de referenciar valores de atributo de característica em um nó condition é com um nó stateReader.

Para fazer isso, primeiro capture o valor do atributo de característica em um nó stateReader. Um stateReader usa o structure e o atributo como argumentos:

typealias ActivatedCarbonFilterMonitoringTrait = Matter.ActivatedCarbonFilterMonitoringTrait

let filterMonitoringState = stateReader(structure, ActivatedCarbonFilterMonitoringTrait.self)

Em seguida, faça referência ao stateReader no nó condition:

condition {
filterMonitoringState.changeIndication.equals(.warning)
}

Usando comparação e operadores lógicos, várias stateReaders podem ser usadas em um nó condition:

typealias ArmDisarm = Google.ArmDisarmTrait
typealias DoorLockDevice = Matter.DoorLockDeviceType
typealias DoorLock = Matter.DoorLockTrait

let armState = stateReader(doorLock, DoorLockDevice.self, ArmDisarm )
let doorLockState = stateReader(doorLock, DoorLockDevice.self, DoorLock)
armState
doorLockState
condition {
  let exp1 = armState.armState
  let exp2 = doorLockState.lockState
  exp1.and(exp2)
}

Duração da condição

Além de uma expressão booleana em uma condição, você pode especificar um período em que a expressão precisa ser verdadeira para executar a automação. Por exemplo, é possível definir uma condição que é acionada somente se uma luz estiver acesa por dez minutos.

condition(for: .seconds(600)) {
lightStateReader.onOff.equals(true)
}

A duração pode variar de um a 30 minutos.

Nós de ação

O nó de ação é onde o trabalho da automação acontece. Neste exemplo, a ação invoca o comando broadcast() da AssistantBroadcastTrait:

action(speaker, SpeakerDeviceType.self) {
  Google.AssistantBroadcastTrait.broadcast(msg: "Oven Cycle Complete")
}