คุณเข้าถึง Structure API ได้ผ่าน Home API สำหรับ iOS
หากต้องการทำงานกับ Structure API ให้เริ่มด้วยการนำเข้าแพ็กเกจ GoogleHomeSDK ไปยังแอปของคุณ
import GoogleHomeSDK
การจัดการข้อผิดพลาด
เมธอดบางรายการใน Home API จะแสดง HomeError ดังนั้นเราขอแนะนำให้คุณใช้บล็อก do-catch เพื่อตรวจจับ HomeError ในการเรียกใช้เหล่านั้น
เมื่อจัดการ HomeError ให้ตรวจสอบช่อง code และ message เพื่อดูว่าเกิดข้อผิดพลาดใดขึ้น
ข้อผิดพลาดที่ไม่ได้จัดการจะทำให้แอปขัดข้อง
ดูข้อมูลเพิ่มเติมได้ที่การจัดการข้อผิดพลาด
Structure API
Home แสดงถึง Home Graph และเป็นจุดแรกเข้าของ Structure API
โดยจะให้ข้อมูลอ้างอิงเกี่ยวกับบ้าน ห้อง และอุปกรณ์
Structure แสดงถึงบ้านใน Home Graph ซึ่งจะให้สิทธิ์เข้าถึงข้อมูลเมตาของบ้าน เช่น 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)
ตัวอย่างการเรียกใช้โครงสร้าง
รับชุดบ้านเสมือน
การเรียก list() ใน Query<Structure> จะแสดงผลชุดองค์ประกอบล่าสุด ดังนี้
// Get a stream of all structures accessible to the user let allStructuresChanges = self.home.structures() let allStructures = try? await allStructuresChanges.list()
เมื่อออกแบบแอปแบบรีแอ็กทีฟ คุณจะต้องใช้การเรียก batched() และ stream() แทน list() เนื่องจากจะสร้างข้อมูลโดยอัตโนมัติเมื่อ Home Graph มีการเปลี่ยนแปลง
ดูพร็อพเพอร์ตี้ของบ้าน
เมื่อมีรายการโครงสร้างแล้ว คุณจะเข้าถึงพร็อพเพอร์ตี้ของโครงสร้างเหล่านั้นได้โดยทำดังนี้
// 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 }
จากนั้นคุณจะเข้าถึงที่พัก ห้อง และอุปกรณ์สำหรับบ้านแต่ละหลังได้
ทำงานกับบ้านหลายหลัง
หากต้องการใช้บ้านมากกว่า 1 หลัง ให้รับข้อมูลอ้างอิงแยกต่างหากสำหรับบ้านแต่ละหลัง ดังนี้
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 }
ห้องพัก
ห้องประกอบด้วยกลุ่มอุปกรณ์ ห้องจะเป็นส่วนหนึ่งของบ้านเสมอ และบ้านอาจมีหลายห้อง การนำห้องออกจากบ้านจะไม่นำอุปกรณ์ในห้องนั้นออกจากบ้าน อย่างไรก็ตาม หากลบห้อง ระบบจะยกเลิกการกำหนดอุปกรณ์ในห้องนั้น
ใช้ 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)
การโทรจากห้องตัวอย่าง
ดูรายการห้องแชท
เมื่อใช้คลาส 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!!)
นอกจากนี้ คุณยังลบห้องแชทโดยใช้รหัสห้องแชทได้ด้วย โดยทำดังนี้
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 ที่อัปเดตซึ่งแสดงผล
ระบบจะตัดชื่อให้สั้นลงหากเกินขีดจำกัด Code Point (อักขระ) ของ Unicode ที่ 60 รายการ และจะไม่แสดงข้อผิดพลาด นักพัฒนาแอปมีหน้าที่รับผิดชอบในการจัดการชื่อที่ยาว และสามารถตัดสินใจได้ว่าต้องการแจ้งให้ผู้ใช้ทราบหรือไม่ว่าชื่อจะถูกตัดให้สั้นลง
กลุ่มอุปกรณ์
กลุ่มอุปกรณ์แสดงถึงคอลเล็กชันอุปกรณ์ที่ผู้ใช้กำหนดภายในโครงสร้างเดียว ระบบจะเก็บข้อมูลการเป็นสมาชิกกลุ่มไว้ในบริการของ Google และสมาชิกคนอื่นๆ ของบ้านและแอปอื่นๆ ที่มีสิทธิ์เข้าถึงบ้านจะเห็นข้อมูลดังกล่าว
กลุ่มอุปกรณ์จะอยู่ในบ้านหลังเดียว เช่นเดียวกับห้องจริง แต่กลุ่มอุปกรณ์เป็นการจัดกลุ่มเชิงตรรกะซึ่งต่างจากห้อง อุปกรณ์เครื่องหนึ่งสามารถอยู่ในกลุ่มอุปกรณ์หลายกลุ่มพร้อมกันได้ กลุ่มอุปกรณ์มีอุปกรณ์ได้สูงสุด 100 เครื่อง
กลุ่มอุปกรณ์จะแสดงด้วยเอนทิตีDeviceGroup ซึ่งแตกต่างจาก HomeDevice หากต้องการโต้ตอบกับกลุ่มอุปกรณ์ ให้ระบุประเภทและลักษณะของอุปกรณ์ที่เกี่ยวข้องเมื่อกำหนดค่า ReferencedAutomationTypes ใน Home.configure พร้อมกับลักษณะ GroupTrait, GroupManagementTrait และ GroupMembershipTrait
คุณสามารถโต้ตอบกับอุปกรณ์ในกลุ่มได้โดยการทำซ้ำในอุปกรณ์ที่เป็นสมาชิกโดยตรง (ดูหัวข้อโต้ตอบกับอุปกรณ์ที่เป็นสมาชิกกลุ่ม) หรือโดยการกำหนดเป้าหมายส่วนประเภทอุปกรณ์ใน DeviceGroup (ดูหัวข้อควบคุมกลุ่มอุปกรณ์)
ดูรายการกลุ่มอุปกรณ์
วิธีค้นหากลุ่มอุปกรณ์ทั้งหมดในบ้าน
let groups = try await home.entities(DeviceGroup.self).list()
for group in groups {
let groupTrait = await group.traits.get(Google.GroupTrait.self)
let name = groupTrait?.attributes.name ?? "Device Group"
print("Found group: \(name) with ID: \(group.id)")
}
โต้ตอบกับอุปกรณ์ของสมาชิกในกลุ่ม
การทำซ้ำในอุปกรณ์ของสมาชิกกลุ่มช่วยให้คุณควบคุมสมาชิกแต่ละรายได้อย่างละเอียด ช่วยให้คุณรวมคำสั่งเป็นกลุ่มในคำขอเดียว และช่วยให้คุณรวมหรือเขียนแอตทริบิวต์ในสมาชิกได้
ก่อนอื่น ให้กรองอุปกรณ์ในบ้านโดยตรวจสอบ GroupMembershipTrait ของอุปกรณ์แต่ละเครื่องเพื่อหารหัสกลุ่มเป้าหมาย ดังนี้
let allDevices = try await home.devices().list()
var members: [HomeDevice] = []
for device in allDevices {
if let membership = await device.traits.get(
Google.GroupMembershipTrait.self
),
membership.attributes.groupObjectIdsArray.contains(group.id) {
members.append(device)
}
}
หากต้องการส่งคำขอแบบกลุ่มรายการเดียวพร้อมคำสั่งสำหรับลักษณะหนึ่งๆ ไปยังสมาชิกทั้งหมดที่เข้ากันได้ของกลุ่ม ให้ทำดังนี้
var onOffTraits: [Matter.OnOffTrait] = []
for device in members {
if let light = await device.types.get(OnOffLightDeviceType.self),
let onOff = light.matterTraits.onOffTrait {
onOffTraits.append(onOff)
}
}
let traitsToUse = onOffTraits
let responses = try await home.sendBatchedCommands { batcher in
return try traitsToUse.map { batcher.add(try $0.onBatchable()) }
}
for response in responses {
try response.getOrThrow()
}
นอกจากนี้ คุณยังอัปเดตแอตทริบิวต์ในอุปกรณ์สมาชิกที่ตรงกันทั้งหมดในกลุ่มได้ด้วย (เช่น ตั้งค่า onTransitionTime เป็น 1 ในสมาชิก DimmableLightDeviceType ทั้งหมด) พร้อมกันและรอให้เสร็จสิ้นภายในกำหนดเวลา ดังนี้
try await withThrowingTaskGroup(of: Void.self) { taskGroup in
taskGroup.addTask {
try await Task.sleep(for: .seconds(5))
throw CancellationError()
}
for device in members {
taskGroup.addTask {
guard let light = await device.types.get(DimmableLightDeviceType.self),
let levelControl = light.matterTraits.levelControlTrait,
levelControl.attributes.$onTransitionTime.isSupported
else { return }
_ = try await levelControl.update {
$0.setOnTransitionTime(1)
}
}
}
for _ in 0..<members.count {
try await taskGroup.next()
}
taskGroup.cancelAll()
}
หากต้องการรวมแอตทริบิวต์ในสมาชิกของกลุ่ม เช่น การค้นหา colorTempPhysicalMaxMireds ต่ำสุดในไฟอุณหภูมิสีทั้งหมดในกลุ่ม ให้ทำดังนี้
var maxMiredsValues: [UInt16] = []
for device in members {
if let light = await device.types.get(ColorTemperatureLightDeviceType.self),
let mireds = light.matterTraits.colorControlTrait?.attributes
.colorTempPhysicalMaxMireds {
maxMiredsValues.append(mireds)
}
}
let minMaxMireds = maxMiredsValues.min()
สร้างกลุ่มอุปกรณ์
ใช้
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)
)
เปลี่ยนชื่อกลุ่มอุปกรณ์
หากต้องการเปลี่ยนชื่อกลุ่มอุปกรณ์ ให้อัปเดตช่อง name ของ GroupTrait ดังนี้
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)