Automation API dapat diakses melalui Home API untuk Android, tetapi karena titik masuknya melalui struktur, izin harus diberikan terlebih dahulu pada struktur sebelum dapat digunakan.
Setelah izin diberikan untuk struktur, impor paket ini ke aplikasi Anda:
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id
import com.google.home.Structure
Struktur berisi antarmuka
HasAutomations
dengan metode khusus otomatisasi berikut:
| API | Deskripsi |
|---|---|
automations() |
Mencantumkan semua otomatisasi yang termasuk dalam struktur. Hanya otomatisasi yang Anda buat melalui Home API yang ditampilkan. |
createAutomation(automation) |
Buat instance otomatisasi untuk struktur. |
deleteAutomation(automationId) |
Menghapus instance otomatisasi berdasarkan ID-nya. |
Membuat otomatisasi
Setelah membuat instance Home dan menerima izin dari pengguna, dapatkan struktur dan perangkat:
val structure = homeManager.structures().list().single()
val device = homeManager.devices().get(Id("myDevice"))!!
Kemudian, tentukan logika otomatisasi Anda menggunakan DSL Otomatisasi. Di Home API,
otomatisasi diwakili oleh antarmuka Automation. Antarmuka ini
berisi serangkaian properti:
- Metadata, seperti nama dan deskripsi.
- Flag yang menunjukkan, misalnya, apakah otomatisasi dapat dieksekusi atau tidak.
- Daftar node yang berisi logika otomatisasi, yang disebut grafik otomatisasi, yang diwakili oleh properti
automationGraph.
automationGraph, secara default, berjenis SequentialFlow, yang merupakan class
yang berisi daftar node yang dieksekusi dalam urutan beruntun. Setiap node
mewakili elemen otomatisasi, seperti pemicu, kondisi, atau
tindakan.
Tetapkan name dan description untuk otomatisasi.
Pembuatan otomatisasi secara default menetapkan flag isActive ke true, sehingga
tidak perlu menetapkan flag ini secara eksplisit kecuali jika Anda awalnya ingin
menonaktifkan otomatisasi. Dalam skenario tersebut, tetapkan tanda ke false selama
pembuatan.
Antarmuka DraftAutomation digunakan untuk membangun dan membuat otomatisasi,
dan antarmuka Automation digunakan untuk pengambilan. Misalnya, berikut adalah
DSL Otomatisasi untuk otomatisasi yang mengaktifkan perangkat saat perangkat lain
diaktifkan:
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()) }
}
}
Setelah DSL otomatisasi ditentukan, teruskan ke metode
createAutomation()
untuk membuat instance DraftAutomation:
val createdAutomation = structure.createAutomation(automation)
Dari sini, Anda dapat menggunakan semua metode otomatisasi lainnya pada otomatisasi, seperti execute(), stop(), dan update().
Error validasi
Jika pembuatan otomatisasi tidak lulus validasi, pesan peringatan atau error
akan memberikan informasi tentang masalah tersebut. Untuk mengetahui informasi selengkapnya, lihat
referensi ValidationIssueType.
Meskipun createAutomation() selesai tanpa menampilkan pengecualian, otomatisasi yang dibuat mungkin tidak valid atau dapat dieksekusi. Backend memungkinkan penyimpanan draf otomatisasi yang tidak valid (misalnya, jika pengguna belum memberikan izin yang diperlukan seperti deteksi Wajah yang Dikenali, atau jika kemampuan perangkat tidak ada).
Anda harus selalu memverifikasi isValid dan memeriksa validationIssues pada instance
Automation yang ditampilkan:
val createdAutomation = structure.createAutomation(automation)
if (!createdAutomation.isValid) {
// Iterate through validation issues to identify errors and warnings
for (issue in createdAutomation.validationIssues) {
when (issue.severity) {
ValidationIssueSeverity.ERROR -> {
Log.e(
"Automation",
"Validation error on node ${issue.node}: ${issue.issueType}"
)
// Handle error (for example, prompt the user to enable missing
// consents or device features)
}
ValidationIssueSeverity.WARNING -> {
Log.w(
"Automation",
"Validation warning on node ${issue.node}: ${issue.issueType}"
)
}
else -> {}
}
}
}
Contoh kode
Di sini kami menyajikan beberapa contoh kode yang dapat digunakan untuk menerapkan bagian dari otomatisasi hipotetis yang dijelaskan di halaman Mendesain otomatisasi di Android.
Otomatisasi sederhana
Otomatisasi yang menaikkan tirai pada pukul 08.00 dapat diterapkan seperti ini:
// 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.
}
Otomatisasi kompleks
Otomatisasi yang memicu lampu berkedip saat gerakan terdeteksi dapat diterapkan seperti ini:
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())}
}
}
}
}
Memilih perangkat secara dinamis dengan filter entitas
Saat menulis otomatisasi, Anda tidak terbatas pada penentuan perangkat tertentu. Fitur yang disebut filter entitas memungkinkan otomatisasi Anda memilih perangkat saat runtime berdasarkan berbagai kriteria.
Misalnya, menggunakan filter entitas, otomatisasi Anda dapat menargetkan:
- semua perangkat dari jenis perangkat tertentu
- semua perangkat di ruangan tertentu
- semua perangkat dari jenis perangkat tertentu di ruangan tertentu
- semua perangkat yang diaktifkan
- semua perangkat yang diaktifkan di ruangan tertentu
Untuk menggunakan filter entitas:
- Di
StructureatauRoom, panggilatExecutionTime(). Tindakan ini akan menampilkanTypedExpression<TypedEntity<StructureType>>. - Pada objek ini, panggil
getDevicesOfType(), dengan meneruskanDeviceType.
Filter entitas dapat digunakan dalam pemicu, pembaca status, dan tindakan.
Misalnya, agar Lampu On/Off memicu otomatisasi dari pemicu:
// If any light is turned on or off val starter = starter( entityExpression = structure.atExecutionTime().getDevicesOfType(OnOffLightDevice), trait = OnOff, )
Untuk merekam status OnOff semua lampu dalam struktur (khususnya,
lampu Aktif/Nonaktif) dalam pembaca status:
// Build a Map<Entity, OnOff> val onOffStateOfAllLights = stateReader( entityExpression = structure.atExecutionTime().getDevicesOfType(OnOffLightDevice), trait = OnOff, )
Untuk mendapatkan lampu di ruangan tertentu dan menggunakannya dalam kondisi:
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 } }
Saat runtime:
| Skenario | Hasil |
|---|---|
| Tidak ada perangkat yang memenuhi kriteria dalam starter. | Otomatisasi tidak dipicu. |
| Tidak ada perangkat yang memenuhi kriteria di pembaca status. | Otomatisasi dimulai, tetapi akan berlanjut berdasarkan node kondisi. |
| Tidak ada perangkat yang memenuhi kriteria dalam tindakan. | Otomatisasi dimulai, tetapi tindakan tidak melakukan apa pun. |
Contoh berikut adalah otomatisasi yang mematikan semua lampu kecuali lampu lorong setiap kali satu lampu dimatikan:
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()) } } }
Menjalankan otomatisasi
Jalankan otomatisasi yang dibuat menggunakan metode
execute():
createdAutomation.execute()
Jika otomatisasi memiliki
pemicu manual, execute()
akan memulai otomatisasi dari titik tersebut, dengan mengabaikan semua node yang mendahului
pemicu manual. Jika otomatisasi tidak memiliki pemicu manual, eksekusi
dimulai dari node setelah node pemicu pertama.
Jika operasi execute() gagal, HomeException dapat ditampilkan. Lihat Penanganan error.
Menghentikan otomatisasi
Hentikan otomatisasi yang sedang berjalan menggunakan metode stop():
createdAutomation.stop()
Jika operasi stop() gagal, HomeException dapat ditampilkan. Lihat Penanganan error.
Mendapatkan daftar otomatisasi untuk struktur
Otomatisasi ditentukan di tingkat struktur. Kumpulkan di struktur
automations()
untuk mengakses Flow otomatisasi:
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"))
}
}
Atau, tetapkan ke Collection lokal:
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()
Mendapatkan otomatisasi menurut ID
Untuk mendapatkan otomatisasi menurut ID otomatisasi, panggil metode
automations()
pada struktur, dan cocokkan 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()
Respons:
// 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")
]))
Mendapatkan otomatisasi berdasarkan nama
Metode
filter()
di Kotlin dapat digunakan untuk menyaring panggilan API lebih lanjut. Untuk mendapatkan otomatisasi
berdasarkan nama, dapatkan otomatisasi struktur dan filter berdasarkan nama otomatisasi:
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") }
Mendapatkan semua otomatisasi untuk perangkat
Untuk mendapatkan semua otomatisasi yang mereferensikan perangkat tertentu, gunakan pemfilteran bertingkat
untuk memindai automationGraph setiap otomatisasi:
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
}
}
}
Memperbarui otomatisasi
Untuk memperbarui metadata otomatisasi, panggil metode
update()
miliknya, dengan meneruskan ekspresi lambda yang menetapkan metadata:
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" }
Metode update()
mendukung penggantian grafik otomatisasi sepenuhnya, tetapi tidak mendukung pengeditan per-node pada
grafik. Pengeditan per-node rentan terhadap error karena saling ketergantungan node. Jika
Anda ingin mengubah logika otomatisasi, buat grafik baru dan ganti sepenuhnya grafik yang ada.
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")) }
}
}
}
Menghapus otomatisasi
Untuk menghapus otomatisasi, gunakan metode
deleteAutomation()
struktur. Otomatisasi harus dihapus menggunakan ID-nya.
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)
Jika penghapusan gagal, HomeException dapat ditampilkan. Lihat Penanganan error.
Dampak penghapusan perangkat pada otomatisasi
Jika pengguna menghapus perangkat yang digunakan dalam otomatisasi, perangkat yang dihapus tidak dapat memicu pemicu apa pun, dan otomatisasi tidak akan dapat membaca atribut darinya, atau mengeluarkan perintah ke perangkat tersebut. Misalnya, jika pengguna menghapus
OccupancySensorDevice
dari rumahnya, dan otomatisasi memiliki pemicu yang bergantung pada
OccupancySensorDevice, pemicu tersebut tidak dapat lagi mengaktifkan otomatisasi.