iOS 上的 Structure API

可以通过适用于 iOS 的 Home API 访问结构 API。

如需使用 Structure API,请先将 GoogleHomeSDK 软件包导入到您的应用中:

import GoogleHomeSDK

错误处理

Home API 中的某些方法会抛出 HomeError,因此我们建议您使用 do-catch 块来捕获这些调用中的 HomeError

处理 HomeError 时,请检查其 codemessage 字段,了解问题所在。

任何未处理的错误都会导致应用崩溃。

如需了解详情,请参阅错误处理

Structure API

Home 表示 Home Graph,是 Structure API 的入口点。 它提供对结构、房间和设备的引用。

Structure 表示 Home Graph 中的结构。它提供对结构元数据(例如 idname)的访问权限。

使用 structures() 获取您账号中的所有结构。这些结构以 Query 的形式返回,其中提供了多种使用其数据的方式:

API 说明
stream() 返回一个 Publisher,该对象会在发生更改时单独发出每个对象。
batched() 返回一个 Publisher,该 Publisher 会将当前结果作为对象 Set 发出。每次发出的 Set 都表示对象图的当前状态。
list() 以对象 Set 的形式返回当前结果。

structures().list() 调用可能不会立即返回一组有效的结构。如果您的应用是响应式的,并且调用 stream() 来订阅所有结构更改以驱动界面,则最终应返回有效的结构列表。在其他情况下也可能会返回空结构列表,例如,如果用户的手机断开连接,或者用户已撤消向您的应用授予的权限。您应确保在应用中处理这些情况。

@Published public private(set) var structures: [Structure] = []
private var structuresCancellable: AnyCancellable?

  self.structuresCancellable = home
    .structures()
    .batched()
    .receive(on: DispatchQueue.main)
    .map { Array($0) }
    .catch {
      Logger.error("Failed to load structures: \($0)")
      return Just([Structure]())
    }
    .assign(to: \.structures, on: self)

结构化通话示例

获取一组结构

Query<Structure> 调用 list() 会返回最新的元素集:

// Get a stream of all structures accessible to the user
let allStructuresChanges = try await self.home.structures()
let allStructures = try? await allStructuresChanges.list()

设计响应式应用时,您需要使用 batched()stream() 调用,而不是 list(),因为这些调用会在主图发生变化时自动生成数据。

获取结构属性

有了结构列表后,您就可以访问这些结构的属性:

// Get a stream of changes taking place on a structure.
let structureChanges = try await home.structures().list().filter { $0.id == structureID }

// Get a snapshot of the structure.
let structure = try await structureChanges.first!

// Get structure properties
print("id \(structure.id) ")
print("name \(structure.name) ")

按名称查找结构

如果您知道结构的名称,也可以使用 name 属性访问该结构:

do {
  structure1 = try await home.structures().list().first(where: { $0.name == "Main House" })
} catch let error as HomeError {
  // Code for handling the exception
}

您可以在此处访问每个结构的房源、房间和设备。

处理多种结构

如需使用多个结构,请分别获取每个结构的引用:

var structure1: Structure!
var structure2: Structure!
do {
  structure1 = try await home.structures().list().first(where: { $0.name == "Main House" })
} catch let error as HomeError {
  // Code for handling the exception
}
do {
  structure2 = try await home.structures().list().first(where: { $0.name == "Guest Cottage" })
} catch let error as HomeError {
  // Code for handling the exception
}

Rooms

房间包含一组设备。房间始终是结构的一部分,一个结构可以包含多个房间。从结构中移除房间并不会从结构中移除该房间内的设备。不过,如果房间被删除,该房间中的设备将变为未分配状态。

使用 Home.rooms() 检索账号中的所有房间,然后使用 roomID = device.roomID 显示每个房间中的相应设备。

self.home.rooms().batched()
  .combineLatest(self.home.devices().batched())
  .receive(on: DispatchQueue.main)
  .catch { error in
    Logger.error("Failed to load rooms and devices: \(error)")
    return Just((Set<Room>(), Set<HomeDevice>()))
  }
  .map { rooms, devices in
    var devicesByRoom = [Room: [HomeDevice]]()
    for room in rooms where room.structureID == currentStructureID {
      devicesByRoom[room] = devices.filter { $0.roomID == room.id }
    }
    return devicesByRoom
  }.assign(to: &self.$devicesByRoom)

会议室通话示例

获取会议室列表

使用 Home 类,您可以获取会议室列表并访问这些会议室的属性:

let allRoomsChanges = self.home.rooms()
let allRooms = try await allRoomsChanges.list()
let room = allRooms.first!
XCTAssertTrue(allRooms.contains(room))

print("id \(room.id) ")
print("name \(room.name) ")

创建聊天室

如需在 Structure 中创建新房间,请执行以下操作:

let testName = "Test Room Name"
var newRoom: Room!
do {
  newRoom = try await structure.createRoom(name: testName)
  XCTAssertNotNil(newRoom)
} catch let error as HomeError {
  // Code for handling the exception
}

删除房间

或者,您也可以删除聊天室:

val roomToDelete = structure.rooms().list().filter { it.name == "room_id1" }.firstOrNull()
    structure.deleteRoom(roomToDelete!!)

您还可以使用会议室 ID 删除会议室:

let roomToDelete = allRooms.first(where: { $0.id == room.id })
if let roomToDelete1 = roomToDelete {
  do {
    try await structure.deleteRoom(roomToDelete1)
  } catch let error as HomeError {
    // Code for handling the exception
  }
}

如果删除包含设备的房间,这些设备仍会保留在住宅结构中,但不再分配到任何房间。

将设备移至其他房间

借助 Structure,您还可以将设备移至其他房间:

do {
  try await structure.move(device: light, to: room)
} catch let error as HomeError {
  // Code for handling the exception
}

更改会议室名称

调用 setName(_:) 方法可更改房间的名称:

let updatedRoom = try await theRoom.setName("new room name")

更改房间名称时,原始 Room 结构体保持不变,更改会反映在返回的更新后的 Room 对象中。

如果名称超过 60 个 Unicode 码位(字符)的限制,系统会截断名称,但不会抛出任何错误。开发者负责处理过长的名称,例如,可以决定是否要告知用户名称将被截断。

API 列表

创建 Home 的实例后,可以通过该实例访问以下 Structure API:

API 说明
devices() 获取此账号可看到的所有设备。
device(id:) 获取指定设备的 Publisher,该 Publisher 会在当前状态发生变化时发出信号,并在任何未来的状态更新时再次发出信号。
structures() 获取 Google 账号中的所有结构。返回一个 Query<Structure>,其中包含更多检索和过滤选项。
structure(id:) 获取具有匹配 ID 的结构。
rooms() 获取 Google 账号中的所有房间。返回一个 Query<strRoom>,其中包含更多检索和过滤选项。
room(id:) 获取指定房间的 Publisher,该 Publisher 会发出当前状态,并在任何未来的状态更新时再次发出。

Structure 具有以下 API:

API 说明
deleteRoom(id:) 删除具有指定聊天室 ID 的聊天室。
id 结构的唯一系统 ID。
move(device:, to:) 将设备移至结构中的其他房间。
move(device:, to:) 将具有指定 ID 的设备移至具有指定 ID 的房间。
move(devices:, to:) 将指定设备移至指定房间。
move(devices:, to:) 将具有指定 ID 的设备移至具有指定 ID 的房间。
name 用户提供的结构的名称。

Room 具有以下 API:

API 说明
id 客房的唯一系统 ID。
name 用户提供的聊天室名称。
structureID 相应客房所属结构的唯一系统 ID。