Truy cập vào thiết bị và siêu dữ liệu thiết bị cho Android

Bạn có thể truy cập vào Device API thông qua Home API cho Android. Nhập các gói này vào ứng dụng của bạn:

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

Để sử dụng các loại hoặc đặc điểm thiết bị cụ thể với Device API, bạn phải nhập từng loại hoặc đặc điểm riêng lẻ.

Ví dụ: để sử dụng đặc điểm Matter Bật/Tắt và loại thiết bị Đơn vị bổ trợ Bật/Tắt, hãy nhập các gói sau vào ứng dụng của bạn:

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

Để biết thêm thông tin, hãy xem bài viết Mô hình dữ liệu trên Android.

Xử lý lỗi

Mọi phương thức trong Home API đều có thể gửi HomeException, vì vậy, bạn nên sử dụng khối try-catch để bắt HomeException trên tất cả các lệnh gọi.

Khi xử lý HomeException, hãy kiểm tra các trường codemessage của đối tượng này để biết điều gì đã xảy ra.

Mọi ngoại lệ chưa được xử lý sẽ khiến ứng dụng của bạn gặp sự cố.

Để biết thêm thông tin, hãy xem phần Xử lý lỗi.

Hãy xem phần Gửi lệnh đến thiết bị để biết ví dụ.

Cuộc gọi mẫu

Lấy danh sách thiết bị

Khi có cấu trúc, một lệnh gọi devices() sẽ trả về một Luồng thiết bị mà bạn có thể truy cập từ cấu trúc đó:

// 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()

Từ đó, bạn có thể truy cập vào trạng thái của từng thiết bị và gửi các lệnh được hỗ trợ đến thiết bị.

Đọc trạng thái thiết bị

Hãy xem một ví dụ về cách kiểm tra thuộc tính OnOff từ đặc điểm Bật/tắt của thiết bị. Khi sử dụng mô hình dữ liệu đặc điểm Home APIs, trong đó đặc điểm này được xác định là OnOff, bạn có thể truy xuất dữ liệu đặc điểm thông qua lớp standardTraits của loại thiết bị:

// 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()!!

Hãy xem distinctUntilChanged để tìm hiểu thêm về hàm luồng Kotlin.

Vô hiệu hoá trạng thái trong một gói thuê bao đặc điểm

Giao diện TraitStateInvalidation cung cấp khả năng vô hiệu hoá trạng thái được truy xuất thông qua các lượt đăng ký đối với thiết bị mục tiêu trong trường hợp trạng thái không được báo cáo chính xác. Ví dụ về trường hợp trạng thái có thể không được báo cáo chính xác bao gồm việc sử dụng các thuộc tính trong đặc điểm Matter có chất lượng "C" hoặc do quá trình triển khai thiết bị gây ra vấn đề một cách bất ngờ.

API này phát hành một lệnh đọc bắt buộc về trạng thái đặc điểm hiện tại và trả về kết quả thông qua các luồng đặc điểm hiện có.

Lấy đặc điểm, sau đó chạy forceRead trên đặc điểm:

val generalDiagnosticsTrait = device.trait(GeneralDiagnostics).first()
generalDiagnosticsTrait.forceRead()

Lấy danh sách các đặc điểm của loại thiết bị

Bạn nên dùng các loại thiết bị làm điểm truy cập để đọc các đặc điểm, vì chúng phân tách một thiết bị thành các phần chức năng (chẳng hạn như điểm cuối trong Matter).

Chúng cũng tính đến các xung đột đặc điểm trong trường hợp một thiết bị có hai loại thiết bị, cả hai loại này đều có thể có cùng một đặc điểm. Ví dụ: nếu một thiết bị vừa là Loa vừa là Đèn có thể điều chỉnh độ sáng, thì thiết bị đó sẽ có 2 đặc điểm Bật/tắt và 2 đặc điểm Điều khiển mức độ.

Cách lấy danh sách các đặc điểm có sẵn cho loại thiết bị Đèn có thể điều chỉnh độ sáng:

// 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()

Một loại xung đột đặc điểm khác có thể xảy ra khi một thiết bị có hai đặc điểm có cùng tên. Ví dụ: onOff có thể đề cập đến một phiên bản của đặc điểm OnOff tiêu chuẩn hoặc có thể đề cập đến một phiên bản của đặc điểm OnOff do nhà sản xuất xác định. Để loại bỏ mọi điểm mơ hồ tiềm ẩn về đặc điểm dự kiến, một thực thể Trait được tham chiếu thông qua một thiết bị phải có một không gian tên đủ điều kiện đứng trước. Đối với các đặc điểm tiêu chuẩn, tức là những đặc điểm tương tự như các cụm tiêu chuẩn Matter, hãy sử dụng standardTraits. Đối với các đặc điểm của Google, hãy sử dụng googleTraits:

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

Để truy cập vào một đặc điểm dành riêng cho nhà sản xuất, hãy tham chiếu trực tiếp đặc điểm đó:

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

Lấy danh sách các thiết bị có một đặc điểm cụ thể

Bạn có thể dùng hàm filter trong Kotlin để tinh chỉnh thêm các lệnh gọi API. Ví dụ: để lấy danh sách các thiết bị trong nhà có đặc điểm Bật/Tắt:

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

Hãy xem giao diện Trait để biết danh sách đầy đủ các đặc điểm có trong Home API.

Lấy danh sách các thiết bị có cùng loại thiết bị

Cách lấy danh sách các thiết bị đại diện cho tất cả đèn trong nhà:

// 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)
    }
  }

Có nhiều loại thiết bị trong Home API có thể đại diện cho một loại thiết bị cốt lõi. Ví dụ: không có loại thiết bị "Đèn". Thay vào đó, có 4 loại thiết bị có thể đại diện cho một thiết bị chiếu sáng, như minh hoạ trong ví dụ trước. Do đó, để có được chế độ xem toàn diện về loại thiết bị cấp cao hơn trong nhà, bạn phải đưa nhiều loại thiết bị vào các luồng được lọc.

Hãy xem giao diện DeviceType để biết danh sách đầy đủ các loại thiết bị có trong Home API.

Lấy mã nhà cung cấp hoặc mã sản phẩm cho một thiết bị

Đặc điểm BasicInformation bao gồm những thông tin như Mã nhà cung cấp, Mã sản phẩm, Tên sản phẩm và Số sê-ri của thiết bị:

// 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}")

Tính năng nhận dạng thiết bị từ đám mây đến đám mây dành cho nhà sản xuất thiết bị

Nếu là nhà sản xuất thiết bị và tạo thiết bị Cloud-to-cloud, để xác định thiết bị Cloud-to-cloud thông qua đặc điểm BasicInformation, bạn có thể thêm các trường chuỗi này vào phản hồi SYNC của thiết bị:

  • Liên minh Tiêu chuẩn Kết nối (CSA) đã cấp mã nhận dạng nhà cung cấp: "matterOriginalVendorId": "0xfff1",

  • Giá trị nhận dạng sản phẩm là giá trị nhận dạng riêng biệt của một sản phẩm của nhà cung cấp: "matterOriginalProductId": "0x1234",

  • Giá trị nhận dạng duy nhất của thiết bị, được tạo theo cách dành riêng cho nhà sản xuất: "matterUniqueId": "matter-device-id",

Khi nhập các trường chuỗi này, hãy sử dụng Mã nhận dạng sản phẩm và nhà cung cấp Matter nếu có. Nếu không phải là thành viên CSA và chưa được chỉ định các mã nhận dạng này, bạn có thể để trống các trường matterOriginalVendorIdmatterOriginalProductId, đồng thời cung cấp matterUniqueId làm giá trị nhận dạng.

Ví dụ về phản hồi SYNC cho thấy cách sử dụng các trường này:

{
  "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",
          }
        ]
      }
    ]
  }
}

Để biết thêm thông tin, hãy xem tài liệu về Cloud-to-cloud SYNC.

Siêu dữ liệu về thiết bị và đặc điểm

Các thiết bị và đặc điểm trong Home API có siêu dữ liệu liên kết với chúng, điều này có thể giúp quản lý trải nghiệm người dùng trong một ứng dụng.

Mỗi đặc điểm trong Home API đều chứa một thuộc tính sourceConnectivity. Thuộc tính này có thông tin về trạng thái trực tuyến và vị trí của đặc điểm (định tuyến cục bộ hoặc từ xa).

Lấy loại chính của một thiết bị

Một số thiết bị có thể trình bày nhiều loại thiết bị thông qua Home API. Để đảm bảo người dùng thấy các lựa chọn phù hợp trong một ứng dụng (chẳng hạn như chế độ điều khiển thiết bị và các chế độ tự động hoá được đề xuất) cho thiết bị của họ, bạn nên kiểm tra loại thiết bị chính của một thiết bị.

Trước tiên, hãy lấy(các) loại thiết bị bằng cách sử dụng type(), sau đó xác định(các) loại chính:

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

Kiểm tra xem một đặc điểm có đang trực tuyến hay không

Sử dụng phương thức connectivityState() để kiểm tra khả năng kết nối của một đặc điểm:

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

Một số đặc điểm, thường là đặc điểm smart home của Google, có thể xuất hiện ở trạng thái ngoại tuyến nếu thiết bị không có kết nối Internet. Nguyên nhân là do các đặc điểm này dựa trên đám mây và không có định tuyến cục bộ.

Kiểm tra khả năng kết nối của thiết bị

Khả năng kết nối của thiết bị thực sự được kiểm tra ở cấp loại thiết bị vì một số thiết bị hỗ trợ nhiều loại thiết bị. Trạng thái được trả về là sự kết hợp của các trạng thái kết nối cho tất cả các đặc điểm trên thiết bị đó.

val lightConnectivity = dimmableLightDevice.metadata.sourceConnectivity.connectivityState

Bạn có thể thấy trạng thái PARTIALLY_ONLINE trong trường hợp có nhiều loại thiết bị khi không có kết nối Internet. Các đặc điểm tiêu chuẩn của Matter vẫn có thể trực tuyến do định tuyến cục bộ, nhưng các đặc điểm dựa trên đám mây sẽ không trực tuyến.

Kiểm tra định tuyến mạng của một đặc điểm

Địa điểm của một đặc điểm cũng có trong Home API. dataSourceLocality cho biết liệu đặc điểm này được định tuyến từ xa (thông qua đám mây), cục bộ (thông qua một trung tâm cục bộ) hay ngang hàng (trực tiếp từ thiết bị đến thiết bị, không cần trung tâm).

Giá trị vị trí không xác định UNSPECIFIED có thể xảy ra, ví dụ: trong khi một ứng dụng đang khởi động và chưa kết nối được với một trung tâm hoặc máy chủ để kết nối thiết bị. Những thiết bị này không thể truy cập và sẽ không xử lý được các yêu cầu tương tác từ lệnh hoặc sự kiện. Khách hàng có trách nhiệm xác định cách xử lý những thiết bị như vậy.

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

Kiểm tra định tuyến mạng cho một thiết bị

Giống như khả năng kết nối, tính cục bộ được kiểm tra ở cấp loại thiết bị. Trạng thái được trả về là sự kết hợp của vị trí cho tất cả các đặc điểm trên thiết bị đó.

val lightLocality = dimmableLightDevice.metadata.sourceConnectivity.dataSourceLocality

Bạn có thể thấy trạng thái của MIXED trong một trường hợp tương tự như trạng thái kết nối của PARTIALLY_ONLINE: một số đặc điểm dựa trên đám mây, trong khi những đặc điểm khác là cục bộ.

Thay đổi tên của thiết bị

Gọi phương thức setName() để thay đổi tên của một thiết bị:

mixerDevice.setName("Grendel")

Tên sẽ bị cắt bớt nếu vượt quá giới hạn 60 điểm mã Unicode (ký tự) và sẽ không có lỗi nào xảy ra. Nhà phát triển chịu trách nhiệm xử lý tên dài và có thể quyết định xem họ có muốn thông báo cho người dùng rằng tên sẽ bị cắt bớt hay không.

Danh sách API

Sau khi bạn tạo một phiên bản Home, bạn có thể truy cập vào các Device API sau thông qua phiên bản đó:

API Mô tả
devices() Lấy tất cả thiết bị trong tất cả các cấu trúc trên Tài khoản Google. Trả về một HomeObjectsFlow cung cấp thêm các lựa chọn truy xuất và lọc.

Sau khi bạn có HomeDevice, bạn có thể truy cập vào các API sau thông qua mã này:

API Mô tả
allCandidates() Trả về tất cả đề xuất tự động hoá cho thiết bị và các thành phần con của thiết bị.
candidates() Trả về tất cả đề xuất tự động hoá cho thiết bị.
connectivityStateChanged Thời gian gần đây nhất mà trạng thái của thiết bị thay đổi.
events(event) Nhận một luồng của một Sự kiện cụ thể.
events(trait) Nhận một luồng gồm tất cả các Sự kiện theo Đặc điểm này.
events(traits) Nhận một luồng gồm tất cả Sự kiện theo các Đặc điểm này.
getSourceConnectivity(trait) Lấy siêu dữ liệu cho một đặc điểm cụ thể. Trả về một SourceConnectivity.
has(trait) Kiểm tra xem thiết bị có hỗ trợ đặc điểm được yêu cầu hiện tại hay không.
has(type) Nếu thiết bị hỗ trợ loại được cung cấp.
id Mã nhận dạng duy nhất của hệ thống trên thiết bị.
isInRoom Nếu thiết bị ở trong phòng.
isInStructure Nếu thiết bị nằm trong một nhà.
isMatterDevice Nếu thiết bị được Matter hỗ trợ.
name Tên do người dùng cung cấp cho thiết bị.
room() Phòng mà thiết bị được chỉ định. Trả về một Room.
roomId Mã của phòng mà thiết bị được chỉ định. Trả về một Id.
sourceConnectivity Khả năng kết nối nguồn của thiết bị, thể hiện trạng thái kết nối tổng hợp và vị trí mạng của các đặc điểm của thiết bị.
structure() Cấu trúc được chỉ định cho thiết bị. Trả về một Structure.
structureId Mã nhận dạng của cấu trúc mà thiết bị được chỉ định. Trả về một Id.
type(type) Nhận định nghĩa loại với các đặc điểm được điền sẵn (nếu có) để truy cập trực tiếp. Luôn trả về ảnh chụp nhanh mới nhất về các đặc điểm.
types() Lấy danh sách tất cả các loại có trên thiết bị.