Auf die Automation APIs kann über die Home APIs für Android zugegriffen werden. Da der Einstiegspunkt jedoch über eine Struktur erfolgt, muss zuerst die Berechtigung für die Struktur erteilt werden, bevor sie verwendet werden können.
Nachdem Berechtigungen für eine Struktur erteilt wurden, importieren Sie diese Pakete in Ihre App:
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id
import com.google.home.Structure
Eine Struktur enthält eine HasAutomations
-Schnittstelle mit den folgenden automatisierungsspezifischen Methoden:
API | Beschreibung |
---|---|
automations() |
Alle automatisierten Abläufe auflisten, die zum Zuhause gehören. Es werden nur Automatisierungen zurückgegeben, die Sie über die Home APIs erstellt haben. |
createAutomation(automation) |
Automatisierungsinstanz für ein Gebäude erstellen |
deleteAutomation(automationId) |
Löschen Sie eine automatisierte Instanz anhand ihrer ID. |
Automatisierung erstellen
Nachdem Sie eine Instanz von „Zuhause“ erstellt und Berechtigungen vom Nutzer erhalten haben, rufen Sie die Struktur und das/die Gerät(e) ab:
val structure = homeManager.structures().list().single()
val device = homeManager.devices().get(Id("myDevice"))!!
Definieren Sie dann die Logik Ihrer Automatisierung mit Automation DSL. In den Home APIs wird eine Automatisierung durch die Schnittstelle Automation
dargestellt. Diese Schnittstelle enthält eine Reihe von Eigenschaften:
- Metadaten wie Name und Beschreibung.
- Flags, die beispielsweise angeben, ob die Automatisierung ausgeführt werden kann.
- Eine Liste von Knoten, die die Logik der Automatisierung enthalten, als Automatisierungsgrafik bezeichnet und durch die
automationGraph
-Property dargestellt.
automationGraph
ist standardmäßig vom Typ SequentialFlow
. Das ist eine Klasse, die eine Liste von Knoten enthält, die in sequenzieller Reihenfolge ausgeführt werden. Jeder Knoten stellt ein Element der Automatisierung dar, z. B. einen Starter, eine Bedingung oder eine Aktion.
Weisen Sie der Automatisierung eine name
und eine description
zu.
Beim Erstellen einer Automatisierung wird das Flag isActive
standardmäßig auf true
gesetzt. Es ist daher nicht erforderlich, dieses Flag explizit festzulegen, es sei denn, die Automatisierung soll anfangs deaktiviert sein. Legen Sie in diesem Fall das Flag bei der Erstellung auf false
fest.
Die DraftAutomation
-Schnittstelle wird zum Erstellen und Erstellen von Automatisierungen verwendet und die Automation
-Schnittstelle zum Abrufen. Hier ist beispielsweise die Automation DSL für eine Automation, die ein Gerät einschaltet, wenn ein anderes Gerät eingeschaltet wird:
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()) }
}
}
Sobald die Automatisierungs-DSL definiert ist, übergeben Sie sie an die Methode createAutomation()
, um die DraftAutomation
-Instanz zu erstellen:
val createdAutomation = structure.createAutomation(automation)
Von hier aus können Sie alle anderen Automatisierungsmethoden für die Automatisierung verwenden, z. B. execute()
, stop()
und update()
.
Validierungsfehler
Wenn die Erstellung der Automatisierung die Validierung nicht besteht, wird eine Warnung oder Fehlermeldung mit Informationen zum Problem angezeigt. Weitere Informationen finden Sie in der Referenz zu ValidationIssueType
.
Codebeispiele
Hier finden Sie Beispielcode, mit dem sich Teile der hypothetischen Automatisierungen implementieren lassen, die auf der Seite Automatisierung für Android entwerfen beschrieben werden.
Einfache Automatisierung
Eine Automatisierung, die die Jalousien um 8:00 Uhr hochfährt, könnte so implementiert werden:
// 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.
}
Komplexe Automatisierung
Eine Automatisierung, die blinkende Lichter auslöst, wenn eine Bewegung erkannt wird, könnte so implementiert werden:
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())}
}
}
}
}
Geräte mit Entitätsfiltern dynamisch auswählen
Beim Erstellen einer Automatisierung müssen Sie nicht unbedingt bestimmte Geräte angeben. Mit einer Funktion namens Entitätsfilter können Geräte in Ihrer Automatisierung zur Laufzeit anhand verschiedener Kriterien ausgewählt werden.
Mit Entitätsfiltern können Sie Ihre Automatisierung beispielsweise auf Folgendes ausrichten:
- alle Geräte eines bestimmten Gerätetyps
- alle Geräte in einem bestimmten Raum
- alle Geräte eines bestimmten Gerätetyps in einem bestimmten Raum
- alle eingeschalteten Geräte
- Alle Geräte, die in einem bestimmten Raum eingeschaltet sind
So verwenden Sie Einheitenfilter:
- Rufen Sie
atExecutionTime()
entweder inStructure
oder inRoom
auf. Dadurch wird eineTypedExpression<TypedEntity<StructureType>>
zurückgegeben. - Rufen Sie für dieses Objekt
getDevicesOfType()
auf und übergeben Sie einDeviceType
.
Entitätsfilter können in Auslösern, Statuslesern und Aktionen verwendet werden.
Wenn beispielsweise eine beliebige Ein/Aus-Lampe eine Automatisierung über einen Auslöser auslösen soll:
// If any light is turned on or off val starter = starter( entityExpression = structure.atExecutionTime().getDevicesOfType(OnOffLightDevice), trait = OnOff, )
So erfassen Sie den OnOff
-Status aller Lichter in einem Gebäude (insbesondere Ein-/Aus-Lichter) in einem Statusleser:
// Build a Map<Entity, OnOff> val onOffStateOfAllLights = stateReader( entityExpression = structure.atExecutionTime().getDevicesOfType(OnOffLightDevice), trait = OnOff, )
So rufen Sie die Beleuchtung in einem bestimmten Raum ab und verwenden sie in einer Bedingung:
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 } }
Zur Laufzeit:
Szenario | Ergebnis |
---|---|
Kein Gerät erfüllt die Kriterien in einem Auslöser. | Die Automatisierung wird nicht ausgelöst. |
Keine Geräte entsprechen den Kriterien in einem Statusleser. | Die Automatisierung wird gestartet, es passiert aber nichts. |
Keine Geräte erfüllen die Kriterien in einer Aktion. | Die Automatisierung wird gestartet, aber die Aktion führt zu keiner Änderung. |
Im folgenden Beispiel wird eine Automatisierung gezeigt, die alle Lampen außer der Flurlampe ausschaltet, wenn eine einzelne Lampe ausgeschaltet wird:
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()) } } }
Automatisierung ausführen
So führen Sie eine erstellte Automatisierung mit der Methode execute()
aus:
createdAutomation.execute()
Wenn die Automatisierung einen manuellen Auslöser hat, startet execute()
die Automatisierung ab diesem Punkt und ignoriert alle Knoten, die dem manuellen Auslöser vorangestellt sind. Wenn die Automatisierung keinen manuellen Starter hat, beginnt die Ausführung mit dem Knoten, der auf den ersten Starterknoten folgt.
Wenn der Vorgang execute()
fehlschlägt, wird möglicherweise eine HomeException
ausgelöst. Weitere Informationen finden Sie unter Fehlerbehandlung.
Automatisierung beenden
So beenden Sie eine laufende Automatisierung mit der Methode stop()
:
createdAutomation.stop()
Wenn der Vorgang stop()
fehlschlägt, wird möglicherweise eine HomeException
ausgelöst. Weitere Informationen finden Sie unter Fehlerbehandlung.
Liste der Automatisierungen für ein Gebäude abrufen
Automatisierungen werden auf Gebäudeebene definiert. Greifen Sie über die automations()
der Struktur auf eine Flow
von Automatisierungen zu:
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"))
}
}
Alternativ können Sie sie einer lokalen Collection
zuweisen:
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()
Automatisierung nach ID abrufen
Wenn Sie eine Automation anhand der Automation-ID abrufen möchten, rufen Sie die Methode automations()
für die Struktur auf und gleichen Sie die ID ab:
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")
]))
Automatisierung anhand des Namens abrufen
Mit der Methode filter()
in Kotlin können API-Aufrufe weiter optimiert werden. Wenn Sie eine Automatisierung anhand des Namens abrufen möchten, rufen Sie die Automatisierungen der Struktur ab und filtern Sie nach dem Namen der Automatisierung:
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") }
Alle Automatisierungen für ein Gerät abrufen
Wenn Sie alle automatisierten Abläufe abrufen möchten, die auf ein bestimmtes Gerät verweisen, verwenden Sie die geschachtelte Filterung, um die automationGraph
der einzelnen automatisierten Abläufe zu scannen:
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
}
}
}
Automatisierung aktualisieren
Rufen Sie die Methode update()
der Automatisierung auf und übergeben Sie ihr einen Lambda-Ausdruck, der die Metadaten festlegt, um die Metadaten einer Automatisierung zu aktualisieren:
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" }
Mit der Methode update()
kann ein Automatisierungsdiagramm vollständig ersetzt werden, aber nicht knotenweise bearbeitet werden. Die Bearbeitung einzelner Knoten ist aufgrund der Abhängigkeiten zwischen den Knoten fehleranfällig. Wenn Sie die Logik einer Automatisierung ändern möchten, generieren Sie ein neues Diagramm und ersetzen Sie das vorhandene vollständig.
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")) }
}
}
}
Automatisierung löschen
Verwenden Sie zum Löschen einer Automatisierung die Methode deleteAutomation()
des Gebäudes. Eine Automatisierung muss anhand ihrer ID gelöscht werden.
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)
Wenn das Löschen fehlschlägt, wird möglicherweise eine HomeException
ausgelöst. Weitere Informationen finden Sie unter Fehlerbehandlung.
Auswirkungen des Löschens von Geräten auf Automatisierungen
Wenn ein Nutzer ein Gerät löscht, das in einer Automatisierung verwendet wird, kann das gelöschte Gerät keine Starter auslösen und die Automatisierung kann keine Attribute davon lesen oder Befehle an das Gerät senden. Wenn ein Nutzer beispielsweise ein OccupancySensorDevice
aus seinem Zuhause löscht und eine Automatisierung einen Auslöser hat, der vom OccupancySensorDevice
abhängt, kann dieser Auslöser die Automatisierung nicht mehr aktivieren.