คุณสามารถเข้าถึง Automation API ผ่าน Home API สำหรับ Android ได้ แต่เนื่องจากจุดแรกเข้าของ API เหล่านี้คือผ่านโครงสร้าง จึงต้องให้สิทธิ์ในโครงสร้างก่อนจึงจะใช้งานได้
เมื่อได้รับสิทธิ์สำหรับโครงสร้างแล้ว ให้นำเข้าแพ็กเกจเหล่านี้ไปยังแอปของคุณ
import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id
import com.google.home.Structure
โครงสร้างประกอบด้วยอินเทอร์เฟซ HasAutomations ที่มีเมธอดเฉพาะสำหรับการทำงานอัตโนมัติต่อไปนี้
| API | คำอธิบาย |
|---|---|
automations() |
แสดงรายการการทำงานอัตโนมัติทั้งหมดที่อยู่ในบ้าน ระบบจะแสดงเฉพาะการทำงานอัตโนมัติที่คุณสร้างผ่าน Home API เท่านั้น |
createAutomation(automation) |
สร้างอินสแตนซ์การทำงานอัตโนมัติสำหรับบ้าน |
deleteAutomation(automationId) |
ลบอินสแตนซ์การทำงานอัตโนมัติตามรหัส |
สร้างการทำงานอัตโนมัติ
หลังจากสร้างอินสแตนซ์ของ Home และได้รับสิทธิ์จากผู้ใช้แล้ว ให้รับโครงสร้างและอุปกรณ์โดยทำดังนี้
val structure = homeManager.structures().list().single()
val device = homeManager.devices().get(Id("myDevice"))!!
จากนั้นกำหนดตรรกะของการทำงานอัตโนมัติโดยใช้ DSL ของการทำงานอัตโนมัติ ใน Home API การทำงานอัตโนมัติจะแสดงด้วยอินเทอร์เฟซ Automation อินเทอร์เฟซนี้ประกอบด้วยชุดพร็อพเพอร์ตี้ต่อไปนี้
- ข้อมูลเมตา เช่น ชื่อและคำอธิบาย
- แฟล็กที่ระบุ เช่น การทำงานอัตโนมัติจะดำเนินการได้หรือไม่
- รายการโหนดที่มีตรรกะของการทำงานอัตโนมัติ ซึ่งเรียกว่ากราฟการทำงานอัตโนมัติ โดยแสดงด้วยพร็อพเพอร์ตี้
automationGraph
โดยค่าเริ่มต้น automationGraph จะเป็นประเภท SequentialFlow ซึ่งเป็นคลาสที่มีรายการโหนดที่ดำเนินการตามลำดับ แต่ละโหนดแสดงถึงองค์ประกอบของการทำงานอัตโนมัติ เช่น เงื่อนไขเริ่มต้น เงื่อนไข หรือการดำเนินการ
กำหนดnameและdescriptionให้กับการทำงานอัตโนมัติ
การสร้างการทำงานอัตโนมัติจะตั้งค่าแฟล็ก isActive เป็น true โดยค่าเริ่มต้น คุณจึงไม่จำเป็นต้องตั้งค่าแฟล็กนี้อย่างชัดเจน เว้นแต่คุณต้องการปิดใช้การทำงานอัตโนมัติในตอนแรก ในกรณีนี้ ให้ตั้งค่าแฟล็กเป็น false ระหว่างการสร้าง
อินเทอร์เฟซ DraftAutomation ใช้สำหรับการสร้างและสร้างการทำงานอัตโนมัติ
และอินเทอร์เฟซ Automation ใช้สำหรับการดึงข้อมูล ตัวอย่างเช่น DSL ของการทำงานอัตโนมัติสำหรับการทำงานอัตโนมัติที่เปิดอุปกรณ์เมื่อมีการเปิดอุปกรณ์อีกเครื่องหนึ่งมีดังนี้
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()) }
}
}
เมื่อกำหนด DSL ของการทำงานอัตโนมัติแล้ว ให้ส่งไปยังเมธอด createAutomation() เพื่อสร้างอินสแตนซ์ DraftAutomation ดังนี้
val createdAutomation = structure.createAutomation(automation)
จากตรงนี้ คุณจะใช้วิธีการทำงานอัตโนมัติอื่นๆ ทั้งหมดกับการทำงานอัตโนมัติได้ เช่น execute(), stop() และ update()
ข้อผิดพลาดเกี่ยวกับการตรวจสอบความถูกต้อง
หากการสร้างการทำงานอัตโนมัติไม่ผ่านการตรวจสอบ คำเตือนหรือข้อความแสดงข้อผิดพลาดจะให้ข้อมูลเกี่ยวกับปัญหา ดูข้อมูลเพิ่มเติมได้ที่ข้อมูลอ้างอิง ValidationIssueType
แม้ว่า createAutomation() จะเสร็จสมบูรณ์โดยไม่มีการแสดงข้อยกเว้น แต่การทำงานอัตโนมัติที่สร้างขึ้นอาจไม่ถูกต้องหรือเรียกใช้ไม่ได้ แบ็กเอนด์อนุญาตให้บันทึกฉบับร่างการทำงานอัตโนมัติที่ไม่ถูกต้อง (เช่น หากผู้ใช้ไม่ได้ให้ความยินยอมที่จำเป็น เช่น การตรวจจับใบหน้าที่คุ้นเคย หรือหากไม่มีความสามารถของอุปกรณ์)
คุณควรตรวจสอบ isValid และ validationIssues ในอินสแตนซ์ Automation ที่แสดงผลเสมอ
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 -> {}
}
}
}
ตัวอย่างโค้ด
ในที่นี้ เราจะแสดงโค้ดตัวอย่างที่สามารถใช้เพื่อติดตั้งใช้งานส่วนต่างๆ ของการทำงานอัตโนมัติสมมติที่อธิบายไว้ในหน้าออกแบบการทำงานอัตโนมัติใน Android
การทำงานอัตโนมัติแบบง่าย
การทำงานอัตโนมัติที่เปิดม่านตอน 8:00 น. อาจใช้โค้ดดังนี้
// 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.
}
การทำงานอัตโนมัติที่ซับซ้อน
การทำงานอัตโนมัติที่ทริกเกอร์ไฟกะพริบเมื่อตรวจพบการเคลื่อนไหวอาจใช้โค้ดดังนี้
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())}
}
}
}
}
เลือกอุปกรณ์แบบไดนามิกด้วยตัวกรองเอนทิตี
เมื่อเขียนการทำงานอัตโนมัติ คุณไม่จำเป็นต้องระบุอุปกรณ์ที่เจาะจงเท่านั้น ฟีเจอร์ที่เรียกว่าตัวกรองเอนทิตีช่วยให้การทำงานอัตโนมัติเลือกอุปกรณ์ที่รันไทม์ตามเกณฑ์ต่างๆ ได้
ตัวอย่างเช่น การใช้ตัวกรองเอนทิตีจะช่วยให้การทำงานอัตโนมัติกำหนดเป้าหมายต่อไปนี้ได้
- อุปกรณ์ทั้งหมดของอุปกรณ์ประเภทหนึ่งๆ
- อุปกรณ์ทั้งหมดในห้องที่ต้องการ
- อุปกรณ์ทั้งหมดของอุปกรณ์ประเภทหนึ่งๆ ในห้องหนึ่งๆ
- อุปกรณ์ทั้งหมดที่เปิดอยู่
- อุปกรณ์ทั้งหมดที่เปิดอยู่ในห้องหนึ่งๆ
วิธีใช้ตัวกรองเอนทิตี
- โทรหา
atExecutionTime()ในStructureหรือRoomซึ่งจะแสดงผลเป็นTypedExpression<TypedEntity<StructureType>> - ในออบเจ็กต์นี้ ให้เรียกใช้
getDevicesOfType()โดยส่งDeviceTypeไปด้วย
ตัวกรองเอนทิตีอาจใช้ในเงื่อนไขเริ่มต้น ตัวอ่านสถานะ และการดำเนินการ
ตัวอย่างเช่น หากต้องการให้ไฟเปิด/ปิดทริกเกอร์การทำงานอัตโนมัติจากเงื่อนไขเริ่มต้น ให้ทำดังนี้
// If any light is turned on or off val starter = starter( entityExpression = structure.atExecutionTime().getDevicesOfType(OnOffLightDevice), trait = OnOff, )
วิธีบันทึกสถานะ OnOff ของไฟทั้งหมดในบ้าน (โดยเฉพาะไฟเปิด/ปิด) ในโปรแกรมอ่านสถานะ
// Build a Map<Entity, OnOff> val onOffStateOfAllLights = stateReader( entityExpression = structure.atExecutionTime().getDevicesOfType(OnOffLightDevice), trait = OnOff, )
วิธีรับข้อมูลหลอดไฟในห้องที่เฉพาะเจาะจงและใช้ในเงื่อนไข
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 } }
เมื่อรันไทม์:
| สถานการณ์ | ผลลัพธ์ |
|---|---|
| ไม่มีอุปกรณ์ที่ตรงตามเกณฑ์ในเงื่อนไขเริ่มต้น | การทำงานอัตโนมัติไม่ทริกเกอร์ |
| ไม่มีอุปกรณ์ที่ตรงตามเกณฑ์ในเครื่องอ่านสถานะ | การทำงานอัตโนมัติจะเริ่มขึ้น แต่จะทำงานต่อไปตามโหนดเงื่อนไข |
| ไม่มีอุปกรณ์ที่ตรงตามเกณฑ์ในการดำเนินการ | การทำงานอัตโนมัติเริ่มต้นขึ้น แต่ไม่มีการดำเนินการใดๆ |
ตัวอย่างต่อไปนี้คือการทำงานอัตโนมัติที่จะปิดไฟทุกดวงยกเว้นไฟในห้องโถงเมื่อใดก็ตามที่มีการปิดไฟดวงใดดวงหนึ่ง
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()) } } }
เรียกใช้การทำงานอัตโนมัติ
เรียกใช้การทำงานอัตโนมัติที่สร้างขึ้นโดยใช้เมธอด execute() ดังนี้
createdAutomation.execute()
หากการทำงานอัตโนมัติมีเงื่อนไขเริ่มต้นด้วยตนเอง execute() จะเริ่มการทำงานอัตโนมัติจากจุดนั้น โดยไม่สนใจโหนดทั้งหมดที่อยู่ก่อนเงื่อนไขเริ่มต้นด้วยตนเอง หากการทำงานอัตโนมัติไม่มีเงื่อนไขเริ่มต้นด้วยตนเอง การดำเนินการจะเริ่มจากโหนดที่อยู่ถัดจากโหนดเงื่อนไขเริ่มต้นแรก
หากการดำเนินการ execute() ล้มเหลว ระบบอาจแสดง HomeException ดูการจัดการข้อผิดพลาด
หยุดการทำงานอัตโนมัติ
หยุดการทำงานอัตโนมัติที่กำลังทำงานอยู่โดยใช้วิธี stop()
createdAutomation.stop()
หากการดำเนินการ stop() ล้มเหลว ระบบอาจแสดง HomeException ดูการจัดการข้อผิดพลาด
ดูรายการการทำงานอัตโนมัติสำหรับบ้าน
ระบบจะกำหนดการทำงานอัตโนมัติที่ระดับบ้าน สะสมautomations()ในโครงสร้างเพื่อเข้าถึงFlowของการทำงานอัตโนมัติ
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"))
}
}
หรือจะกำหนดให้กับ Collection ในเครื่องก็ได้ โดยทำดังนี้
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()
ดูการทำงานอัตโนมัติตามรหัส
หากต้องการรับการทำงานอัตโนมัติด้วยรหัสการทำงานอัตโนมัติ ให้เรียกใช้เมธอด
automations()
ในบ้าน และจับคู่กับรหัส ดังนี้
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()
คำตอบ:
// 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")
]))
รับการทำงานอัตโนมัติตามชื่อ
คุณสามารถใช้เมธอด filter() ใน Kotlin เพื่อปรับแต่งการเรียก API เพิ่มเติมได้ หากต้องการรับการทำงานอัตโนมัติด้วยชื่อ ให้รับการทำงานอัตโนมัติของบ้านและกรองตามชื่อการทำงานอัตโนมัติ ดังนี้
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") }
ดูการทำงานอัตโนมัติทั้งหมดสำหรับอุปกรณ์
หากต้องการดูการทำงานอัตโนมัติทั้งหมดที่อ้างอิงอุปกรณ์หนึ่งๆ ให้ใช้การกรองที่ซ้อนกันเพื่อสแกน automationGraph ของการทำงานอัตโนมัติแต่ละรายการ ดังนี้
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
}
}
}
อัปเดตการทำงานอัตโนมัติ
หากต้องการอัปเดตข้อมูลเมตาของการทำงานอัตโนมัติ ให้เรียกใช้เมธอด update() โดยส่งนิพจน์ Lambda ที่ตั้งค่าข้อมูลเมตา ดังนี้
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" }
เมธอด update() รองรับการแทนที่กราฟการทำงานอัตโนมัติทั้งหมด แต่ไม่รองรับการแก้ไขกราฟต่อโหนด การแก้ไขต่อโหนดมีแนวโน้มที่จะเกิดข้อผิดพลาดเนื่องจากการพึ่งพาซึ่งกันและกันของโหนด หากต้องการเปลี่ยนตรรกะของการทำงานอัตโนมัติ ให้สร้างกราฟใหม่และแทนที่กราฟที่มีอยู่ทั้งหมด
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")) }
}
}
}
ลบการทำงานอัตโนมัติ
หากต้องการลบการทำงานอัตโนมัติ ให้ใช้เมธอด deleteAutomation() ของบ้าน คุณต้องลบการทำงานอัตโนมัติโดยใช้รหัสของการทำงานอัตโนมัตินั้น
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)
หากลบไม่สำเร็จ ระบบอาจแสดง HomeException ดูการจัดการข้อผิดพลาด
ผลกระทบของการลบอุปกรณ์ที่มีต่อการทำงานอัตโนมัติ
หากผู้ใช้ลบอุปกรณ์ที่ใช้ในการทำงานอัตโนมัติ อุปกรณ์ที่ลบไปจะไม่สามารถทริกเกอร์เงื่อนไขเริ่มต้นใดๆ ได้ และการทำงานอัตโนมัติจะอ่านแอตทริบิวต์จากอุปกรณ์หรือส่งคำสั่งไปยังอุปกรณ์ไม่ได้ ตัวอย่างเช่น หากผู้ใช้ลบ OccupancySensorDevice ออกจากบ้าน และการทำงานอัตโนมัติมีเงื่อนไขเริ่มต้นที่ขึ้นอยู่กับ OccupancySensorDevice เงื่อนไขเริ่มต้นนั้นจะเปิดใช้งานการทำงานอัตโนมัติไม่ได้อีกต่อไป