Usa la siguiente guía para comprender cómo se pueden usar varios nodos de DSL de Automation para construir una automatización.
Todo el DSL de automatización se coloca dentro de un solo nodo automation. El nodo automation forma el límite entre el contexto del lenguaje Kotlin externo y el contexto de DSL incorporado.
Flujo secuencial
El flujo secuencial es el tipo predeterminado de flujo de automatización.
Aquí tienes una plantilla de DSL de automatización muy básica que usa un flujo secuencial que consta de un activador, una condición y una acción:
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 {...}
}
}
Esto se puede definir mejor agregando nodos adicionales.
Starter
Los nodos de activador definen las circunstancias iniciales que activan una automatización. Por ejemplo, un cambio de estado o valor. Una automatización debe tener al menos un
activador; de lo contrario, fallará la validación. Para agregar más de un activador a una automatización, debes usar un nodo select.
Activador basado en el atributo de un rasgo
Cuando declares un nodo de inicio que se base en un atributo de característica, especifica lo siguiente:
- el dispositivo
- el tipo de dispositivo al que pertenece el atributo
- el rasgo
starter<_>(thermostat, TemperatureSensorDevice, TemperatureMeasurement)
El parámetro de tipo de dispositivo es obligatorio porque te permite especificar a qué tipo de dispositivo dentro de un dispositivo se dirige la automatización. Por ejemplo, un dispositivo puede estar compuesto por un FanDevice y un HeatingCoolingUnitDevice, que contienen el atributo OnOff. Si especificas el tipo de dispositivo, no habrá ambigüedad sobre qué parte del
dispositivo activa la automatización.
Activador basado en un evento
Cuando declares un nodo de activador que se base en un evento, especifica lo siguiente:
- el dispositivo
- el tipo de dispositivo al que pertenece el atributo
- el evento
starter<_>(doorBell, GoogleDoorbellDevice, DoorbellPressed)
Activador basado en una estructura y un evento, con parámetros
Algunos eventos pueden tener parámetros, por lo que estos también deben incluirse en el activador.
Por ejemplo, este activador usa el atributo ScheduledTimeEvent de la característica Time para activar la automatización a las 7:00 a.m.:
val earlyMorning = starter<_>(structure, Time.ScheduledTimeEvent) {
parameter(Time.ScheduledTimeEvent.clockTime(
LocalTime.of(7, 0, 0, 0)))
}
Iniciador basado en el clima
Puedes especificar las condiciones climáticas actuales o previstas en un activador con el atributo Weather:
val weatherState = starter<_>(structure, trait = Weather)
Consulta Cierra las persianas si es probable que llueva en la página Ejemplos de automatizaciones.
Arrancador manual
Un activador manual es un tipo especial de activador que permite al usuario ejecutar la automatización de forma manual.
Cuando declares un activador manual, ten en cuenta lo siguiente:
- No especifiques un rasgo ni un tipo de dispositivo.
- Proporciona un elemento de la IU que llame a
Automation.execute().
Cuando colocas un activador manual en un flujo de select junto con otro activador, el
activador manual anula el otro activador:
select {
manualStarter()
starter<_>(thermostat, TemperatureSensorDevice, TemperatureMeasurement)
}
Ten en cuenta que se evaluarán todos los nodos condition que sigan a un activador manual,
y podrían bloquear la ejecución de la automatización, según la expresión
condition.
Una forma de estructurar tu automatización para que los nodos condition no bloqueen una
automatización que se activó con un activador manual es colocar el otro activador
en un flujo secuencial separado junto con su condition:
automation_graph {
sequential {
select {
sequential {
starter<_>(...)
condition {...}
}
sequential {
manualStarter()
}
}
action {...}
}
}
Cómo hacer referencia al valor de un atributo
Para usar el valor de un atributo en una expresión, usa la siguiente sintaxis.
Con un stateReader:
val time = stateReader<_>(structure, Structure, Time)
val currTime = time.currentTime
Con un starter:
val starterNode = starter<_>(device1, LaundryWasherDevice, OnOff)
condition() {
expression = starterNode.onOff equals true
}
Nodos y expresiones de condición
Un nodo de condición representa un punto de decisión que determina si la
automatización continúa o no. Una automatización puede tener varios nodos condition.
Si la expresión de cualquier nodo condition se evalúa como false, finaliza la ejecución de toda la automatización.
Dentro de un nodo condition, puedes combinar varios criterios de condición con
varios operadores, siempre que la expresión
se evalúe como un solo
valor booleano. Si el valor resultante es true, se cumple la condición y la
automatización continúa con la ejecución del siguiente nodo. Si es false, la automatización
deja de ejecutarse en ese punto.
Las expresiones se forman de manera similar a las expresiones en Kotlin y pueden contener valores primitivos, como números, caracteres, cadenas y valores booleanos, así como valores Enum. Agrupar subexpresiones con paréntesis te permite controlar el orden en que se evalúan.
Este es un ejemplo de un condition que combina varias subexpresiones en una
sola expresión:
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)
}
Puedes hacer referencia al valor de un atributo al que se accede a través de un activador:
val starterNode = starter<_>(device, OnOff)
condition() { expression = starterNode.onOff equals true }
stateReader
La otra forma de hacer referencia a los valores de los atributos de rasgos en un nodo condition es con
un nodo stateReader.
Para ello, primero captura el valor del atributo de rasgo en un nodo stateReader. Un stateReader toma el structure y el atributo como argumentos:
import com.google.home.automation.stateReader
...
val filterMonitoringState = stateReader<_>(structure, ActivatedCarbonFilterMonitoring)
Luego, haz referencia al stateReader en el nodo condition:
condition() {
expression =
filterMonitoringState.changeIndication
.equals(ChangeIndicationEnum.Warning)
}
Con los operadores de comparación y
lógicos, se pueden usar varios
stateReaders en un nodo condition:
val armState = stateReader<_>(doorLock, DoorLockDevice, ArmDisarm )
val doorLockState = stateReader<_>(doorLock, DoorLockDevice, DoorLock)
condition() {
expression =
(armState.armState equals true)
and
(doorLockState.lockState equals true)
}
Duración de la condición
Además de una expresión booleana en una condición, puedes especificar un período durante el cual la expresión debe ser verdadera para ejecutar la automatización. Por ejemplo, puedes definir una condición que se active solo si una luz estuvo encendida durante diez minutos.
condition {
expression(lightStateReader.onOff == true)
forDuration(Duration.ofMinutes(10))
}
La duración puede variar de 5 segundos a 24 horas.
Nodos de acción
El nodo de acción es donde se realiza el trabajo de la automatización.
En este ejemplo, la acción invoca el comando broadcast() del atributo AssistantBroadcast:
action(device, SpeakerDevice) {
command(AssistantBroadcast.broadcast("Intruder detected!"))
}
Declaraciones de importación
Cuando desarrollas automatizaciones, no siempre es obvio cómo importar varios elementos de las APIs de Home a tu código.
Los atributos de rasgos se importan del objeto Companion del rasgo:
import com.google.home.matter.standard.OnOff.Companion.onOff
Las estructuras de datos que define un atributo se importan de la clase de atributo cuyo nombre termina en "-Trait":
import com.google.home.matter.standard.MediaPlaybackTrait.PlaybackStateEnum
Los comandos de rasgos se importan desde el objeto Companion del rasgo:
import com.google.home.matter.standard.Thermostat.Companion.setTemperatureSetpointHold