Questa è una panoramica dei concetti fondamentali del DSL di automazione su Android.
Componenti di automazione
Un'automazione è costituita dai seguenti componenti di base, generalmente valutati in questo ordine:
- Comando iniziale: definisce le condizioni iniziali che attivano l'automazione, ad esempio una modifica a un tratto. Un'automazione deve avere un comando iniziale.
- Condizione: eventuali vincoli aggiuntivi da valutare dopo l'attivazione di un'automazione. L'espressione in una condizione deve essere valutata come
trueaffinché le azioni di un'automazione possano procedere. - Azione: comandi o aggiornamenti di stato eseguiti quando tutte le condizioni sono state soddisfatte.
Ad esempio, potresti avere un'automazione che riduce l'intensità delle luci di una stanza quando la TV in quella stanza viene accesa tra il tramonto e l'alba. In questo esempio:
- Starter: la TV è stata accesa, il che rappresenta una modifica dello stato di una caratteristica della TV.
- Condizione: viene valutata l'ora corrente della casa in cui si trova la TV.
- Azione: le luci nella stessa stanza della TV vengono regolate.
L'automazione viene attivata quando la TV nella stanza viene accesa, ma viene eseguita solo se è soddisfatta la condizione "l'ora è compresa tra il tramonto e l'alba".
Oltre alla struttura di base, le automazioni nelle API Home contengono anche metadati, come name e description, che possono essere utilizzati per identificarle per sviluppatori e utenti.
Nodi
Nelle API Home, la struttura logica di un'automazione è costituita da nodi. I nodi sono unità astratte e riutilizzabili che rappresentano i comportamenti delle entità o i flussi di esecuzione. Ogni nodo può avere variabili di input e variabili di output che possono essere utilizzate da altri nodi.
| Nodo | Tipo di nodo | Implementazione di Kotlin | Descrizione |
|---|---|---|---|
| Starter | Comportamentale |
StarterNodeDsl
|
Avvia un'automazione quando lo stato di una caratteristica (qualsiasi attributo) cambia. |
| StateReader | Comportamentale |
StateReaderNodeDsl
|
Legge un attributo di un tratto e ti consente di acquisirne il valore per utilizzarlo nei nodi di condizione. |
| Azione | Comportamentale |
ActionNodeDsl
|
Richiama i comandi del tratto. |
| Sequenziale | Flusso di esecuzione |
SequentialFlow
|
Esegue i nodi di azione nidificati in sequenza. Questo è il comportamento di esecuzione predefinito. |
| Parallel | Flusso di esecuzione |
ParallelFlow
|
Esegue i nodi di azione nidificati in parallelo. |
| Condizione | Flusso di esecuzione |
ConditionNodeDsl
|
Modifica in modo condizionale il flusso di esecuzione in base alle valutazioni delle espressioni logiche. Le condizioni possono essere associate a un comando iniziale (condizioni specifiche del comando iniziale) o essere globali (applicate a tutti i comandi iniziali). |
| Seleziona | Flusso di esecuzione |
SelectFlow
|
Consente a più di un comando iniziale di attivare un'automazione. |
| IfFlow | Flusso di esecuzione |
IfFlowDsl
|
Esegue al massimo un'azione (o un ramo) in base alla condizione (se presente) che restituisce il valore true (simile a un'istruzione if-then-else). |
| Espressione | Valore |
Expression
|
Può essere il valore di un attributo di un tratto, una costante o un valore letterale e deve restituire un elenco, un numero, un valore booleano o una stringa. |
Nodi comportamentali
I nodi come i comandi iniziali e le azioni sono nodi comportamentali. I comandi iniziali attivano un'automazione in base alle modifiche degli attributi del dispositivo. Le azioni inviano comandi ai dispositivi o aggiornano gli attributi.
I nodi di comportamento sono in genere collegati ai tratti del dispositivo e allo stato dei tratti di output per l'utilizzo come input in altri nodi.
Nodi del flusso di esecuzione
Alcuni nodi rappresentano flussi di esecuzione, ad esempio sequenziali e paralleli. Ognuno di questi nodi contiene i nodi comportamentali che definiscono l'automazione.
Ad esempio, un flusso sequenziale può contenere nodi che vengono eseguiti in ordine sequenziale. In genere, si tratta di comando iniziale, condizione e azione.
Un flusso parallelo può avere più nodi di azione in esecuzione contemporaneamente, ad esempio l'accensione di più luci contemporaneamente. I nodi che seguono un flusso parallelo non verranno eseguiti finché non saranno terminati tutti i rami del flusso parallelo.
Un altro tipo di flusso di esecuzione è un flusso di condizione, che può modificare il flusso di esecuzione in base alla valutazione di un'espressione.
Ad esempio, potresti avere un'automazione che esegue un'azione in base al fatto che sia notte. Un nodo di condizione controlla l'ora del giorno, quindi segue il percorso di esecuzione appropriato in base a questa valutazione.
Un flusso di selezione è utile quando vuoi avere più di un comando iniziale che può attivare l'automazione. Quando racchiudi due o più starter in un flusso select, uno qualsiasi degli starter può attivare l'automazione.
Ad esempio, potresti scrivere un'automazione che abbassa le tapparelle al tramonto, se la temperatura supera una determinata soglia o se la luminosità supera una soglia. Tre starter separati gestiscono ciascuno di questi scenari e tutti e tre verrebbero inseriti in un flusso select.
Un flusso if-then-else (IfFlow) consente l'esecuzione condizionale con branching all'interno di un'automazione. A differenza di un nodo condition, che interrompe l'intera automazione se la condizione è false, un flusso if-then-else esegue in modo condizionale azioni specifiche quando una condizione è vera e può tornare a condizioni alternative o azioni di riserva oppure continuare con i nodi successivi dell'automazione. Per maggiori dettagli, consulta
Esecuzione condizionale.
Flussi nidificati
Nelle automazioni complesse, i nodi del flusso di esecuzione possono anche essere nidificati. Ad esempio, potresti avere un flusso sequenziale che esegue un flusso parallelo.
I nodi DSL possono essere nidificati e combinati in vari modi per soddisfare le tue esigenze specifiche, in base ai vincoli descritti nella tabella seguente. La colonna Builder rimanda alla documentazione del builder typesafe di Kotlin, che descrive in dettaglio cosa è consentito utilizzare in ogni tipo di nodo.
| Nodo | Può contenere il seguente tipo di nodo e i seguenti dati | Deve essere uno dei seguenti tipi di nodo |
|---|---|---|
| Starter | Espressione | Seleziona, Sequenziale |
| ManualStarter | Seleziona, Sequenziale | |
| StateReader | Espressione (in genere costituita da un valore dell'attributo del tratto) | IfFlow, Parallel, Sequential |
| Azione | Comando, entità, espressione | IfFlow, Parallel, Select, Sequential |
| Sequenziale | IfFlow, Parallel, Select, Sequential | |
| Parallel | Azione | IfFlow, Sequential |
| Condizione | Espressione | IfFlow, Parallel, Sequential |
| Seleziona | Condition, Sequential, Starter, ManualStarter | Sequenziale e deve essere il primo nodo del flusso |
| IfFlow | Action, Condition, Delay, IfFlow, Parallel, Sequential, StateReader, Suppression | Sequenziale |
DSL di automazione
Nelle API Home, le automazioni vengono definite utilizzando il DSL (Domain-Specific Language) di automazione. Il DSL di automazione è implementato come DSL (domain-specific language) Kotlin, utilizzando i builder type-safe di Kotlin ed è progettato specificamente per la definizione di template di automazione.
Quando un'automazione viene compilata, i builder di sicurezza dei tipi di Kotlin generano classi di dati Kotlin che vengono poi serializzate in JSON del buffer di protocollo, utilizzato per effettuare chiamate ai servizi di automazione di Google.
Il DSL di automazione semplifica e ottimizza il processo di creazione delle automazioni. Utilizza in modo nativo lo stesso modello di dati dei tratti standard di Matter e dei tratti di smart home presenti nell'API Device.
Il DSL di automazione definisce anche la logica di un'automazione in termini di tipi di dispositivi astratti, anziché di istanze di dispositivi specifiche situate nella casa di un utente. Consente allo sviluppatore di fornire parametri di input che possono essere utilizzati in fase di runtime per specificare istanze di dispositivi effettive, nonché altri valori parametro importanti.
La sintassi DSL è simile a quella di Kotlin ed è altrettanto sicura per i tipi, ma un'automazione scritta in DSL di automazione è più semplice e concisa della stessa automazione scritta in Kotlin puro.
Esempio
Di seguito è riportato un esempio di automazione che accende un dispositivo, scritta utilizzando il DSL di automazione:
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()) }
}
}
Questa automazione è molto semplice: quando device1, una luce, si accende (l'attributo onOff cambia in true), invia il comando on() per accendere device2.
L'automazione utilizza un nodo sequential, il che indica che i suoi nodi verranno eseguiti in ordine sequenziale.
All'interno del nodo sequential sono presenti nodi comportamentali come starter,
condition e action. L'output del nodo starter viene assegnato a una variabile da utilizzare nel nodo condition.