Guide du DSL iOS pour les automatisations complexes

Le DSL d'automatisation peut être utilisé pour créer des automatisations plus complexes que celles décrites dans le guide du DSL : automatisations de base sur iOS.

Séquentiel avec plusieurs actions

Séquentiel avec plusieurs actions

Une automatisation peut effectuer plusieurs actions. Par exemple, au lieu d'un seul nœud action, vous pouvez avoir plusieurs nœuds action, qui s'exécutent dans l'ordre séquentiel :

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {

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

}

Séquentiel avec plusieurs actions parallèles

Séquentiel avec plusieurs actions parallèles

Si vous placez plusieurs nœuds action dans un nœud parallel, les actions s'exécutent simultanément.

import GoogleHomeSDK
import GoogleHomeTypes

automation (
...
) {

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

}

Si le nœud sequential contient des nœuds action qui se trouvent après le nœud parallel, ils attendent que tous les nœuds du nœud parallel aient terminé leur exécution avant de s'exécuter.

Exécution conditionnelle

Par défaut, une automatisation exécute les nœuds de manière séquentielle ou en parallèle. Si vous avez besoin d'une logique de branchement conditionnel (exécuter différentes actions ou chemins en fonction des conditions d'exécution), utilisez des instructions if-then-else, qui sont créées à l'aide des blocs DSL de flux de contrôle conditionnel : ifThen, elseIf et orElse.

Alors qu'un nœud condition standard contrôle l'ensemble de l'automatisation (si la condition est évaluée à false, l'automatisation s'arrête immédiatement), les blocs ifThen permettent de contrôler le flux de branchement :

  • Nœud condition : arrête l'exécution de l'automatisation entière (ou du chemin d'exécution actuel) si l'expression est false.
  • ifThen / elseIf / orElse : évalue les conditions dans l'ordre. Si une condition est false, l'exécution passe à la branche elseIf suivante, à la branche de remplacement orElse ou aux nœuds suivants de l'automatisation si aucune condition n'est remplie.

Exécuter une action en fonction d'une condition

Le bloc ifThen évalue une expression conditionnelle. Si l'expression renvoie true, les actions ou les nœuds DSL imbriqués dans le bloc sont exécutés. Si l'évaluation renvoie false, les actions sont ignorées et l'automatisation passe aux nœuds suivants dans le flux séquentiel.

Vous pouvez utiliser un bloc ifThen autonome lorsque vous souhaitez uniquement effectuer une action de manière conditionnelle sans bloquer ni arrêter les nœuds suivants de l'automatisation :

// When a door opens, turn on the light only if it is off,
// and always broadcast an announcement.
typealias ContactSensorDevice = Matter.ContactSensorDeviceType
typealias BooleanStateTrait = Matter.BooleanStateTrait
typealias DimmableLightDevice = Matter.DimmableLightDeviceType
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let contactState = starter(
    contactSensor,
    ContactSensorDevice.self,
    BooleanStateTrait.self
  )
  let lightState = stateReader(
    light,
    DimmableLightDevice.self,
    OnOffTrait.self
  )
  contactState
  lightState

  condition {
    // Door opened (contact sensor open)
    contactState.stateValue.equals(false)
  }

  // Conditionally turn on the light if it's off
  ifThen(lightState.onOff.equals(false)) {
    action(light, DimmableLightDevice.self) {
      OnOffTrait.on()
    }
  }

  // Continue executing subsequent actions in the sequential flow
  action(structure) {
    Google.AssistantBroadcastTrait.broadcast(msg: "The door was opened.")
  }
}

Exécuter différentes actions en fonction d'une condition

Pour exécuter un ensemble d'actions lorsqu'une condition est vraie et un autre ensemble d'actions lorsqu'elle est fausse, associez le bloc .orElse { ... } facultatif après ifThen(...) { ... } :

// When the door is unlocked, turn on the entryway light if it is off;
// otherwise, broadcast a welcome message.
typealias DoorLockDevice = Matter.DoorLockDeviceType
typealias DoorLockTrait = Matter.DoorLockTrait
typealias DimmableLightDevice = Matter.DimmableLightDeviceType
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let doorLockEvent = starter(
    doorLock,
    DoorLockDevice.self,
    DoorLockTrait.LockOperationEvent.self
  )
  let lightState = stateReader(
    light,
    DimmableLightDevice.self,
    OnOffTrait.self
  )
  doorLockEvent
  lightState

  condition {
    doorLockEvent.lockOperationType.equals(.unlock)
  }

  ifThen(lightState.onOff.equals(false)) {
    action(light, DimmableLightDevice.self) {
      OnOffTrait.on()
    }
  }.orElse {
    action(structure) {
      Google.AssistantBroadcastTrait.broadcast(msg: "Welcome home!")
    }
  }
}

Enchaîner plusieurs conditions à la suite

Vous pouvez enchaîner un ou plusieurs blocs .elseIf(...) { ... } facultatifs pour évaluer plusieurs conditions de manière séquentielle. La première branche dont la condition est évaluée à true est exécutée, et toutes les branches restantes sont ignorées. Si aucune des conditions n'est évaluée à true, un bloc .orElse { ... } facultatif s'exécute (s'il est fourni) :

// Adjust climate controls based on room temperature changes.
typealias TemperatureSensorDeviceType = Matter.TemperatureSensorDeviceType
typealias TemperatureMeasurementTrait = Matter.TemperatureMeasurementTrait
typealias ThermostatDeviceType = Matter.ThermostatDeviceType
typealias SimplifiedThermostatTrait = Google.SimplifiedThermostatTrait
typealias FanDeviceType = Matter.FanDeviceType
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let tempStarter = starter(
    tempSensor,
    TemperatureSensorDeviceType.self,
    TemperatureMeasurementTrait.self
  )
  tempStarter

  // If temperature is high (>= 28°C / 2800 mC), switch thermostat to Cool mode
  ifThen(tempStarter.measuredValue.greaterThanOrEquals(2800)) {
    action(thermostat, ThermostatDeviceType.self) {
      SimplifiedThermostatTrait.setSystemMode(systemMode: .cool)
    }
  }.elseIf(tempStarter.measuredValue.lessThan(1800)) {
    // If temperature is low (< 18°C / 1800 mC), switch to Heat mode
    action(thermostat, ThermostatDeviceType.self) {
      SimplifiedThermostatTrait.setSystemMode(systemMode: .heat)
    }
  }.orElse {
    // Otherwise, turn on the fan
    action(fan, FanDeviceType.self) {
      OnOffTrait.on()
    }
  }
}

Flux conditionnels imbriqués

Les blocs conditionnels peuvent être imbriqués dans d'autres blocs ifThen, elseIf ou orElse, et combinés avec des nœuds parallel, delay(for:) et stateReader.

Les blocs ifThen, elseIf et orElse exécutent leur contenu sous forme de flux séquentiels. Vous pouvez placer n'importe quel nœud séquentiel dans chaque branche, y compris les blocs action, stateReader, parallel, delay(for:) et ifThen imbriqués.

Retards

Vous pouvez introduire des pauses dans vos automatisations à l'aide de la méthode delay(for:), qui utilise un argument Duration représentant la durée de la pause avant de poursuivre l'exécution. La durée de la mise en veille peut être comprise entre cinq secondes et 24 heures.

Par exemple, pour allumer et éteindre une lumière quatre fois avec une pause de cinq secondes entre chaque action :

typealias OnOffLightDevice = Matter.OnOffLightDeviceType
typealias OnOffTrait = Matter.OnOffTrait

sequential {
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
  delay(for:.seconds(5))
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
  delay(for:.seconds(5))
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
  delay(for:.seconds(5))
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
}

Suppression du déclencheur

La suppression de déclencheur est une fonctionnalité qui permet à votre automatisation d'ignorer un starter pendant une période spécifiée après l'événement de déclenchement initial. Par exemple, si l'automatisation comporte un starter déclenché par la détection de mouvement et que vous spécifiez une durée de suppression du déclencheur de cinq minutes, lorsque le starter se déclenche, il ne se déclenchera plus pendant les cinq minutes suivantes. Cela évite que l'automatisation ne se déclenche rapidement à plusieurs reprises.

Pour appliquer la suppression de déclencheur à votre automatisation, utilisez le mot clé suppress(for:) avec un argument Duration représentant le temps d'attente avant de répondre aux déclencheurs suivants. La durée de suppression peut être comprise entre cinq secondes et 24 heures.

typealias OccupancySensorDevice = Matter.OccupancySensorDeviceType
typealias OnOffLightDevice = Matter.OnOffLightDeviceType
typealias MotionDetectionTrait = Google.MotionDetectionTrait
typealias OnOffTrait = Matter.OnOffTrait

automation {
  let starterNode = starter(device, OccupancySensorDevice.self, MotionDetectionTrait.self)
  starterNode
  suppress(for: .seconds(30 * 60)) // 30 minutes
  action(light, OnOffLightDevice.self) { OnOffTrait.toggle() }
}

Notez que la suppression des déclencheurs affecte tous les starters d'une automatisation qui précèdent le Suppression.

Limiter le nombre d'exécutions

Vous pouvez limiter le nombre d'exécutions d'une automatisation.

Par exemple, vous pouvez configurer une automatisation ponctuelle qui passe l'aspirateur pendant que vous êtes absent pour la journée.

Pour ce faire, définissez le champ de métadonnées maxExecutionCount de l'automatisation. L'exemple suivant est une automatisation qui ne peut s'exécuter qu'une seule fois :

import GoogleHomeSDK
import GoogleHomeTypes

typealias RoboticVacuumCleanerDevice = Matter.RoboticVacuumCleanerDeviceType
typealias RvcRunModeTrait = Matter.RvcRunModeTrait
typealias AreaPresenceStateTrait = Google.AreaPresenceStateTrait

let draftAutomation = automation(
  name: "Vacuum home away",
  description: "Run the vacuum once when everyone is away.",
  maxExecutionCount: 1
) {
  let homeAwayState = starter(structure, AreaPresenceStateTrait.self)
  homeAwayState

  condition {
    homeAwayState.presenceState.equals(.presenceStateVacant)
  }

  action(vacuum, RoboticVacuumCleanerDevice.self) {
    RvcRunModeTrait.changeToMode(newMode: 1)
  }
}

L'automatisation est immédiatement supprimée une fois qu'elle a terminé son exécution pour la dernière fois et que maxExecutionCount est atteint. L'entrée de l'historique de l'automatisation reste dans l'onglet Google Home app (GHA) Activité, y compris automation_id.

Définir les attributs d'une caractéristique dans une action

Pour définir la valeur d'un attribut de trait :

  1. Créez un nœud update dans un nœud action, en incluant la caractéristique pertinente en tant qu'argument du nœud update :
    action(deviceReference, deviceType) {
      update(trait) {
    
      }
    }
    
  2. Dans le nœud update, pour chaque attribut à modifier, utilisez une fonction de mutateur et transmettez-lui la nouvelle valeur. Pour former le nom de la fonction de mutateur :
    1. Mettre en majuscule le nom de l'attribut
    2. Ajoutez le préfixe set.
    Par exemple, pour mettre à jour un attribut appelé defaultMoveRate, vous devez utiliser une fonction de mutateur appelée setDefaultMoveRate.

Notez qu'un nœud update peut avoir plusieurs fonctions de mutateur. Voici un exemple où deux attributs sont mis à jour :

typealias FanDeviceType = Matter.FanDeviceType
typealias FanControlTrait = Matter.FanControlTrait

action(fan, FanDeviceType.self) {
  update(FanControlTrait.self) {
    $0.setFanMode(.on)
  }
}