คุณเข้าถึง 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"))!!
จากนั้นกำหนดตรรกะของการทำงานอัตโนมัติโดยใช้ Automation DSL ใน Home API การทำงานอัตโนมัติจะแสดงด้วยอินเทอร์เฟซ Automation อินเทอร์เฟซนี้มีชุดพร็อพเพอร์ตี้ดังนี้
- ข้อมูลเมตา เช่น ชื่อและคำอธิบาย
- แฟล็กที่ระบุ เช่น การทำงานอัตโนมัติสามารถดำเนินการได้หรือไม่
- รายการโหนดที่มีตรรกะของการทำงานอัตโนมัติ ซึ่งเรียกว่ากราฟการทำงานอัตโนมัติ โดยแสดงด้วยพร็อพเพอร์ตี้
automationGraph
automationGraphมีประเภทเป็น SequentialFlow โดยค่าเริ่มต้น ซึ่งเป็นคลาสที่มีรายการโหนดที่ดำเนินการตามลำดับ แต่ละโหนดแสดงถึงองค์ประกอบของการทำงานอัตโนมัติ เช่น เงื่อนไขเริ่มต้น เงื่อนไข หรือการดำเนินการ
กำหนด name และ description ให้กับการทำงานอัตโนมัติ
การสร้างการทำงานอัตโนมัติจะตั้งค่าแฟล็ก isActive เป็น true โดยค่าเริ่มต้น คุณจึงไม่จำเป็นต้องตั้งค่าแฟล็กนี้อย่างชัดเจน เว้นแต่ว่าคุณต้องการปิดใช้การทำงานอัตโนมัติในตอนแรก ในกรณีดังกล่าว ให้ตั้งค่าแฟล็กเป็น false ระหว่างการสร้าง
อินเทอร์เฟซ DraftAutomation ใช้สำหรับสร้างการทำงานอัตโนมัติ
ส่วนอินเทอร์เฟซ Automation ใช้สำหรับการดึงข้อมูล ตัวอย่างเช่น นี่คือ 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()) }
}
}
เมื่อกำหนด Automation DSL แล้ว ให้ส่งไปยัง
createAutomation()
เมธอดเพื่อสร้างอินสแตนซ์ DraftAutomation
val createdAutomation = structure.createAutomation(automation)
จากที่นี่ คุณสามารถใช้เมธอดการทำงานอัตโนมัติอื่นๆ ทั้งหมดกับการทำงานอัตโนมัติ เช่น execute(), stop() และ update()
ข้อผิดพลาดเกี่ยวกับการตรวจสอบความถูกต้อง
หากการสร้างการทำงานอัตโนมัติไม่ผ่านการตรวจสอบความถูกต้อง ข้อความคำเตือนหรือข้อความแสดงข้อผิดพลาดจะให้ข้อมูลเกี่ยวกับปัญหา ดูข้อมูลเพิ่มเติมได้ที่ข้อมูลอ้างอิง
ValidationIssueType
ตัวอย่างโค้ด
เราจะแสดงตัวอย่างโค้ดที่ใช้เพื่อนำส่วนต่างๆ ของการทำงานอัตโนมัติสมมติที่อธิบายไว้ในหน้า ออกแบบการทำงานอัตโนมัติใน 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()
เมธอด แล้วส่งนิพจน์แลมบ์ดาที่ตั้งค่าข้อมูลเมตา
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 เงื่อนไขเริ่มต้นดังกล่าวจะไม่สามารถเปิดใช้งานการทำงานอัตโนมัติได้อีกต่อไป