Conceitos de DSL do Android

Esta é uma visão geral dos conceitos fundamentais da DSL de automação no Android.

Componentes de automação

Uma automação consiste nos seguintes componentes básicos, geralmente avaliados nesta ordem:

  1. Ativação: define as condições iniciais que ativam a automação, como uma mudança em uma característica. Uma automação precisa ter uma ativação.
  2. Condição: qualquer restrição adicional a ser avaliada depois que uma automação for ativada. A expressão em uma condição precisa ser avaliada como true para que as ações de uma automação sejam executadas.
  3. Ação: comandos ou atualizações de estado realizados quando todas as condições são atendidas.

Por exemplo, talvez você tenha uma automação que diminua as luzes de um cômodo quando a TV desse cômodo for ligada entre o pôr e o nascer do sol. Neste exemplo:

  1. Inicialização: a TV foi ligada, o que é uma mudança de estado em uma característica da TV.
  2. Condição: o horário atual da casa em que a TV está é avaliado.
  3. Ação: as luzes no mesmo ambiente da TV são diminuídas.

A automação seria ativada quando a TV da sala fosse ligada, mas só seria executada se a condição "o horário está entre o pôr e o nascer do sol" fosse atendida.

Além da estrutura básica, as automações nas APIs Home também contêm metadados, como name e description, que podem ser usados para identificar automações para desenvolvedores e usuários.

Nós

Nas APIs Home, a estrutura lógica de uma automação consiste em nós. Os nós são unidades abstratas e reutilizáveis que representam comportamentos de entidades ou fluxos de execução. Cada nó pode ter variáveis de entrada e de saída que podem ser consumidas por outros nós.

Tabela: tipos de nós de automação
Tipo do nó Implementação em Kotlin Descrição
Starter Comportamental StarterNodeDsl Inicia uma automação quando o estado de uma característica (qualquer atributo) muda.
StateReader Comportamental StateReaderNodeDsl Lê um atributo de traço e permite capturar o valor dele para uso em nós de condição.
Ação Comportamental ActionNodeDsl Invoca comandos de traços.
Sequencial Fluxo de execução SequentialFlow Executa nós de ação aninhados em sequência. Esse é o comportamento padrão de execução.
Paralela Fluxo de execução ParallelFlow Executa nós de ação aninhados em paralelo.
Condição Fluxo de execução ConditionNodeDsl Mudar condicionalmente o fluxo de execução com base em avaliações de expressões lógicas. As condições podem ser associadas a uma ação inicial (condições específicas da ação inicial) ou ser globais (aplicadas a todas as ações iniciais).
Selecionar Fluxo de execução SelectFlow Permite que mais de uma ativação inicie uma automação.
Expressão Valor Expression Pode ser o valor de um atributo de característica, uma constante ou um valor literal e precisa ser avaliado como uma lista, um número, um booleano ou uma string.

Nós comportamentais

Nós como ativações e ações são comportamentais. As ativações iniciam uma automação com base em mudanças nos atributos do dispositivo. As ações emitem comandos de dispositivo ou atualizam atributos.

Os nós comportamentais geralmente estão vinculados a características do dispositivo e geram o estado da característica de saída para uso como entrada em outros nós.

Nós de fluxo de execução

Alguns nós representam fluxos de execução, como sequenciais e paralelos. Cada um desses nós contém os nós comportamentais que definem a automação.

Por exemplo, um fluxo sequencial pode conter nós que são executados em ordem sequencial. Normalmente, são ativação, condição e ação.

Fluxos de execução sequenciais
Figura 1: fluxo de automação sequencial

Um fluxo paralelo pode ter vários nós de ação em execução ao mesmo tempo, como acender várias luzes simultaneamente. Os nós que seguem um fluxo paralelo não serão executados até que todas as ramificações do fluxo paralelo sejam concluídas.

Fluxos de execução paralela
Figura 2: fluxo de automação paralela

Outro tipo de fluxo de execução é um fluxo condicional, que pode mudar o fluxo de execução com base na avaliação de uma expressão.

Por exemplo, talvez você tenha uma automação que execute uma ação com base em se é noite. Um nó de condição verifica a hora do dia e segue o caminho de execução apropriado com base nessa avaliação.

Fluxo de condição
Figura 3: fluxo de condição

Um fluxo de seleção é útil quando você quer ter mais de um início que pode ativar sua automação. Quando você inclui duas ou mais ativações em um fluxo select, qualquer uma delas pode ativar a automação.

Por exemplo, é possível escrever uma automação que abaixe as persianas ao pôr do sol, se a temperatura subir acima de um determinado limite ou se o brilho exceder um limite. Três inicializadores separados processam cada um desses cenários, e todos os três seriam envolvidos em um fluxo select.

Selecionar fluxo
Figura 4: fluxo de seleção

Fluxos aninhados

Em automações complexas, os nós de fluxo de execução também podem ser aninhados. Por exemplo, é possível ter um fluxo sequencial que executa um fluxo paralelo.

Fluxos de execução aninhados
Figura 5: fluxos de execução aninhados

Os nós da DSL podem ser aninhados e combinados de várias maneiras para atender às suas necessidades específicas, de acordo com as restrições descritas na tabela a seguir. A coluna "Builder" tem um link para a documentação do builder com segurança de tipo do Kotlin, que detalha o que pode ser usado em cada tipo de nó.

Tabela: como os nós podem ser combinados
Pode conter o seguinte tipo de nó e dados Precisa estar em um dos seguintes tipos de nó
Starter Expressão Selecionar, sequencial
ManualStarter Selecionar, sequencial
StateReader Expressão (normalmente consistindo em um valor de atributo de traço) Ação, condição
Ação Comando, Entidade, Expressão Paralela, de seleção, sequencial
Sequencial Paralela, de seleção, sequencial
Paralela Ação Sequencial
Condição Expressão Paralelo, sequencial
Selecionar Condition, Sequential, Starter, ManualStarter Sequencial e precisa ser o primeiro nó no fluxo

DSL de automação

Nas APIs Home, as automações são definidas usando a DSL de automação (linguagem específica de domínio). A DSL de automação é implementada como uma DSL do Kotlin (linguagem específica do domínio), usando builders com segurança de tipos do Kotlin e foi projetada especificamente para definir modelos de automação.

Quando uma automação é compilada, os builders com segurança de tipo do Kotlin geram classes de dados do Kotlin que são serializadas em JSON de buffer de protocolo, usado para fazer chamadas aos Serviços de automação do Google.

A DSL de automação simplifica e otimiza o processo de criação de automações. Ele usa nativamente o mesmo modelo de dados de características padrão Matter e smart home apresentadas na API Device.

A DSL de automação também define a lógica de uma automação em termos de tipos de dispositivos abstratos, em vez de instâncias específicas localizadas na casa de um usuário. Ele permite que o desenvolvedor forneça parâmetros de entrada que podem ser usados no ambiente de execução para especificar instâncias reais de dispositivos, bem como outros valores de parâmetros importantes.

A sintaxe da DSL é semelhante à do Kotlin e igualmente segura em relação a tipos, mas uma automação escrita na DSL de automação é mais simples e concisa do que a mesma automação escrita em Kotlin puro.

Exemplo

Confira a seguir um exemplo de automação que liga um dispositivo, escrito usando a DSL de automação:

val automation = automation {
  name = "MyFirstAutomation"
  description = "If light1 is on, turn on light2."
  isActive = true
  sequential {
    val onOffTrait = starter<_>(device1, OnOffLightDevice, OnOff)
    condition() { expression = onOffTrait.onOff equals true }
    action(device2, OnOffLightDevice) { command(OnOff.on()) }
  }
}

Essa automação é muito básica: quando device1, uma luz acende (o atributo onOff muda para true) e envia o comando on() para acender device2.

A automação usa um nó sequential, o que indica que os nós serão executados em ordem sequencial.

No nó sequential, há nós comportamentais, como starter, condition e action. A saída do nó starter é atribuída a uma variável para uso no nó condition.