Conceptos de DSL

Esta es una descripción general de los conceptos fundamentales de la DSL de Automation.

Componentes de automatización

Una automatización consta de los siguientes componentes básicos, que suelen evaluarse en este orden:

  1. Activador: Define las condiciones iniciales que activan la automatización, como un cambio en un atributo. Una automatización debe tener un activador.
  2. Condición: Son las restricciones adicionales que se deben evaluar después de que se activa una automatización. La expresión de una condición debe evaluarse como true para que se ejecuten las acciones de una automatización.
  3. Acción: Son los comandos o las actualizaciones de estado que se realizan cuando se cumplen todas las condiciones.

Por ejemplo, tal vez tengas una automatización que atenúe las luces de una habitación cuando la TV de esa habitación se enciende entre el atardecer y el amanecer. En este ejemplo:

  1. Activador: La TV se encendió, lo que representa un cambio de estado en un atributo de TV.
  2. Condición: Se evalúa la hora actual de la casa en la que se encuentra la TV.
  3. Acción: Las luces de la misma habitación que la TV se atenúan.

La automatización se activaría cuando se encienda la TV de la habitación, pero solo se ejecutará si se cumple la condición de "la hora está entre el atardecer y el amanecer".

Además de la estructura básica, las automatizaciones en las APIs de Home también contienen metadatos, como name y description, que se pueden usar para identificarlas para los desarrolladores y los usuarios.

Nodos

En las APIs de Home, la estructura lógica de una automatización consta de nodes. Los nodos son unidades abstractas y reutilizables que representan los comportamientos de las entidades o los flujos de ejecución. Cada nodo puede tener variables de entrada, así como variables de salida que pueden ser consumidas por otros nodos.

Tabla: Tipos de nodos de automatización
Nodo Tipo de nodo Implementación de Kotlin Descripción
Activador Comportamiento StarterNodeDsl Inicia una automatización cuando cambia el estado de un rasgo (cualquier atributo).
StateReader Comportamiento StateReaderNodeDsl Lee un atributo de rasgo y te permite capturar su valor para usarlo en los nodos de condición.
Acción Comportamiento ActionNodeDsl Invoca comandos de atributos.
Secuencial Flujo de ejecución SequentialFlow Ejecuta los nodos de acción anidados en secuencia. Este es el comportamiento de ejecución predeterminado.
Paralelo Flujo de ejecución ParallelFlow Ejecuta nodos de acción anidados en paralelo.
Afección Flujo de ejecución ConditionNodeDsl Cambiar condicionalmente el flujo de ejecución en función de las evaluaciones de expresiones lógicas Las condiciones pueden estar asociadas con un activador (condiciones específicas del activador) o ser globales (se aplican a todos los activadores).
Seleccionar Flujo de ejecución SelectFlow Permite que más de un activador active una automatización.
Expresión Valor Expression Puede ser el valor del atributo de un rasgo, una constante o un valor literal, y debe evaluarse como una lista, un número, un valor booleano o una cadena.

Nodos de comportamiento

Los nodos, como los activadores y las acciones, son nodos de comportamiento. Los activadores activan una automatización en función de los cambios en los atributos del dispositivo. Las acciones emiten comandos del dispositivo o actualizan atributos.

Por lo general, los nodos de comportamiento están vinculados a los atributos del dispositivo y al estado del atributo de salida para usarlos como entrada en otros nodos.

Nodos del flujo de ejecución

Algunos nodos representan flujos de ejecución, como los secuenciales y los paralelos. Cada uno de estos nodos contiene los nodos de comportamiento que definen la automatización.

Por ejemplo, un flujo secuencial puede contener nodos que se ejecutan en orden secuencial. Por lo general, estos serían el activador, la condición y la acción.

Flujos de ejecución secuenciales
Figura 1: Flujo de automatización secuencial

Un flujo paralelo puede tener varios nodos de acción que se ejecutan al mismo tiempo, como encender varias luces al mismo tiempo. Los nodos que siguen un flujo paralelo no se ejecutarán hasta que finalicen todas las ramas del flujo paralelo.

Flujos de ejecución en paralelo
Figura 2: Flujo de automatización en paralelo

Otro tipo de flujo de ejecución es un flujo de condiciones, que puede cambiar el flujo de ejecución según la evaluación de una expresión.

Por ejemplo, tal vez tengas una automatización que realice una acción según si es de noche. Un nodo de condición verifica la hora del día y, luego, sigue la ruta de ejecución adecuada según esa evaluación.

Flujo de condiciones
Figura 3: Flujo de condiciones

Un flujo de selección es útil cuando deseas tener más de un activador que pueda activar tu automatización. Cuando unes dos o más activadores en un flujo select, cualquiera de ellos puede activar la automatización.

Por ejemplo, puedes escribir una automatización que baje las cortinas al atardecer, si la temperatura aumenta por encima de un umbral determinado o si el brillo supera un umbral. Tres activadores independientes controlan cada una de estas situaciones, y los tres se unirían en un flujo select.

Seleccionar flujo
Figura 4: Flujo de selección

Flujos anidados

En automatizaciones complejas, los nodos del flujo de ejecución también se pueden anidar. Por ejemplo, puedes tener un flujo secuencial que ejecute un flujo paralelo.

Flujos de ejecución anidados
Figura 5: Flujos de ejecución anidados

Los nodos de DSL se pueden anidar y combinar de varias maneras para satisfacer tus necesidades específicas, según las restricciones que se describen en la siguiente tabla. La columna "Compilador" vincula a la documentación del compilador de acceso seguro a tipos de Kotlin, que detalla lo que se permite usar en cada tipo de nodo.

Tabla: Cómo se pueden combinar los nodos
Nodo Builder Puede contener el siguiente tipo de nodo y datos Debe estar dentro de uno de los siguientes tipos de nodos:
Activador AutomationBuilder Expresión Selecciona, Secuencial
ManualStarter AutomationBuilder Selecciona, Secuencial
StateReader AutomationBuilder Expresión (por lo general, consiste en un valor de atributo de rasgo) Acción, condición
Acción ActionBuilder Comando, entidad y expresión Paralelo, Seleccionado y Secuencial
Secuencial SequentialFlowBuilder Paralelo, Seleccionado y Secuencial
Paralelo ParallelFlowBuilder Acción Secuencial
Afección ConditionBuilder Expresión Paralelo, secuencial
Seleccionar AutomationBuilder Condition, Sequential, Starter, ManualStarter Es secuencial y debe ser el primer nodo del flujo.

DSL de automatización

En las APIs de Home, las automatizaciones se definen con el DSL de automatización (lenguaje específico de dominio). La DSL de Automation se implementa como una DSL de Kotlin (lenguaje específico de dominio) con compiladores de acceso seguro a tipos de Kotlin y está diseñada específicamente para definir plantillas de automatización.

Cuando se compila una automatización, los compiladores de tipo seguro de Kotlin generan clases de datos de Kotlin que, luego, se serializan en un búfer de protocolo JSON, que se usa para realizar llamadas a los servicios de automatización de Google.

La DSL de automatización simplifica y optimiza el proceso de compilación de automatizaciones. De forma nativa, usa el mismo modelo de datos de atributos estándar Matter y atributos smart home que se muestran en la API de Device.

La DSL de automatización también define la lógica de una automatización en términos de tipos de dispositivos abstractos, en lugar de instancias de dispositivos específicos ubicadas en la casa de un usuario. Permite que el desarrollador proporcione parámetros de entrada que se pueden usar en el entorno de ejecución para especificar instancias de dispositivos reales, así como otros valores de parámetros importantes.

La sintaxis de la DSL es similar a la de Kotlin y es igualmente segura para tipos, pero una automatización escrita en la DSL de Automation es más simple y concisa que la misma automatización escrita en Kotlin puro.

Ejemplo

El siguiente es un ejemplo de automatización que enciende un dispositivo, escrito con la DSL de Automation:

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()) }
  }
}

Esta automatización es muy básica: cuando device1, una luz, se enciende (el atributo onOff cambia a true), envía el comando on() para encender device2.

La automatización usa un nodo sequential, que indica que sus nodos se ejecutarán en orden secuencial.

Dentro del nodo sequential, se encuentran los nodos de comportamiento, como starter, condition y action. El resultado del nodo starter se asigna a una variable para usarla en el nodo condition.