Guia de DSL do Android

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.

Toda a DSL de automação é colocada em um único nó automation. O nó automation forma o limite entre o contexto da linguagem Kotlin externa e o contexto da DSL incorporada.

Fluxo sequencial

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

Exemplo de DSL sequencial

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


import com.google.home.automation.action
import com.google.home.automation.automation
import com.google.home.automation.condition
import com.google.home.automation.sequential
import com.google.home.automation.starter

...

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

Isso pode ser refinado com a adição de outros nós.

Acionador

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

Acionador com base no atributo de característica

Ao declarar um nó de acionador com base em um atributo de característica, especifique:

  • o dispositivo
  • o tipo de dispositivo a que a característica pertence
  • a característica
starter<_>(thermostat, TemperatureSensorDevice, TemperatureMeasurement)

O parâmetro de tipo de dispositivo é obrigatório porque permite especificar qual tipo de dispositivo dentro de um dispositivo a automação aborda. Por exemplo, um dispositivo pode ser composto por um FanDevice e um HeatingCoolingUnitDevice, ambos contendo a OnOff característica. Ao especificar o tipo de dispositivo, não há ambiguidade sobre qual parte do dispositivo aciona a automação.

Acionador com base em eventos

Ao declarar um nó de acionador com base em um evento, especifique:

  • o dispositivo
  • o tipo de dispositivo a que a característica pertence
  • o evento
starter<_>(doorBell, GoogleDoorbellDevice, DoorbellPressed)

Acionador com base em uma estrutura e evento, com parâmetros

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

Por exemplo, esse acionador usa o Time da característica ScheduledTimeEvent para ativar a automação às 7h:

val earlyMorning = starter<_>(structure, Time.ScheduledTimeEvent) {
  parameter(Time.ScheduledTimeEvent.clockTime(
    LocalTime.of(7, 0, 0, 0)))
}

Acionador com base no clima

É possível especificar as condições climáticas atuais ou previstas em um acionador usando a característica Weather:

val weatherState = starter<_>(structure, trait = Weather)

Consulte Fechar as persianas se houver probabilidade de chuva na página de automações de exemplo.

Acionador manual

Um acionador manual é um tipo especial de acionador que permite ao usuário executar a automação manualmente.

Ao declarar um acionador manual:

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

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

select {
  manualStarter()
  starter<_>(thermostat, TemperatureSensorDevice, TemperatureMeasurement)
}

Observe que todos os nós condition que seguem um acionador manual serão avaliados e poderão bloquear a execução da automação, dependendo da expressão condition.

Separar um iniciador 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 acionador manual é colocar o outro acionador em um fluxo sequencial separado com a condition dele:

automation_graph {
  sequential {
    select {
      sequential {
        starter<_>(...)
        condition {...}
      }
      sequential {
        manualStarter()
      }
    }
    action {...}
  }
}

Referenciar o valor de um atributo

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

Com um stateReader:

val time = stateReader<_>(structure, Structure, Time)
val currTime = time.currentTime

Com um starter:

val starterNode = starter<_>(device1, LaundryWasherDevice, OnOff)
condition() {
  expression = 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 Kotlin e podem conter valores primitivos, como números, caracteres, strings e booleanos, bem como valores de enumeração. Agrupar subexpressões com parênteses permite controlar a ordem em que elas são avaliadas.

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

condition() {
  val expr1 = starterNode.lockState equals DlLockState.Unlocked
  val expr2 = stateReaderNode.lockState equals true

  val expr3 = occupancySensingDevice.occupied notEquals 0
  val expr4 = timeStateReaderNode
    .currentTime
    .between(
      timeStateReaderNode.sunsetTime,
      timeStateReaderNode.sunriseTime)
  expression = (expr1 and expr2) or (expr3 and expr4)
}

É possível referenciar o valor de uma característica acessada por um acionador:

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

stateReader

A outra maneira de referenciar valores de atributos de características 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 a structure e a característica como argumentos:

import com.google.home.automation.stateReader
...
val filterMonitoringState = stateReader<_>(structure, ActivatedCarbonFilterMonitoring)

Em seguida, referencie o stateReader no nó condition:

condition() {
  expression =
    filterMonitoringState.changeIndication
      .equals(ChangeIndicationEnum.Warning)
}

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

val armState = stateReader<_>(doorLock, DoorLockDevice, ArmDisarm )
val doorLockState = stateReader<_>(doorLock, DoorLockDevice, DoorLock)
condition() {
  expression =
    (armState.armState equals true)
    and
    (doorLockState.lockState equals true)
}

Duração da condição

Além de uma expressão booleana em uma condição, é possível especificar um período durante o qual 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 {
    expression(lightStateReader.onOff == true)
    forDuration(Duration.ofMinutes(10))
  }

A duração pode variar de 5 segundos a 24 horas.

Nós de ação

O nó de ação é onde o trabalho da automação ocorre. Neste exemplo, a ação invoca o AssistantBroadcast comando broadcast() da característica:

action(device, SpeakerDevice) {
  command(AssistantBroadcast.broadcast("Intruder detected!"))
}

Declarações de importação

Ao desenvolver automações, nem sempre é óbvio como importar vários elementos das APIs Home para o código.

Os atributos de característica são importados do objeto Companion da característica:

import com.google.home.matter.standard.OnOff.Companion.onOff

As estruturas de dados definidas por uma característica são importadas da classe de característica cujo nome termina em "-Trait":

import com.google.home.matter.standard.MediaPlaybackTrait.PlaybackStateEnum

Os comandos de característica são importados do objeto Companion da característica:

import com.google.home.matter.standard.Thermostat.Companion.setTemperatureSetpointHold