iOS 上的 Structure API

您可以通过适用于 iOS 的 Home API 访问 Structure API。

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

import GoogleHomeSDK

错误处理

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

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

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

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

Structure API

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

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

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

API 说明
stream() 返回一个 Publisher,用于在发生变化时单独发出每个对象。
batched() 返回一个 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 对象中。

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。