Les API Automation sont accessibles via les API Home pour Android, mais comme leur point d'entrée se fait par le biais d'une structure, une autorisation doit d'abord être accordée sur la structure avant de pouvoir les utiliser.
Une fois les autorisations accordées pour une structure, importez ces packages dans votre application :
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id
import com.google.home.Structure
Une structure contient une interface HasAutomations
avec les méthodes spécifiques à l'automatisation suivantes :
API | Description |
---|---|
automations() |
Répertorie toutes les automatisations appartenant à la structure. Seules les automatisations que vous avez créées à l'aide des API Home sont renvoyées. |
createAutomation(automation) |
Créez une instance d'automatisation pour une structure. |
deleteAutomation(automationId) |
Supprimez une instance d'automatisation par son ID. |
Créer une automatisation
Après avoir créé une instance de Home et reçu les autorisations de l'utilisateur, récupérez la structure et les appareils :
val structure = homeManager.structures().list().single()
val device = homeManager.devices().get(Id("myDevice"))!!
Définissez ensuite la logique de votre automatisation à l'aide du DSL d'automatisation. Dans les API Home, une automatisation est représentée par l'interface Automation
. Cette interface contient un ensemble de propriétés :
- Métadonnées, comme le nom et la description.
- Indicateurs qui indiquent, par exemple, si l'automatisation peut être exécutée ou non.
- Liste des nœuds contenant la logique de l'automatisation, appelée graphique d'automatisation, représentée par la propriété
automationGraph
.
automationGraph
est de type SequentialFlow
par défaut. Il s'agit d'une classe qui contient une liste de nœuds qui s'exécutent dans l'ordre séquentiel. Chaque nœud représente un élément de l'automatisation, tel qu'un déclencheur, une condition ou une action.
Attribuez un name
et un description
à l'automatisation.
Lors de la création d'une automatisation, l'option isActive
est définie par défaut sur true
. Il n'est donc pas nécessaire de définir explicitement cette option, sauf si vous souhaitez que l'automatisation soit désactivée au départ. Dans ce cas, définissez l'indicateur sur false
lors de la création.
L'interface DraftAutomation
est utilisée pour créer des automatisations, et l'interface Automation
est utilisée pour la récupération. Par exemple, voici le DSL d'automatisation pour une automatisation qui allume un appareil lorsqu'un autre appareil est allumé :
import com.google.home.automation.Action
import com.google.home.automation.Automation
import com.google.home.automation.Condition
import com.google.home.automation.DraftAutomation
import com.google.home.automation.Equals
import com.google.home.automation.Node
import com.google.home.automation.SequentialFlow
import com.google.home.automation.Starter
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.matter.standard.OnOff
import com.google.home.Structure
...
val automation: DraftAutomation = automation {
name = "MyFirstAutomation"
description = "Turn on a device when another device is turned on."
sequential {
val starterNode = starter<_>(device1, OnOffLightDevice, trait=OnOff)
condition() { expression = stateReaderNode.onOff equals true }
action(device2, OnOffLightDevice) { command(OnOff.on()) }
}
}
Une fois le DSL d'automatisation défini, transmettez-le à la méthode createAutomation()
pour créer l'instance DraftAutomation
:
val createdAutomation = structure.createAutomation(automation)
À partir de là, vous pouvez utiliser toutes les autres méthodes d'automatisation sur l'automatisation, telles que execute()
, stop()
et update()
.
Erreurs de validation
Si la création d'une automatisation ne passe pas la validation, un message d'avertissement ou d'erreur fournit des informations sur le problème. Pour en savoir plus, consultez la documentation de référence sur ValidationIssueType
.
Exemples de code
Nous présentons ici des exemples de code qui pourraient être utilisés pour implémenter des parties des automatisations hypothétiques décrites sur la page Concevoir une automatisation sur Android.
Automatisation simple
Une automatisation qui lève les stores à 8h00 peut être implémentée comme suit :
// get all the automation node candidates in the structure
val allCandidates = structure.allCandidates().first()
// determine whether a scheduled automation can be constructed
val isSchedulingSupported =
allCandidates.any {
it is EventCandidate &&
it.eventFactory == Time.ScheduledTimeEvent &&
it.unsupportedReasons.isEmpty()
}
// get the blinds present in the structure
val blinds =
allCandidates
.filter {
it is CommandCandidate &&
it.commandDescriptor == WindowCoveringTrait.UpOrOpenCommand &&
it.unsupportedReasons.isEmpty()
}
.map { it.entity }
.filterIsInstance<HomeDevice>()
.filter { it.has(WindowCoveringDevice) }
if (isSchedulingSupported && blinds.isNotEmpty()) {
// Proceed to create automation
val automation: DraftAutomation = automation {
name = "Day time open blinds"
description = "Open all blinds at 8AM everyday"
isActive = true
sequential {
// At 8:00am local time....
val unused =
starter(structure, Time.ScheduledTimeEvent) {
parameter(Time.ScheduledTimeEvent.clockTime(LocalTime.of(8, 0, 0, 0)))
}
// ...open all the blinds
parallel {
for (blind in blinds) {
action(blind, WindowCoveringDevice) { command(WindowCovering.upOrOpen()) }
}
}
}
}
val createdAutomation = structure.createAutomation(automation)
} else if (!isSchedulingSupported) {
// Cannot create automation.
// Set up your address on the structure, then try again.
} else {
// You don't have any WindowCoveringDevices.
// Try again after adding some blinds to your structure.
}
Automatisation complexe
Une automatisation qui déclenche des lumières clignotantes lorsqu'un mouvement est détecté peut être implémentée comme suit :
import com.google.home.Home
import com.google.home.HomeClient
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
import com.google.home.automation.action
import com.google.home.automation.automation
import com.google.home.automation.equals
import com.google.home.automation.parallel
import com.google.home.automation.starter
import com.google.home.google.AssistantBroadcast
import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOff.Companion.toggle
import com.google.home.matter.standard.OnOffLightDevice
import java.time.Duration
// get all the automation node candidates in the structure
val allCandidates = structure.allCandidates().first()
// get the lights present in the structure
val availableLights = allCandidates.filter {
it is CommandCandidate &&
it.commandDescriptor == OnOffTrait.OnCommand
}.map { it.entity }
.filterIsInstance<HomeDevice>()
.filter {it.has(OnOffLightDevice) ||
it.has(ColorTemperatureLightDevice) ||
it.has(DimmableLightDevice) ||
it.has(ExtendedColorLightDevice)}
val selectedLights = ... // user selects one or more lights from availableLights
automation {
isActive = true
sequential {
// If the presence state changes...
val starterNode = starter<_>(structure, AreaPresenceState)
// ...and if the area is occupied...
condition() {
expression = starterNode.presenceState equals PresenceState.PresenceStateOccupied
}
// "blink" the light(s)
parallel {
for(light in selectedLights) {
action(light, OnOffLightDevice) { command(OnOff.toggle()) }
delayFor(Duration.ofSeconds(1))
action(light, OnOffLightDevice) { command(OnOff.toggle()) }
delayFor(Duration.ofSeconds(1))
action(light, OnOffLightDevice) { command(OnOff.toggle()) }
delayFor(Duration.ofSeconds(1))
action(light, OnOffLightDevice) { command(OnOff.toggle())}
}
}
}
}
Sélectionner dynamiquement des appareils avec des filtres d'entités
Lorsque vous écrivez une automatisation, vous n'êtes pas limité à la spécification d'appareils spécifiques. Une fonctionnalité appelée filtres d'entités permet à votre automatisation de sélectionner des appareils au moment de l'exécution en fonction de différents critères.
Par exemple, à l'aide de filtres d'entités, votre automatisation peut cibler :
- tous les appareils d'un type d'appareil particulier.
- tous les appareils d'une pièce spécifique
- tous les appareils d'un type d'appareil spécifique dans une pièce donnée ;
- tous les appareils allumés ;
- tous les appareils allumés dans une pièce donnée.
Pour utiliser les filtres d'entités :
- Sur
Structure
ouRoom
, appelezatExecutionTime()
. Cette opération renvoie unTypedExpression<TypedEntity<StructureType>>
. - Sur cet objet, appelez
getDevicesOfType()
en lui transmettant unDeviceType
.
Les filtres d'entités peuvent être utilisés dans les déclencheurs, les lecteurs d'état et les actions.
Par exemple, pour qu'un déclencheur lance une automatisation à partir d'un déclencheur :
// If any light is turned on or off val starter = starter( entityExpression = structure.atExecutionTime().getDevicesOfType(OnOffLightDevice), trait = OnOff, )
Pour capturer l'état OnOff
de toutes les lumières d'une structure (plus précisément, les lumières allumées/éteintes) dans un lecteur d'état :
// Build a Map<Entity, OnOff> val onOffStateOfAllLights = stateReader( entityExpression = structure.atExecutionTime().getDevicesOfType(OnOffLightDevice), trait = OnOff, )
Pour obtenir les lumières d'une pièce spécifique et les utiliser dans une condition :
val livingRoomLights = stateReader( entityExpression = livingRoom.atExecutionTime().getDevicesOfType(OnOffLightDevice), trait = OnOff, ) // Are any of the lights in the living room on? condition { expression = livingRoomLights.values.any { it.onOff equals true } }
Lors de l'exécution :
Scénario | Résultat |
---|---|
Aucun appareil ne répond aux critères d'un déclencheur. | L'automatisation ne se déclenche pas. |
Aucun appareil ne répond aux critères dans un lecteur d'état. | L'automatisation démarre, mais ne fait rien. |
Aucun appareil ne répond aux critères d'une action. | L'automatisation démarre, mais l'action ne fait rien. |
L'exemple suivant est une automatisation qui éteint toutes les lumières, sauf celle du couloir, chaque fois qu'une lumière individuelle est éteinte :
val unused = automation { sequential { // If any light is turned on or off val starter = starter( entityExpression = structure.atExecutionTime().getDevicesOfType(OnOffLightDevice), trait = OnOff, ) condition { // Check to see if the triggering light was turned off expression = starter.onOff equals false } // Turn off all lights except the hall light action( entityExpression = structure.atExecutionTime().getDevicesOfType(OnOffLightDevice).filter { it notEquals entity(hallwayLight, OnOffLightDevice) } ) { command(OnOff.on()) } } }
Exécuter une automatisation
Exécutez une automatisation créée à l'aide de la méthode execute()
:
createdAutomation.execute()
Si l'automatisation comporte un déclencheur manuel, execute()
démarre l'automatisation à partir de ce point, en ignorant tous les nœuds qui précèdent le déclencheur manuel. Si l'automatisation ne dispose pas d'un déclencheur manuel, l'exécution commence à partir du nœud suivant le premier nœud de déclencheur.
Si l'opération execute()
échoue, une HomeException
peut être générée. Consultez la section Gestion des erreurs.
Arrêter une automatisation
Arrêtez une automatisation en cours d'exécution à l'aide de la méthode stop()
:
createdAutomation.stop()
Si l'opération stop()
échoue, une HomeException
peut être générée. Consultez la section Gestion des erreurs.
Obtenir la liste des automatisations pour une structure
Les automatisations sont définies au niveau de la structure. Appuyez sur l'automations()
de la structure pour accéder à un Flow
d'automatisations :
import com.google.home.automation.Automation
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
...
val structure = homeManager.structures().list().single()
structure.automations().collect {
println("Available automations:")
for (automation in it) {
println(String.format("%S %S", "$automation.id", "$automation.name"))
}
}
Vous pouvez également l'attribuer à un Collection
local :
import com.google.home.automation.Automation
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
...
var myAutomations: Collection<Automation> = emptyList()
myAutomations = structure.automations()
Obtenir une automatisation par ID
Pour obtenir une automatisation par ID d'automatisation, appelez la méthode automations()
sur la structure et faites correspondre l'ID :
import com.google.home.automation.Automation
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
...
val structure = homeManager.structures().list().single()
val automation: DraftAutomation = structure.automations().mapNotNull {
it.firstOrNull
{ automation -> automation.id == Id("automation-id") }
}.firstOrNull()
Response:
// Here's how the automation looks like in the get response.
// Here, it's represented as if calling a println(automation.toString())
Automation(
name = "automation-name",
description = "automation-description",
isActive = true,
id = Id("automation@automation-id"),
automationGraph = SequentialFlow(
nodes = [
Starter(
entity="device@test-device",
type="home.matter.0000.types.0101",
trait="OnOff@6789..."),
Action(
entity="device@test-device",
type="home.matter.0000.types.0101",
trait="OnOff@8765...",
command="on")
]))
Obtenir une automatisation par son nom
La méthode filter()
en Kotlin peut être utilisée pour affiner davantage les appels d'API. Pour obtenir une automatisation par son nom, récupérez les automatisations de la structure et filtrez-les sur le nom de l'automatisation :
import com.google.home.automation.Automation
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
...
val structure = homeManager.structures().list().single()
val automation: DraftAutomation = structure.automations().filter {
it.name.equals("Sunset Blinds") }
Obtenir toutes les automatisations d'un appareil
Pour obtenir toutes les automatisations qui font référence à un appareil donné, utilisez le filtrage imbriqué pour analyser le automationGraph
de chaque automatisation :
import android.util.Log
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
import com.google.home.automation.Action
import com.google.home.automation.Automation
import com.google.home.automation.Automation.automationGraph
import com.google.home.automation.Node
import com.google.home.automation.ParallelFlow
import com.google.home.automation.SelectFlow
import com.google.home.automation.SequentialFlow
import com.google.home.automation.Starter
import com.google.home.automation.StateReader
...
fun collectDescendants(node: Node): List<Node> {
val d: MutableList<Node> = mutableListOf(node)
val children: List<Node> =
when (node) {
is SequentialFlow -> node.nodes
is ParallelFlow -> node.nodes
is SelectFlow -> node.nodes
else -> emptyList()
}
for (c in children) {
d += collectDescendants(c)
}
return d
}
val myDeviceId = "device@452f78ce8-0143-84a-7e32-1d99ab54c83a"
val structure = homeManager.structures().list().single()
val automations =
structure.automations().first().filter {
automation: Automation ->
collectDescendants(automation.automationGraph!!).any { node: Node ->
when (node) {
is Starter -> node.entity.id.id == myDeviceId
is StateReader -> node.entity.id.id == myDeviceId
is Action -> node.entity.id.id == myDeviceId
else -> false
}
}
}
Modifier une automatisation
Pour mettre à jour les métadonnées d'une automatisation, appelez sa méthode update()
en lui transmettant une expression lambda qui définit les métadonnées :
import com.google.home.automation.Automation
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
...
val structure = homeManager.structures().list().single()
val automation: DraftAutomation = structure.automations().mapNotNull {
it.firstOrNull
{ automation -> automation.id == Id("automation-id") }
}.firstOrNull()
automation.update { this.name = "Flashing lights 2" }
La méthode update()
permet de remplacer complètement un graphique d'automatisation, mais pas de modifier chaque nœud du graphique. La modification par nœud est sujette aux erreurs en raison des interdépendances entre les nœuds. Si vous souhaitez modifier la logique d'une automatisation, générez un nouveau graphique et remplacez complètement celui existant.
import com.google.home.automation.Automation
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
...
val structure = homeManager.structures().list().single()
val automation: Automation = structure.automations().mapNotNull {
it.firstOrNull
{ automation -> automation.id == Id("automation-id") }
}.firstOrNull()
automation.update {
this.automationGraph = sequential {
val laundryWasherCompletionEvent =
starter<_>(laundryWasher, LaundryWasherDevice, OperationCompletionEvent)
condition {
expression =
laundryWasherCompletionEvent.completionErrorCode equals
// UByte 0x00u means NoError
0x00u
}
action(speaker, SpeakerDevice) { command(AssistantBroadcast.broadcast("laundry is done")) }
}
}
}
Supprimer une automatisation
Pour supprimer une automatisation, utilisez la méthode deleteAutomation()
de la structure. Une automatisation doit être supprimée à l'aide de son ID.
import com.google.home.automation.Automation
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.HomeManager
import com.google.home.Id
import com.google.home.Structure
...
val structure = homeManager.structures().list().single()
val automation: DraftAutomation = structure.automations().first()
structure.deleteAutomation(automation.id)
Si la suppression échoue, une HomeException
peut être générée. Consultez la section Gestion des erreurs.
Impact de la suppression d'un appareil sur les automatisations
Si un utilisateur supprime un appareil utilisé dans une automatisation, l'appareil supprimé ne peut plus déclencher de démarreurs, et l'automatisation ne peut plus lire ses attributs ni lui envoyer de commandes. Par exemple, si un utilisateur supprime un OccupancySensorDevice
de sa maison et qu'une automatisation comporte un déclencheur qui dépend du OccupancySensorDevice
, ce déclencheur ne peut plus activer l'automatisation.