Discovery API มีไว้สำหรับแอปที่สร้างการทำงานอัตโนมัติได้ โดยอิงตามอุปกรณ์ที่มีอยู่ในบ้านของผู้ใช้ ข้อมูลนี้สามารถแสดงให้แอปทราบที่รันไทม์ว่าลักษณะและอุปกรณ์ใดอยู่ในโครงสร้างหนึ่งๆ เพื่อใช้ในการทำงานอัตโนมัติ นอกจากนี้ ยังแสดงคําสั่ง แอตทริบิวต์ และเหตุการณ์ที่เกี่ยวข้อง รวมถึงช่วงของค่าที่อนุญาตสําหรับพารามิเตอร์และช่อง
Discovery API จะไม่สนใจอุปกรณ์หรือลักษณะที่อยู่ในโครงสร้างที่ Automation API ไม่รองรับ รวมถึงอุปกรณ์หรือลักษณะที่ไม่ได้ลงทะเบียนใน FactoryRegistry
ดูข้อมูลเพิ่มเติมเกี่ยวกับการใช้ FactoryRegistry
ได้ที่หัวข้อสร้างอินสแตนซ์ Home
ใช้ API
หัวใจสําคัญของ Discovery API คือ HasCandidates
อินเทอร์เฟซ ซึ่งเป็นรูทของลําดับชั้นประเภทที่มี Structure
,
Room
และ HomeDevice
อินเทอร์เฟซ HasCandidates
กำหนดเมธอด 2 รายการ ได้แก่ candidates()
และ allCandidates()
ซึ่งทั้ง 2 เมธอดจะแสดงผลออบเจ็กต์ Flow
candidates()
แสดงรายการผู้สมัครรับการทำงานอัตโนมัติสำหรับเอนทิตี (Structure
,Room
,HomeDevice
)allCandidates()
จะสร้างรายการรายการที่เป็นไปได้สำหรับการทำงานอัตโนมัติของเอนทิตีและรายการย่อยทั้งหมดRoom
ไม่รองรับวิธีการนี้
ต่างจากออบเจ็กต์ Flow
อื่นๆ ที่ Home API แสดงผล ซึ่งจะมีสแนปชอตแบบครั้งเดียว
หากต้องการดูรายการตัวเลือกล่าสุดของนักพัฒนาแอปต้องเรียกใช้ candidates()
หรือ allCandidates()
ทุกครั้ง และไม่สามารถเรียกใช้ collect()
ในออบเจ็กต์ Flow
ได้ นอกจากนี้ เนื่องจาก 2 วิธีนี้ใช้ทรัพยากรมากเป็นพิเศษ การเรียกใช้บ่อยกว่า 1 ครั้งต่อนาทีจะส่งผลให้ระบบแสดงข้อมูลที่แคชไว้ ซึ่งอาจไม่ได้แสดงสถานะปัจจุบันจริง ณ ขณะนั้น
อินเทอร์เฟซ NodeCandidate
แสดงโหนดที่เป็นไปได้ซึ่งพบโดย 2 วิธีนี้ และเป็นรูทของลําดับชั้นซึ่งมีอินเทอร์เฟซต่อไปนี้
และชั้นเรียนต่อไปนี้
ทำงานร่วมกับผู้สมัครเข้าร่วมการทํางานอัตโนมัติ
สมมติว่าคุณเขียนแอปที่สร้างการทำงานอัตโนมัติเพื่อปิดชุดม่านหน้าต่างอัจฉริยะตามเวลาที่ผู้ใช้ระบุ อย่างไรก็ตาม คุณไม่ทราบว่าผู้ใช้มีอุปกรณ์ที่รองรับลักษณะ WindowCovering
หรือไม่ และ WindowCovering
หรือแอตทริบิวต์หรือคําสั่งใดๆ ของ WindowCovering
สามารถใช้ในงานอัตโนมัติได้หรือไม่
โค้ดต่อไปนี้แสดงวิธีใช้ Discovery API เพื่อกรองเอาต์พุตของเมธอด candidates()
เพื่อจำกัดขอบเขตผลลัพธ์และรับองค์ประกอบประเภทที่เฉพาะเจาะจง (โครงสร้าง เหตุการณ์ คําสั่ง) ที่ต้องการ ในตอนท้าย ระบบจะสร้างการทำงานอัตโนมัติจากองค์ประกอบที่รวบรวม
import com.google.home.Structure
import com.google.home.automation.CommandCandidate
import com.google.home.automation.EventCandidate
import com.google.home.automation.Automation
import com.google.home.automation.DraftAutomation
import com.google.home.platform.Time
import java.time.LocalTime
import com.google.home.matter.standard.WindowCoveringTrait
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
fun createAutomationWithDiscoveryApiTimeStarter(
structureName: String,
scheduledTimeInSecond: Int,
): String = runBlocking {
// get the Structure
val structure = homeClient.structures().findStructureByName(structureName)
// get an event candidate
val clockTimeStarter =
structure
.allCandidates().first().firstOrNull {candidate ->
candidate is EventCandidate && candidate.eventFactory == Time.ScheduledTimeEvent
} as EventCandidate
// retrieve the first 'DownOrClose' command encountered
val downOrCloseCommand =
structure.allCandidates().first().firstOrNull {
candidate ->
candidate is CommandCandidate
&& candidate.commandDescriptor == WindowCoveringTrait.DownOrCloseCommand
} as CommandCandidate
val blinds = ...
// prompt user to select the WindowCoveringDevice
...
if (clockTimeStarter && downOrCloseCommand && blinds) {
// Create the draft automation
val draftAutomation: DraftAutomation = automation {
name = ""
description = ""
isActive = true
sequential {
val mainStarter = starter<_>(structure, Time.ScheduledTimeEvent) {
parameter(
Time.ScheduledTimeEvent.clockTime(
LocalTime.ofSecondOfDay(scheduledTimeInSecond.toLong())
)
)
}
action(blinds, WindowCoveringDevice) { command(WindowCoveringTrait.downOrClose())
}
}
// Create the automation in the structure
val automation = structure.createAutomation(draftAutomation)
return@runBlocking automation.id.id
} else ... //the automation cannot be created
ตัวอย่างต่อไปนี้สร้างการทำงานอัตโนมัติเพื่อตั้งค่าระดับความสว่างของหลอดไฟเมื่อเปิด
import com.google.home.Structure
import com.google.home.automation.CommandCandidate
import com.google.home.automation.TraitAttributesCandidate
import com.google.home.automation.Automation
import com.google.home.automation.DraftAutomation
import com.google.home.matter.standard.LevelControl
import com.google.home.matter.standard.LevelControlTrait.MoveToLevelCommand
import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOff.Companion.onOff
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import com.google.home.automation.equals
fun createAutomationWithDiscoveryApiDimLight(
structureName: String,
): String = runBlocking {
// get the Structure
val structure: Structure = homeClient.structures().findStructureByName(structureName)
/**
* When I turn on the light, move the brightness level to 55
*/
val allCandidates = structure.allCandidates().first()
val dimmableLightDevice = structure.devices().list().first {it.has(OnOff) && it.has(LevelControl)}
val starterCandidate =
allCandidates
.filterIsInstance<TraitAttributesCandidate>()
.first { it.entity == dimmableLightDevice && it.trait == OnOff }
val actionCandidate =
allCandidates
.filterIsInstance<CommandCandidate>()
.first {it.entity == dimmableLightDevice && it.commandDescriptor == MoveToLevelCommand }
if (starterCandidate && actionCandidate) {
// Create the draft automation
val draftAutomation: DraftAutomation = automation {
sequential {
val starter = starter<_>(dimmableLightDevice, OnOffLightDevice, OnOff)
condition { expression = starter.onOff equals true }
action(dimmableLightDevice,DimmableLightDevice) {
mapOf(MoveToLevelCommand.Request.CommandFields.level to 55u.toUByte())
)
}
}
// Create the automation in the structure
val automation = structure.createAutomation(draftAutomation)
return@runBlocking automation.id.id
}
} else ... //the automation cannot be created
ตรวจสอบข้อกําหนดเบื้องต้น
Discovery API ช่วยให้คุณทราบว่าลักษณะไม่มีข้อกําหนดเบื้องต้นในการใช้งาน เช่น การสมัครใช้บริการหรือที่อยู่โครงสร้าง
โดยจะใช้แอตทริบิวต์ของคลาส Candidate
unsupportedReasons
ระบบจะป้อนข้อมูลแอตทริบิวต์นี้ด้วย UnsupportedCandidateReason
ในระหว่างการเรียก candidates()
และข้อมูลเดียวกันจะปรากฏในข้อความแสดงข้อผิดพลาดของการตรวจสอบเมื่อเรียกใช้ createAutomation()
ตัวอย่างเหตุผล
MissingStructureAddressSetup
แจ้งให้ผู้ใช้ทราบว่าต้องตั้งค่าที่อยู่เพื่อใช้Time
ลักษณะ เปลี่ยนที่อยู่บ้านของ Google อธิบายวิธีที่ผู้ใช้ป้อนที่อยู่โครงสร้างโดยใช้ Google Home app (GHA)MissingPresenceSensingSetup
แจ้งให้ผู้ใช้ทราบว่าต้องตั้งค่าการแสดงผลเพื่อใช้ลักษณะAreaPresenceState
และAreaAttendanceState
MissingSubscription
แจ้งให้ผู้ใช้ทราบว่าต้องสมัครใช้บริการ Nest Aware จึงจะใช้ลักษณะObjectDetection
ได้
ตัวอย่างเช่น หากต้องการจัดการ MissingStructureAddressSetup
UnsupportedCandidateReason
คุณอาจต้องแสดง Toast ในแอปและเปิด GHA เพื่ออนุญาตให้ผู้ใช้ระบุที่อยู่ของโครงสร้าง
val structure = homeManager.structures().list().single()
val allCandidates = structure.allCandidates().list().single()
val scheduledStarterCandidate = allCandidates.first { it is EventCandidate && it.eventFactory == ScheduledTimeEvent }
if (scheduledStarterCandidate.unsupportedReasons.any { it is MissingStructureAddressSetup }) {
showToast("No Structure Address setup. Redirecting to GHA to set up an address.")
launchChangeAddress(...)
}
ตรวจสอบพารามิเตอร์
Discovery API จะแสดงค่าที่อนุญาตสำหรับแอตทริบิวต์ พารามิเตอร์ หรือฟิลด์เหตุการณ์ในรูปแบบของอินสแตนซ์ Constraint
ข้อมูลนี้ช่วยให้นักพัฒนาแอปป้องกันไม่ให้ผู้ใช้ตั้งค่าที่ไม่ถูกต้องได้
คลาสย่อยแต่ละคลาสของ Constraint
มีวิธีแสดงค่าที่ยอมรับของตนเอง
คลาสข้อจำกัด | พร็อพเพอร์ตี้ที่แสดงค่าที่ยอมรับ |
---|---|
BitmapConstraint |
combinedBits
|
BooleanConstraint | |
ByteConstraint |
maxLength และ minLength
|
EnumConstraint |
allowedSet
|
NumberRangeConstraint |
lowerBound , upperBound , step และ unit
|
NumberSetConstraint |
allowedSet และ unit
|
StringConstraint |
allowedSet , disallowedSet , isCaseSensitive ,
maxLength , minLength และ
regex
|
StructConstraint |
fieldConstraints
|
ListConstraint |
elementConstraint
|
ใช้ข้อจำกัด
สมมติว่าคุณเขียนแอปที่สร้างการทำงานอัตโนมัติซึ่งตั้งค่าระดับของอุปกรณ์ที่มีลักษณะLevelControl
ตัวอย่างต่อไปนี้แสดงวิธีตรวจสอบว่าค่าที่ใช้เพื่อตั้งค่าแอตทริบิวต์ LevelControl
ของลักษณะ currentLevel
อยู่ภายในขอบเขตที่ยอมรับ
import android.content.Context
import com.google.home.Home
import com.google.home.Structure
import com.google.home.automation.Action
import com.google.home.automation.Automation
import com.google.home.automation.CommandCandidate
import com.google.home.automation.Condition
import com.google.home.automation.Constraint
import com.google.home.automation.Equals
import com.google.home.automation.EventCandidate
import com.google.home.automation.HasCandidates
import com.google.home.automation.Node
import com.google.home.automation.NodeCandidate
import com.google.home.automation.SequentialFlow
import com.google.home.automation.Starter
import com.google.home.matter.standard.LevelControlTrait
// Filter the output of candidates() to find the TraitAttributesCandidate
// for the LevelControl trait.
val levelCommand =
structure
.allCandidates()
.first()
.firstOrNull { candidate ->
candidate is CommandCandidate && candidate.command == LevelControlTrait.MoveToLevelCommand
} as? CommandCandidate
var levelConstraint = null
// Get the NodeCandidate instance's fieldDetailsMap and
// retrieve the Constraint associated with the level parameter.
// In this case, it is a NumberRangeConstraint.
if (levelCommand != null) {
levelConstraint =
levelCommand.fieldDetailsMap[
LevelControlTrait.MoveToLevelCommand.Request.CommandFields.level
]!!.constraint
}
...
// Test the value against the Constraint (ignoring step and unit)
if ( value in levelConstraint.lowerBound..levelConstraint.upperBound) {
// ok to use the value
}
เปรียบเทียบ Device API กับ Discovery API
คุณสามารถดูประเภทอุปกรณ์ ลักษณะ และแอตทริบิวต์ของอุปกรณ์ได้โดยไม่ต้องใช้ Discovery API เมื่อใช้ Device API คุณจะค้นพบข้อมูลต่อไปนี้
- ประเภทอุปกรณ์หลักที่ผู้ใช้ให้สิทธิ์แก่นักพัฒนาแอปในการควบคุมโดยใช้วิธีการ
DeviceType.Metadata.isPrimaryType()
- อุปกรณ์แต่ละเครื่องรองรับลักษณะทั้งหมดที่การทำงานอัตโนมัติต้องการหรือไม่ โดยใช้วิธี
HasTraits.has()
- แต่ละลักษณะรองรับแอตทริบิวต์และคําสั่งทั้งหมดที่การทำงานอัตโนมัติต้องใช้หรือไม่โดยใช้เมธอด
supports()
โปรดทราบว่าหากใช้ Device API ในการค้นพบ คุณจะไม่ได้รับประโยชน์จากความสามารถต่อไปนี้ของ Discovery API
- การกรองลักษณะที่ Automation API ไม่รองรับออกโดยอัตโนมัติ
- ความสามารถในการให้ตัวเลือกแก่ผู้ใช้ในการเลือกค่าที่ถูกต้องสำหรับแอตทริบิวต์และพารามิเตอร์ที่ใช้ข้อจำกัด