Guida al DSL per iOS

Utilizza la seguente guida per capire come i vari nodi DSL di automazione possono essere utilizzati per creare un'automazione.

Tutta la DSL di automazione è inserita in un singolo nodo automation. Il nodo automation forma il limite tra il contesto del linguaggio Swift esterno e il contesto DSL incorporato.

Flusso sequenziale

Il flusso sequenziale è il tipo di flusso di automazione predefinito.

Esempio di DSL sequenziale

Ecco un modello DSL di automazione molto semplice che utilizza un flusso sequenziale composto da un comando iniziale, una condizione e un'azione:

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {
  starter(...)
  condition {...}
  action {...}
}

Questo può essere perfezionato aggiungendo altri nodi.

Starter

I nodi di comando iniziale definiscono le circostanze iniziali che attivano un'automazione. Ad esempio, una modifica dello stato o del valore. Un'automazione deve avere almeno un comando iniziale, altrimenti la convalida non andrà a buon fine. Per aggiungere più di un comando iniziale a un'automazione, devi utilizzare un nodo select.

Comando iniziale basato sull'attributo del trait

Quando dichiari un nodo di comando iniziale basato su un attributo del trait, specifica:

  • Il dispositivo
  • Il tipo di dispositivo a cui appartiene il trait
  • Il trait
starter(
  thermostat,
  Matter.TemperatureSensorDeviceType.self,
  Matter.TemperatureMeasurementTrait.self
)

Il parametro del tipo di dispositivo è obbligatorio perché ti consente di specificare il tipo di dispositivo all'interno di un dispositivo a cui si rivolge l'automazione. Ad esempio, un dispositivo potrebbe essere composto da un FanDeviceType e un HeatingCoolingUnitDeviceType, entrambi contenenti il OnOffTrait trait. Se specifichi il tipo di dispositivo, non ci sono ambiguità sulla parte del dispositivo che attiva l'automazione.

Comando iniziale basato sull'evento

Quando dichiari un nodo di comando iniziale basato su un evento, specifica:

  • Il dispositivo
  • Il tipo di dispositivo a cui appartiene il trait
  • L'evento
starter(
  doorbell,
  Google.GoogleDoorbellDeviceType.self,
  Google.DoorbellPressTrait.DoorbellPressedEvent
)

Comando iniziale basato su una struttura e un evento, con parametri

Alcuni eventi possono avere parametri, quindi questi parametri devono essere inclusi anche nel comando iniziale.

Ad esempio, questo comando iniziale utilizza TimeTrait's ScheduledEvent per attivare l'automazione alle 7:00:

typealias TimeTrait = Google.TimeTrait

let earlyMorning = starter(
  structure,
  TimeTrait.ScheduledEvent.self
) {
  TimeTrait.ScheduledEvent.clockTime(TimeOfDay(hours: 7, minutes: 0))
}

Comando iniziale basato sul meteo

Puoi specificare le condizioni meteorologiche attuali o previste in un comando iniziale utilizzando il trait Meteo:

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

Consulta Chiudere le persiane se è probabile che piova nella pagina Automazioni di esempio.

Comando iniziale manuale

Un comando iniziale manuale è un tipo speciale di comando iniziale che consente all'utente di eseguire manualmente l'automazione.

Quando dichiari un comando iniziale manuale:

  • Non specificare un trait o un tipo di dispositivo.
  • Fornisci un elemento dell'interfaccia utente che chiama Automation.execute().

Quando inserisci un comando iniziale manuale in un flusso select insieme a un altro comando iniziale, il comando iniziale manuale sostituisce l'altro comando iniziale:

select {
  manualStarter()
  starter(
    thermostat,
    Matter.TemperatureSensorDeviceType.self,
    Matter.TemperatureMeasurementTrait.self
  )
}

Tieni presente che tutti i nodi condition che seguono un comando iniziale manuale verranno valutati e potrebbero bloccare l'esecuzione dell'automazione, a seconda dell'espressione condition.

Separare un comando iniziale manuale da uno condizionale

Un modo per strutturare l'automazione in modo che i nodi condition non blocchino un'automazione attivata con un comando iniziale manuale è inserire l'altro comando iniziale in un flusso sequenziale separato insieme alla relativa condition:

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {

  select {
    sequential {
      starter(...)
      condition {...}
    }
    sequential {
      manualStarter()
    }
  }
  action {...}

}

Fare riferimento al valore di un attributo

Per utilizzare il valore di un attributo in un'espressione, utilizza la seguente sintassi.

Con un stateReader:

typealias TimeTrait = Google.TimeTrait

let time = stateReader(structure, TimeTrait.self)
time
let currTime = time.currentTime

Con un starter:

typealias LaundryWasherDeviceType = Matter.LaundryWasherDeviceType
typealias OnOffTrait = Google.OnOffTrait

let starterNode = starter(device1, LaundryWasherDeviceType.self, OnOffTrait.self)
starterNode
condition {
  starterNode.onOff.equals(true)
}

Nodi ed espressioni di condizione

Un nodo di condizione rappresenta un punto decisionale che determina se l'automazione continua o meno. Un'automazione può avere più nodi condition. Se l'espressione di un nodo condition restituisce false, l'esecuzione dell'intera automazione termina.

All'interno di un nodo condition, puoi combinare più criteri di condizione utilizzando vari operatori, purché l' espressione restituisca un singolo valore booleano. Se il valore risultante è true, la condizione è soddisfatta e l'automazione continua l'esecuzione del nodo successivo. Se è false, l'automazione interrompe l'esecuzione a quel punto.

Le espressioni sono formate in modo simile alle espressioni in Swift e possono contenere valori primitivi come numeri, caratteri, stringhe e valori booleani, nonché valori Enum. Il raggruppamento delle sottoespressioni con le parentesi consente di controllare l'ordine in cui vengono valutate.

Ecco un esempio di condition che combina più sottoespressioni in un'unica espressione:

condition {
  let exp1 = starterNode.lockState.equals(.unlocked)
  let exp2 = stateReaderNode.lockState.equals(true)
  let exp3 = occupancySensingDevice.occupied.notEquals(0)
  (exp1.and(exp2)).or(exp3)
}

Puoi fare riferimento al valore di un trait a cui hai accesso tramite un comando iniziale:

typealias OnOffTrait = Matter.OnOffTrait

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

stateReader

L'altro modo per fare riferimento ai valori degli attributi del trait in un nodo condition è con un nodo stateReader.

Per farlo, acquisisci prima il valore dell'attributo del trait in un nodo stateReader. Un stateReader accetta come argomenti la structure e il trait:

typealias ActivatedCarbonFilterMonitoringTrait = Matter.ActivatedCarbonFilterMonitoringTrait

let filterMonitoringState = stateReader(structure, ActivatedCarbonFilterMonitoringTrait.self)

Quindi fai riferimento a stateReader nel nodo condition:

condition {
filterMonitoringState.changeIndication.equals(.warning)
}

Utilizzando operatori di confronto e logici, è possibile utilizzare più stateReaders in un nodo condition:

typealias ArmDisarm = Google.ArmDisarmTrait
typealias DoorLockDevice = Matter.DoorLockDeviceType
typealias DoorLock = Matter.DoorLockTrait

let armState = stateReader(doorLock, DoorLockDevice.self, ArmDisarm )
let doorLockState = stateReader(doorLock, DoorLockDevice.self, DoorLock)
armState
doorLockState
condition {
  let exp1 = armState.armState
  let exp2 = doorLockState.lockState
  exp1.and(exp2)
}

Durata della condizione

Oltre a un'espressione booleana in una condizione, puoi specificare un intervallo di tempo durante il quale l'espressione deve essere vera per eseguire l'automazione. Ad esempio, puoi definire una condizione che si attiva solo se una luce è accesa da dieci minuti.

condition(for: .seconds(600)) {
lightStateReader.onOff.equals(true)
}

La durata può variare da uno a 30 minuti.

Nodi di azione

Il nodo di azione è il punto in cui si svolge il lavoro dell'automazione. In questo esempio, l'azione richiama il AssistantBroadcastTrait's broadcast() comando:

action(speaker, SpeakerDeviceType.self) {
  Google.AssistantBroadcastTrait.broadcast(msg: "Oven Cycle Complete")
}