เข้าถึงอุปกรณ์และข้อมูลเมตาของอุปกรณ์สำหรับ Android

คุณเข้าถึง Device API ได้ผ่าน Home API สำหรับ Android นำเข้าแพ็กเกจเหล่านี้ไปยังแอปของคุณ

import com.google.home.Home
import com.google.home.HomeDevice
import com.google.home.Id

หากต้องการใช้ประเภทหรือลักษณะเฉพาะของอุปกรณ์กับ Device API คุณต้องนำเข้าทีละรายการ

ตัวอย่างเช่น หากต้องการใช้ลักษณะ Matter On/Off และประเภทอุปกรณ์ On/Off Plug-in Unit ให้นำเข้าแพ็กเกจต่อไปนี้ลงในแอปพลิเคชัน

import com.google.home.matter.standard.OnOff
import com.google.home.matter.standard.OnOffPluginUnitDevice

ดูข้อมูลเพิ่มเติมได้ที่โมเดลข้อมูลใน Android

การจัดการข้อผิดพลาด

เมธอดใดก็ตามใน Home API สามารถแสดง HomeException ได้ ดังนั้นเราขอแนะนำให้คุณใช้บล็อก try-catch เพื่อตรวจจับ HomeException ในการเรียกใช้ทั้งหมด

เมื่อจัดการ HomeException ให้ตรวจสอบช่อง error.code และ error.message เพื่อดูว่าเกิดข้อผิดพลาดใดขึ้น นอกจากนี้ อาจมีรหัสข้อผิดพลาดย่อยด้วย ดังนั้นให้เรียกใช้เมธอด getSubErrorCodes() และตรวจสอบผลลัพธ์

ข้อยกเว้นที่ไม่ได้จัดการจะทำให้แอปขัดข้อง

ดูข้อมูลเพิ่มเติมได้ที่การจัดการข้อผิดพลาด

ดูตัวอย่างได้ที่หัวข้อส่งคำสั่งไปยังอุปกรณ์

ตัวอย่างการโทร

ดูรายการอุปกรณ์

เมื่อคุณมีข้อมูลอ้างอิงไปยังอินสแตนซ์ Structure แล้ว การเรียก devices() จะแสดงผล Flow ของอุปกรณ์ที่คุณเข้าถึงได้จากโครงสร้างนั้น

// Get a flow of all devices accessible to the user
val allDevicesFlow: HomeObjectsFlow<HomeDevice> = home.devices()

// Calling list() on a HomeObjectsFlow returns the first Set of elements.
val allDevices: Set<HomeDevice> = allDevicesFlow.list()

จากตรงนั้น คุณจะเข้าถึงสถานะของอุปกรณ์แต่ละเครื่องและส่งคำสั่งไปยังอุปกรณ์ได้

Home API เวอร์ชัน 1.8 ช่วยให้คุณมีตัวเลือกในการให้ API แสดงอุปกรณ์แบบหลายส่วนแต่ละเครื่องเป็นอุปกรณ์เดียวได้โดยตั้งค่าพารามิเตอร์ enableMultipartDevices ของเมธอด devices() เป็น true ดูข้อมูลเพิ่มเติมได้ที่อุปกรณ์แบบหลายส่วนใน Android

อ่านสถานะอุปกรณ์

ดูตัวอย่างการตรวจสอบแอตทริบิวต์ OnOff จากลักษณะเปิด/ปิดของอุปกรณ์ เมื่อใช้โมเดลข้อมูลลักษณะของ Home API ซึ่งลักษณะนี้ระบุเป็น OnOff คุณจะดึงข้อมูลลักษณะผ่านคลาส standardTraits ของประเภทอุปกรณ์ได้ ดังนี้

// Assuming we have a device.
val deviceFlow = home.devices().itemFlow(myDeviceId)

val device = deviceFlow.first()

// Get a flow of a standard trait on the type. distinctUntilChanged() is needed to only trigger
// on the specific trait changes and not the whole type.
val onOffTraitFlow: Flow<OnOff?> =
  device.type(DimmableLightDevice).map { it.standardTraits.onOff }.distinctUntilChanged()

val onOffTrait: OnOff = onOffTraitFlow.first()!!

ดูข้อมูลเพิ่มเติมเกี่ยวกับฟังก์ชัน Kotlin Flow ได้ที่ distinctUntilChanged

สถานะไม่ถูกต้องในการสมัครใช้บริการลักษณะ

อินเทอร์เฟซ TraitStateInvalidation ช่วยให้สามารถลบล้างสถานะที่ดึงมาผ่านการสมัครใช้บริการไปยังอุปกรณ์เป้าหมายในกรณีที่ไม่มีการรายงานสถานะอย่างถูกต้อง ตัวอย่างกรณีที่อาจมีการรายงานสถานะอย่างไม่ถูกต้อง ได้แก่ การใช้แอตทริบิวต์ในลักษณะ Matter ที่มีคุณภาพ "C" หรือเนื่องจากการติดตั้งใช้งานอุปกรณ์ที่ทำให้เกิดปัญหาโดยไม่คาดคิด

API นี้จะบังคับให้อ่านสถานะลักษณะปัจจุบันและแสดงผลลัพธ์ผ่านขั้นตอนลักษณะที่มีอยู่

รับลักษณะ แล้วเรียกใช้ forceRead ในลักษณะดังกล่าว

val onOffTrait = device.?type(DimmableLightDevice)?.map{it.trait(OnOff)}.first()
onOffTrait.forceRead()

ดูรายการลักษณะของประเภทอุปกรณ์

ควรใช้ประเภทอุปกรณ์เป็นจุดแรกเข้าสำหรับการอ่านลักษณะ เนื่องจากประเภทอุปกรณ์จะแยกย่อยอุปกรณ์ออกเป็นส่วนๆ ตามฟังก์ชันการทำงาน (เช่น ปลายทางใน Matter)

นอกจากนี้ยังพิจารณาการชนกันของลักษณะในกรณีที่อุปกรณ์มีลักษณะของอุปกรณ์ 2 ประเภท ซึ่งทั้ง 2 ประเภทอาจมีลักษณะเดียวกัน ตัวอย่างเช่น หากอุปกรณ์เป็นทั้งลำโพงและหลอดไฟหรี่แสงได้ อุปกรณ์จะมีลักษณะ On/Off 2 รายการและ Level Control 2 รายการ

วิธีดูรายการลักษณะที่ใช้ได้สำหรับอุปกรณ์ประเภทไฟที่หรี่แสงได้

// Get all types available on this device. Requires the types to be part of the registry during
// SDK initialization.
val typesFlow: Flow<Set<DeviceType>> = device.types()

// Get a snapshot of all types.
val types: Set<DeviceType> = typesFlow.first()

// Get the DimmableLightDevice instance from the set of types.
val dimmableLightDevice = types.filterIsInstance<DimmableLightDevice>().firstOrNull()

// Get all traits in the type + traits registered
val allTraits: Set<Trait> = dimmableLightDevice!!.traits()

การทับซ้อนของลักษณะอีกประเภทหนึ่งอาจเกิดขึ้นเมื่ออุปกรณ์มีลักษณะ 2 รายการที่มีชื่อเดียวกัน เช่น onOff อาจหมายถึงอินสแตนซ์ของลักษณะ OnOff มาตรฐาน หรืออาจหมายถึงอินสแตนซ์ของลักษณะ OnOff ที่ผู้ผลิตกำหนด เพื่อขจัดความกำกวมที่อาจเกิดขึ้นเกี่ยวกับลักษณะที่ต้องการ อินสแตนซ์ Trait ที่อ้างอิงผ่านอุปกรณ์ควรนำหน้าด้วยเนมสเปซที่ตรงตามเกณฑ์ สำหรับลักษณะมาตรฐาน ซึ่งก็คือลักษณะที่คล้ายคลึงกับคลัสเตอร์มาตรฐาน Matter ให้ใช้ standardTraits สำหรับลักษณะของ Google ให้ใช้ googleTraits:

// Accessing standard traits on the type.
val onOffTrait: OnOff? = dimmableLightDevice.standardTraits.onOff
val levelControlTrait: LevelControl? = dimmableLightDevice.standardTraits.levelControl

หากต้องการเข้าถึงลักษณะเฉพาะของผู้ผลิต ให้อ้างอิงลักษณะดังกล่าวโดยตรง ดังนี้

// Accessing a custom trait on the type.
val customTrait = dimmableLightDevice.trait(MyCustomTrait)

ดูรายการอุปกรณ์ที่มีลักษณะเฉพาะ

คุณสามารถใช้ฟังก์ชัน filter ใน Kotlin เพื่อปรับแต่งการเรียก API เพิ่มเติมได้ ตัวอย่างเช่น หากต้องการดูรายการอุปกรณ์ในบ้านที่มีลักษณะเปิด/ปิดทั้งหมด ให้ทำดังนี้

// Get all devices that support OnOff
val onOffDevices: Flow<List<HomeDevice>> =
  home.devices().map { devices -> devices.filter { it.has(OnOff) } }

ดูรายการลักษณะทั้งหมดที่มีใน Home API ได้ที่อินเทอร์เฟซ Trait

ดูรายการอุปกรณ์ที่มีประเภทอุปกรณ์คล้ายกัน

วิธีดูรายการอุปกรณ์ที่แสดงถึงหลอดไฟทั้งหมดในบ้าน

// Get a list of devices with similar device types (lights)
val lightDevices =
  home.devices().map { devices ->
    devices.filter {
      it.has(DimmableLightDevice) ||
        it.has(OnOffLightDevice) ||
        it.has(ColorTemperatureLightDevice) ||
        it.has(ExtendedColorLightDevice)
    }
  }

Home API มีอุปกรณ์หลายประเภทที่อาจแสดงถึงประเภทอุปกรณ์หลัก เช่น ไม่มีประเภทอุปกรณ์ "Light" แต่จะมีอุปกรณ์ 4 ประเภทที่แตกต่างกันซึ่งอาจแสดงถึงไฟ ดังที่แสดงในตัวอย่างก่อนหน้านี้ ดังนั้น หากต้องการดูภาพรวมของประเภทอุปกรณ์ระดับสูงในบ้าน คุณต้องรวมอุปกรณ์หลายประเภทไว้ในขั้นตอนที่กรอง

ดูรายการประเภทอุปกรณ์ทั้งหมดที่พร้อมใช้งานใน Home API ได้ที่อินเทอร์เฟซ DeviceType

ดูรหัสผู้ให้บริการหรือรหัสสินค้าสำหรับอุปกรณ์

ลักษณะ BasicInformation ประกอบด้วยข้อมูล เช่น รหัสผู้ให้บริการ รหัสสินค้า ชื่อสินค้า และหมายเลขซีเรียลของอุปกรณ์

// Get device basic information. All general information traits are on the RootNodeDevice type.
val basicInformation = device.type(RootNodeDevice).first().standardTraits.basicInformation!!
println("vendorName ${basicInformation.vendorName}")
println("vendorId ${basicInformation.vendorId}")
println("productId ${basicInformation.productId}")

การระบุอุปกรณ์แบบ Cloud-to-Cloud สำหรับผู้ผลิตอุปกรณ์

หากคุณเป็นผู้ผลิตอุปกรณ์และสร้างอุปกรณ์ Cloud-to-cloud เพื่อระบุอุปกรณ์ Cloud-to-cloud ผ่านลักษณะ BasicInformation คุณสามารถใส่ช่องสตริงเหล่านี้ในการตอบกลับ SYNC ได้

  • รหัสผู้ให้บริการที่ออกโดย Connectivity Standards Alliance (Alliance): "matterOriginalVendorId": "0xfff1",

  • ตัวระบุสินค้าที่ระบุผลิตภัณฑ์ของผู้ให้บริการโดยไม่ซ้ำกัน "matterOriginalProductId": "0x1234",

  • ตัวระบุที่ไม่ซ้ำกันสำหรับอุปกรณ์ ซึ่งสร้างขึ้นในลักษณะเฉพาะของผู้ผลิต ดังนี้ "matterUniqueId": "matter-device-id",

เมื่อป้อนช่องสตริงเหล่านี้ ให้ใช้Matter รหัสผู้ให้บริการและรหัสสินค้าหากมี หากคุณไม่ได้เป็นสมาชิก Alliance และไม่ได้รับรหัสเหล่านี้ คุณสามารถเว้นช่อง matterOriginalVendorId และ matterOriginalProductId ว่างไว้ แล้วระบุ matterUniqueId เป็นตัวระบุได้

ตัวอย่างการตอบกลับ SYNC แสดงการใช้ช่องเหล่านี้

{
  "requestId": "ff36a3cc-ec34-11e6-b1a0-64510650abcf",
  "payload": {
    "agentUserId": "1836.15267389",
    "devices": [
      {
        "id": "456",
        "type": "action.devices.types.LIGHT",
        "traits": [
          "action.devices.traits.OnOff",
          "action.devices.traits.Brightness",
          "action.devices.traits.ColorSetting",
        ],
        "willReportState": true,
        "deviceInfo": { ... },
        "matterOriginalVendorId": "0xfff1",
        "matterOriginalProductId": "0x1234",
        "matterUniqueId": "matter-device-id",
        "otherDeviceIds": [
          {
            "deviceId": "local-device-id",
          }
        ]
      }
    ]
  }
}

ดูข้อมูลเพิ่มเติมได้ที่เอกสารประกอบของ Cloud-to-cloud SYNC

ข้อมูลเมตาของอุปกรณ์และลักษณะเฉพาะ

อุปกรณ์และลักษณะใน Home API มีข้อมูลเมตาที่เชื่อมโยงอยู่ ซึ่งจะช่วยจัดการประสบการณ์ของผู้ใช้ในแอปได้

ลักษณะแต่ละรายการใน Home API จะมีพร็อพเพอร์ตี้ sourceConnectivity ซึ่งมีข้อมูลเกี่ยวกับสถานะออนไลน์และตำแหน่ง (การกำหนดเส้นทางภายในหรือระยะไกล) ของลักษณะ

รับประเภทหลักของอุปกรณ์

อุปกรณ์บางเครื่องอาจแสดงอุปกรณ์หลายประเภทผ่าน Home API คุณควรตรวจสอบประเภทอุปกรณ์หลักของอุปกรณ์เพื่อให้แน่ใจว่าผู้ใช้จะเห็นตัวเลือกที่เหมาะสมในแอป (เช่น การควบคุมอุปกรณ์และการทำงานอัตโนมัติที่แนะนำ) สำหรับอุปกรณ์ของตน

ก่อนอื่น ให้ดูประเภทของอุปกรณ์โดยใช้ type() จากนั้นระบุประเภทหลัก ดังนี้

val types = device.types().first()
val primaryTypes = types.filter { it.metadata.isPrimaryType }

ตรวจสอบว่าลักษณะออนไลน์อยู่หรือไม่

ใช้เมธอด connectivityState() เพื่อตรวจสอบการเชื่อมต่อของลักษณะเฉพาะ ดังนี้

val onOffConnectivity = onOffTrait?.metadata?.sourceConnectivity?.connectivityState

ลักษณะบางอย่าง โดยปกติแล้วจะเป็นลักษณะของ Google smart home อาจแสดงเป็นออฟไลน์หากอุปกรณ์ไม่มีการเชื่อมต่ออินเทอร์เน็ต เนื่องจากลักษณะเหล่านี้ทำงานในระบบคลาวด์และไม่มีการกำหนดเส้นทางในเครื่อง

ตรวจสอบการเชื่อมต่อของอุปกรณ์

ระบบจะตรวจสอบการเชื่อมต่อของอุปกรณ์ที่ระดับประเภทอุปกรณ์ เนื่องจากอุปกรณ์บางเครื่องรองรับอุปกรณ์หลายประเภท สถานะที่แสดงผลคือชุดค่าผสมของสถานะการเชื่อมต่อสำหรับลักษณะทั้งหมดในอุปกรณ์นั้น

val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

อาจพบสถานะ PARTIALLY_ONLINE ในกรณีที่อุปกรณ์มีหลายประเภทและไม่มีการเชื่อมต่ออินเทอร์เน็ต ลักษณะมาตรฐานของ Matter อาจยังออนไลน์อยู่เนื่องจากการกำหนดเส้นทางในเครื่อง แต่ลักษณะที่อิงตามระบบคลาวด์จะออฟไลน์

ดูที่อยู่ IP ของอุปกรณ์

หากต้องการค้นหาที่อยู่ IP ของอุปกรณ์ ให้ใช้แอตทริบิวต์ networkInterfaces ของลักษณะ GeneralDiagnostics ระบบจะแสดงผลที่อยู่เป็นอาร์เรย์ไบต์ ซึ่งคุณสามารถจัดรูปแบบเป็นสตริง IPv4 หรือ IPv6 มาตรฐานได้ ดังนี้

val ipAddresses =
  trait.networkInterfaces?.flatMap { networkInterface ->
    (networkInterface.ipv4Addresses + networkInterface.ipv6Addresses).mapNotNull { bytes ->
      try {
        java.net.InetAddress.getByAddress(bytes).hostAddress
      } catch (e: java.net.UnknownHostException) {
        null
      }
    }
  } ?: emptyList()

ตรวจสอบการกำหนดเส้นทางเครือข่ายของลักษณะ

นอกจากนี้ ตำแหน่งของลักษณะยังพร้อมใช้งานใน Home API ด้วย dataSourceLocality ระบุว่าลักษณะได้รับการกำหนดเส้นทางจากระยะไกล (ผ่านระบบคลาวด์) ในเครื่อง (ผ่านฮับในเครื่อง) หรือแบบเพียร์ทูเพียร์ (จากอุปกรณ์หนึ่งไปยังอีกอุปกรณ์หนึ่งโดยตรงโดยไม่มีฮับ)

ค่าตำแหน่งที่ไม่รู้จัก UNSPECIFIED อาจเกิดขึ้นได้ เช่น ขณะที่แอปกำลังบูตและยังไม่ถึงฮับหรือเซิร์ฟเวอร์สำหรับการเชื่อมต่ออุปกรณ์ อุปกรณ์เหล่านี้เข้าถึงไม่ได้และจะส่งคำขอการโต้ตอบจากคำสั่งหรือเหตุการณ์ไม่สำเร็จ ลูกค้าจะเป็นผู้กำหนดวิธีจัดการอุปกรณ์ดังกล่าว

val onOffLocality = onOffTrait?.metadata?.sourceConnectivity?.dataSourceLocality

ตรวจสอบการกำหนดเส้นทางเครือข่ายสำหรับอุปกรณ์

ระบบจะตรวจสอบตำแหน่งที่ระดับประเภทอุปกรณ์ เช่นเดียวกับการเชื่อมต่อ สถานะที่แสดงผลคือการรวมกันของตำแหน่งสำหรับลักษณะทั้งหมดในอุปกรณ์นั้น

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

สถานะ MIXED อาจพบได้ในสถานการณ์ที่คล้ายกับการเชื่อมต่อ PARTIALLY_ONLINE นั่นคือลักษณะบางอย่างเป็นแบบในระบบคลาวด์ ในขณะที่ลักษณะอื่นๆ เป็นแบบในเครื่อง

เปลี่ยนชื่ออุปกรณ์

เรียกใช้เมธอด setName() เพื่อเปลี่ยนชื่ออุปกรณ์

mixerDevice.setName("Grendel")

ระบบจะตัดชื่อให้สั้นลงหากเกินขีดจำกัด Code Point (อักขระ) ของ Unicode ที่ 60 รายการ และจะไม่แสดงข้อผิดพลาด นักพัฒนาแอปมีหน้าที่รับผิดชอบในการจัดการชื่อที่ยาว และสามารถตัดสินใจได้ว่าต้องการแจ้งให้ผู้ใช้ทราบหรือไม่ว่าชื่อจะถูกตัดให้สั้นลง

ตรวจสอบการเป็นสมาชิกกลุ่มของอุปกรณ์

อุปกรณ์จริงสามารถอยู่ในกลุ่มอุปกรณ์ได้มากกว่า 1 กลุ่ม หากต้องการดูว่าอุปกรณ์อยู่ในกลุ่มใด ให้ตรวจสอบลักษณะ GroupMembership ในอุปกรณ์ โดยทำดังนี้

val groupIds = device.trait(GroupMembershipTrait)?.groupObjectIds.orEmpty()
for (groupId in groupIds) {
  println("HomeAPI", "Device belongs to group: $groupId")
}

ในทางกลับกัน คุณสามารถสังเกตอุปกรณ์สมาชิกทั้งหมดที่เป็นของ DeviceGroup ได้โดยเรียกใช้โฟลว์ devices() ใน DeviceGroup ดังนี้

group.devices(enableMultipartDevices = true).collect { members ->
  println("HomeAPI", "Group contains ${members.size} devices")
}

หากต้องการตรวจสอบประเภทอุปกรณ์ที่ DeviceGroup รองรับและส่งคำสั่งไปยังกลุ่มเป็นเอนทิตีเดียว โปรดดูหัวข้อควบคุมกลุ่มอุปกรณ์