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

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

import GoogleHomeSDK
import GoogleHomeTypes

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

Xử lý lỗi

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

Khi xử lý HomeError, hãy kiểm tra các trường codemessage để tìm hiểu điều gì đã xảy ra.

Mọi lỗi không đượ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 Xử lý lỗi.

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

Lệnh gọi mẫu

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

Với một tham chiếu đến đối tượng Home, hãy gọi devices() để lấy Query của các thiết bị có thể truy cập. Gọi phương thức Query's batched(), phương thức này sẽ phát ra một Tập hợp phản ánh trạng thái hiện tại của Home với mọi thay đổi về siêu dữ liệu của thiết bị. Hoặc gọi Query.list() để lấy ảnh chụp nhanh của các thiết bị có sẵn. Đây là một phương thức tiện lợi giúp đăng ký luồng batched() và trả về giá trị được phát đầu tiên. Query.stream() tạo ra một luồng phát ra các giá trị mới khi có thay đổi về siêu dữ liệu của thiết bị, chẳng hạn như tên, phòng hoặc cấu trúc. Về mặt nội bộ, phương thức này sử dụng batched() và chỉ phát ra các thuộc tính đã thay đổi.

// Get a list of all devices accessible to the user
let homeDevices = try await self.home.devices().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 lệnh đến các thiết bị.

Với bản phát hành 1.8 của Home API, bạn có thể chọn để API đại diện cho từng thiết bị nhiều phần dưới dạng một thiết bị bằng cách đặt tham số enableMultipartDevices của phương thức devices() thành true. Hãy xem bài viết Thiết bị nhiều phần trên iOS để biết thêm thông tin.

Lấy các loại thiết bị

Để lấy các loại thiết bị được liên kết với một thiết bị, hãy đọc thuộc tính types của thiết bị. Thuộc tính này trả về DeviceTypeController.

Gọi DeviceTypeController.subscribe(_:) để đăng ký nhận thông tin cập nhật cho một loại thiết bị cụ thể:

let devices = try await self.home.devices().list()
if let device = devices.first(where: { $0.id == myDeviceId }) {
  var receivedUpdate1 = false
  var receivedUpdate2 = false
  device.types.subscribe(OnOffLightDeviceType.self)
    .assertNoFailure()
    .sink { device in
      if !receivedUpdate1 {
        receivedUpdate1 = true
        Task {
          try await device.matterTraits.onOffTrait?.on()
        }
        return
      }
      if !receivedUpdate2 {
        receivedUpdate2 = true
        return
      }
      fatalError("Received unexpected update")
    }
}

Nếu thiết bị không hỗ trợ loại thiết bị được chỉ định, thì thiết bị đó sẽ trả về một Empty Publisher hoàn tất ngay lập tức.

Nếu thiết bị hỗ trợ một loại thiết bị cụ thể, bạn có thể lấy một trình xử lý cho loại đó bằng cách gọi get():

if let device = devices.first(where: { $0.id == myDeviceId }) {
  let _ = await device.types.get(OnOffLightDeviceType.self)
}

Nếu thiết bị không hỗ trợ loại được chỉ định, thì thiết bị đó sẽ trả về nil.

Gọi DeviceTypeController.subscribeAll() để lấy Publisher của DeviceTypeCollection. Lớp này cho phép bạn kiểm tra xem thiết bị có một loại thiết bị cụ thể hay không:

if let device = devices.first(where: { $0.id == myDeviceId }) {
  device.types.subscribeAll()
    .assertNoFailure()
    .sink { types in
      let lightDeviceType = types[OnOffLightDeviceType.self]
      let fanDeviceType = types[FanDeviceType.self]
    }
}

Lấy một đặc điểm của loại thiết bị

Các loại thiết bị là đ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 (như điểm cuối trong Matter).

Chúng cũng tính đến các xung đột về đặc điểm trong trường hợp một thiết bị có 2 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 độ.

Một loại xung đột về đặc điểm khác có thể xảy ra khi một thiết bị có 2 đặc điểm có cùng tên. Ví dụ: onOff có thể tham chiếu đến một thực thể của đặc điểm OnOff tiêu chuẩn hoặc có thể tham chiếu đến một thực thể của đặc điểm OnOff do nhà sản xuất xác định. Để loại bỏ mọi sự mơ hồ tiềm ẩn về đặc điểm dự định, hãy tham chiếu đến một đặc điểm thông qua một trong 2 tập hợp đặc điểm trên mỗi loại thiết bị.

Đối với các đặc điểm tiêu chuẩn (tức là những đặc điểm tương tự như Matter cụm tiêu chuẩn), hãy sử dụng matterTraits. Ví dụ: để lấy một đặc điểm cụ thể cho loại thiết bị Đèn có thể điều chỉnh độ sáng:

if let dimmableLightDeviceType =
  await device.types.get(DimmableLightDeviceType.self)
{
  // Accessing standard trait on the type.
  let levelControlTrait =
    dimmableLightDeviceType.matterTraits.levelControlTrait.self
}

Đối với các đặc điểm của Google, hãy sử dụng googleTraits:

if let doorbellDeviceType = await device.types.get(GoogleDoorbellDeviceType.self) {
  // Accessing Google trait on the type.
  let doorbellPressTrait =
    doorbellDeviceType.traits[Google.DoorbellPressTrait.self]
}

Để 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 đến đặc điểm đó thông qua thuộc tính traits, nhưng hãy thêm tên gói của nhà sản xuất vào trước:

let deviceType = await device1?.types.get(OnOffLightDeviceType.self)
// Accessing custom trait on the type.
if let spinnerTrait = deviceType?.traits[ExampleOrganization.SpinnerTrait.self] {
  let rpmVal = spinnerTrait.attributes.rpm
}

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

Hãy xem ví dụ này về cách kiểm tra thuộc tính OnOff từ đặc điểm Bật/Tắt của thiết bị:

let lightDevices = devices.filter {
  $0.types.contains(OnOffLightDeviceType.self)
}
let light1 = lightDevices.first
let lightDeviceTypeOptional = await light1?.types.get(OnOffLightDeviceType.self)
if let onOffTrait = lightDeviceTypeOptional?.matterTraits.onOffTrait {
  let onOffVal = onOffTrait.attributes.onOff
}

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

Để lấy danh sách các thiết bị có một đặc điểm cụ thể, bạn cần lặp lại các thiết bị, các loại thiết bị của từng thiết bị và các đặc điểm của từng loại thiết bị. Ví dụ: để lấy danh sách các thiết bị trong nhà đều có đặc điểm Bật/Tắt:

// Get all light devices that support levelControl
var levelControlDevices: [HomeDevice] = []
let allDevices = try await home.devices().list()
for device in allDevices {
  if let deviceType = await device.types.get(OnOffLightDeviceType.self) {
    if deviceType.traits.contains(Matter.LevelControlTrait.self) {
      levelControlDevices.append(device)
    }
  }
}

Hãy xem bài viết Chỉ mục đặc điểm trên iOS để biết danh sách đầy đủ các đặc điểm có trong Home API.

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

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)
let lightDevices =
  try await self.home.devices().list().compactMap {
    $0.types.contains(DimmableLightDeviceType.self)
      || $0.types.contains(OnOffLightDeviceType.self)
      || $0.types.contains(ColorTemperatureLightDeviceType.self)
      || $0.types.contains(ExtendedColorLightDeviceType.self)
  }

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 chiếc đèn, như trong ví dụ trước. Do đó, để có cái nhìn toàn diện về loại thiết bị cấp cao hơn trong nhà, bạn phải đưa vào nhiều loại thiết bị.

Hãy xem bài viết Các loại thiết bị được hỗ trợ trên iOS để biết danh sách đầy đủ các loại thiết bị và đặc điểm của chúng có trong Home API.

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

Đặc điểm BasicInformationTrait bao gồm các 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 một thiết bị:

guard
  let vendorName =
    basicInfoTrait.attributes.vendorName
else {
  fatalError("Failed to get vendorName")
}
guard
  let vendorID =
    basicInfoTrait.attributes.vendorID
else {
  fatalError("Failed to get vendorID")
}
guard
  let productID =
    basicInfoTrait.attributes.productID
else {
  fatalError("Failed to get productID")
}

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

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

  • Connectivity Standards Alliance (Alliance) đã cấp mã nhà cung cấp: "matterOriginalVendorId": "0xfff1",

  • Giá trị nhận dạng sản phẩm giúp xác định duy nhất một sản phẩm của nhà cung cấp: "matterOriginalProductId": "0x1234",

  • Giá trị nhận dạng duy nhất cho 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ã Matter nhà cung cấp và Mã sản phẩm nếu bạn có. Nếu bạn không phải là Alliance thành viên và chưa được chỉ định các mã này, bạn có thể để trống các trường matterOriginalVendorIdmatterOriginalProductId rồ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 Cloud-to-cloud SYNC tài liệu.

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 được liên kết với chúng, 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 chứa một sourceConnectivity thuộc tính, thuộc tính này có thông tin về trạng thái trực tuyến và vị trí của một đặ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 được cung cấp các lựa chọn phù hợp trong một ứng dụng (chẳng hạn như tính năng điều khiển thiết bị và các quy trình tự động hoá được đề xuất) cho thiết bị của họ, bạn nên kiểm tra xem một loại thiết bị có phải là loại chính của thiết bị hay không.

if let deviceType =
  await device?.types.get(HumiditySensorDeviceType.self)
{
  if deviceType.metadata.isPrimaryType {
    print("Humidity Sensor is the primary type on this device.")
  } else {
    print("Humidity Sensor isn't the primary type on this device.")
  }
}

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

Đọc thuộc tính connectivityState để kiểm tra khả năng kết nối của một đặc điểm:

let levelControlConnectivity =
  levelControlTrait.metadata.sourceConnectivity
  .connectivityState

Một số đặc điểm (thường là đặc điểm smart home của Google) có thể hiển thị 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ó tính năng định tuyến cục bộ.

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

Khả năng kết nối của một 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ị đó.

let lightConnectivity =
  dimmableLightDeviceType.metadata.sourceConnectivity
  .connectivityState

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

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

Vị trí của một đặc điểm cũng có trong Home API. dataSourceLocality cho biết liệu đặc điểm đượ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ó trung tâm).

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

let levelControlLocality =
  levelControlTrait.metadata.sourceConnectivity
  .dataSourceLocality

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

Giống như khả năng kết nối, vị trí đượ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ị đó.

let lightLocality =
  dimmableLightDeviceType.metadata.sourceConnectivity.dataSourceLocality

Bạn có thể quan sát thấy trạng thái mixed trong một tình huống tương tự như khả năng kết nối partiallyOnline: 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 một thiết bị

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

let updatedDevice = try await theDevice.setName("new device name")

Khi thay đổi tên của một thiết bị, cấu trúc HomeDevice ban đầu vẫn giữ nguyên và thay đổi được phản ánh trong đối tượng HomeDevice được cập nhật được trả về.

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 được gửi. Nhà phát triển có trách nhiệm xử lý tên dài và ví dụ: 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.