您可以透過 iOS 版 Home API 存取 Structure API。
如要使用 Structure API,請先將 GoogleHomeSDK 封裝匯入應用程式:
import GoogleHomeSDK
處理錯誤
Home API 中的部分方法會擲回 HomeError,因此建議您使用 do-catch 區塊,在這些呼叫中擷取 HomeError。
處理 HomeError 時,請檢查 code 和 message 欄位,瞭解發生了什麼錯誤。
任何未處理的錯誤都會導致應用程式當機。
詳情請參閱「錯誤處理」。
Structure API
Home 代表住家圖表,也是 Structure API 的進入點。
並提供建築物、房間和裝置的參照。
Structure 代表住家圖表中的結構。可存取結構中繼資料,例如 id 和 name。
使用 structures() 取得帳戶中的所有結構。系統會以 Query 的形式傳回結構,並提供多種資料使用方式:
| API | 說明 |
|---|---|
stream() |
傳回 Publisher,在發生變更時個別發出每個物件。 |
batched() |
傳回 Publisher,該物件會將目前結果做為物件的 Set 發出。發出的每個 Set 都代表物件圖的目前狀態。 |
list() |
以物件 Set 的形式傳回目前結果。 |
structures().list() 呼叫可能不會立即傳回有效的結構集。如果應用程式是反應式,且會呼叫 stream() 來訂閱所有結構變更,以驅動 UI,最終應會傳回有效的結構清單。在其他情況下,系統也可能會傳回空白的結構清單,例如使用者手機失去連線,或是使用者撤銷應用程式的權限。請務必在應用程式中處理這些情況。
@Published public private(set) var structures: [Structure] = []
private var structuresCancellable: AnyCancellable?
self.structuresCancellable = home
.structures()
.batched()
.receive(on: DispatchQueue.main)
.map { Array($0) }
.catch {
// Failed to load structures
return Just([Structure]())
}
.assign(to: \.structures, on: self)
範例結構呼叫
取得一組結構體
在 Query<Structure> 上呼叫 list() 會傳回最新的一組元素:
// Get a stream of all structures accessible to the user let allStructuresChanges = 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 = 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 _ 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 _ as HomeError { // Code for handling the exception } do { structure2 = try await home.structures().list().first(where: { $0.name == "Guest Cottage" }) } catch let _ 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
// Failed to load rooms and devices
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)
Room 呼叫範例
取得會議室清單
您可以使用 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 _ 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 _ as HomeError { // Code for handling the exception } }
如果刪除含有裝置的房間,裝置仍會保留在住家中,但不會再指派至任何房間。
將裝置移至其他房間
Structure 也可讓你將裝置移到其他房間:
do { try await structure.move(device: light, to: room) } catch let _ as HomeError { // Code for handling the exception }
變更房間名稱
呼叫 setName(_:) 方法,變更房間名稱:
let updatedRoom = try await theRoom.setName("new room name")
變更房間名稱時,原始 Room 結構體會保持不變,變更會反映在傳回的更新 Room 物件中。
如果名稱超過 60 個 Unicode 碼點 (字元) 的限制,系統會截斷名稱,但不會擲回任何錯誤。開發人員有責任處理長名稱,例如決定是否要通知使用者名稱會遭到截斷。
裝置群組
裝置群組代表單一結構內使用者定義的裝置集合。
裝置群組與實體房間一樣,都屬於單一建築物。但與房間不同,裝置群組是邏輯分組。裝置可同時隸屬於多個裝置群組。裝置群組最多可包含 100 部裝置。
裝置群組以 Group 實體表示,與 HomeDevice 不同。
取得裝置群組清單
如要查看結構中的所有裝置群組,請按照下列步驟操作:
for await groups in structure.deviceGroups.batched() {
for group in groups {
print("Found group: \(group.name) with ID: \(group.id)")
}
}
建立裝置群組
使用結構中的 GroupManagementTrait 建立裝置群組:
let groupsManagementTrait = try await structure.traits(Google.GroupManagementTrait)
let _ = try await groupsManagementTrait.createUserDefinedGroup(withName: "Kitchen Lights",
withDevices: [light1, light2])
管理群組成員身分
如要將成員新增至現有群組,請按照下列步驟操作:
let groupManagementTrait = try await structure.traits(Google.GroupManagementTrait.self)
groupManagementTrait.addGroupMembers(
groupObjectId: group.id,
memberDeviceObjectIds = [light3.id],
)
如要從群組移除成員,請按照下列步驟操作:
let groupManagementTrait = try await structure.traits(Google.GroupManagementTrait.self)
_ = try await groupManagementTrait.removeGroupMembers(
groupObjectId: group.id,
memberDeviceObjectIdsArray: Array(removedIDs)
變更裝置群組名稱
如要重新命名裝置群組,請更新 GroupTrait 的 name 欄位:
let groupTrait = group.traits.get(Google.GroupTrait.self)
_ = try await groupTrait.update { $0.name = "Movie Corner" }
刪除裝置群組
如要從住家中刪除裝置群組,請按照下列步驟操作:
let groupManagementTrait = try await structure.traits.get(Google.GroupManagementTrait.self)
_ = try await groupManagementTrait.deleteGroup(groupObjectId: group.id)