Bạn có thể truy cập vào Structure API thông qua Home API cho iOS.
Để làm việc với API Cấu trúc, trước tiên, hãy nhập gói GoogleHomeSDK vào ứng dụng của bạn:
import GoogleHomeSDK
Xử lý lỗi
Một số phương thức trong các API cho Home sẽ gửi một HomeError, vì vậy, bạn nên sử dụng khối do-catch để phát hiện HomeError trong các lệnh gọi đó.
Khi xử lý HomeError, hãy kiểm tra các trường code và message để tìm hiểu xem đã xảy ra lỗi gì.
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 phần Xử lý lỗi.
Structure API
Home đại diện cho Home Graph và là điểm truy cập vào Structure API.
API này cung cấp thông tin tham chiếu đến các công trình, phòng và thiết bị.
Structure đại diện cho một cấu trúc trong Sơ đồ nhà của bạn. Thư viện này cung cấp quyền truy cập vào
siêu dữ liệu cấu trúc như id và name.
Sử dụng structures() để lấy tất cả cấu trúc trong tài khoản của bạn. Các cấu trúc được trả về dưới dạng Query, cung cấp nhiều cách sử dụng dữ liệu:
| API | Mô tả |
|---|---|
stream() |
Trả về một Publisher phát ra từng đối tượng riêng lẻ khi có thay đổi. |
batched() |
Trả về một Publisher phát ra kết quả hiện tại dưới dạng một Set đối tượng. Mỗi Set được phát ra đại diện cho trạng thái hiện tại của biểu đồ đối tượng. |
list() |
Trả về kết quả hiện tại dưới dạng Set của các đối tượng. |
Lệnh gọi structures().list() có thể không trả về ngay một tập hợp cấu trúc hợp lệ. Nếu ứng dụng của bạn có tính phản ứng và gọi stream() để đăng ký tất cả các thay đổi về cấu trúc nhằm điều khiển giao diện người dùng, thì danh sách cấu trúc hợp lệ sẽ được trả về. Có những trường hợp khác có thể trả về danh sách cấu trúc trống, chẳng hạn như nếu điện thoại của người dùng mất kết nối hoặc nếu người dùng đã thu hồi quyền đối với ứng dụng của bạn. Bạn nên đảm bảo xử lý các trường hợp này trong ứng dụng của mình.
@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)
Cuộc gọi đến Sample Structure
Lấy một tập hợp các cấu trúc
Khi gọi list() trên Query<Structure>, hệ thống sẽ trả về Tập hợp phần tử gần đây nhất:
// Get a stream of all structures accessible to the user let allStructuresChanges = self.home.structures() let allStructures = try? await allStructuresChanges.list()
Khi thiết kế một ứng dụng phản ứng, bạn nên sử dụng lệnh gọi batched() và stream() thay vì list(), vì các lệnh gọi này tự động tạo dữ liệu khi biểu đồ nhà thay đổi.
Lấy thuộc tính cấu trúc
Khi có danh sách các cấu trúc, bạn có thể truy cập vào các thuộc tính của chúng:
// 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) ")
Tìm cấu trúc theo tên
Nếu biết tên của một cấu trúc, bạn cũng có thể truy cập vào cấu trúc đó bằng thuộc tính name:
do { structure1 = try await home.structures().list().first(where: { $0.name == "Main House" }) } catch let _ as HomeError { // Code for handling the exception }
Từ đó, bạn có thể truy cập vào các nhà, phòng và thiết bị cho từng nhà.
Làm việc với nhiều cấu trúc
Để sử dụng nhiều cấu trúc, hãy lấy một tệp đối chiếu riêng cho từng cấu trúc:
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
Một phòng chứa một nhóm thiết bị. Một phòng luôn là một phần của một công trình và một công trình có thể có nhiều phòng. Khi bạn xoá một phòng khỏi một công trình, các thiết bị trong phòng đó sẽ không bị xoá khỏi công trình. Tuy nhiên, nếu phòng bị xoá, các thiết bị trong phòng đó sẽ không được chỉ định.
Sử dụng Home.rooms() để truy xuất tất cả các phòng trong tài khoản, sau đó sử dụng roomID = device.roomID để hiển thị các thiết bị tương ứng trong mỗi phòng.
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)
Cuộc gọi trong phòng mẫu
Lấy danh sách phòng
Khi sử dụng lớp Home, bạn có thể lấy danh sách phòng và truy cập vào các thuộc tính của phòng:
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) ")
Tạo một phòng
Cách tạo phòng mới trong 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 }
Xoá phòng
Hoặc bạn có thể xoá phòng theo cách sau:
val roomToDelete = structure.rooms().list().filter { it.name == "room_id1" }.firstOrNull() structure.deleteRoom(roomToDelete!!)
Bạn cũng có thể xoá phòng bằng mã nhận dạng của phòng:
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 } }
Nếu một phòng có thiết bị bị xoá, thì các thiết bị đó vẫn sẽ nằm trong cấu trúc nhưng không còn được chỉ định cho phòng nào nữa.
Di chuyển thiết bị sang phòng khác
Structure cũng cho phép bạn di chuyển thiết bị sang một phòng khác:
do { try await structure.move(device: light, to: room) } catch let _ as HomeError { // Code for handling the exception }
Thay đổi tên phòng
Gọi phương thức setName(_:) để thay đổi tên của một phòng:
let updatedRoom = try await theRoom.setName("new room name")
Khi thay đổi tên của một phòng, cấu trúc Room ban đầu vẫn giữ nguyên và thay đổi này được phản ánh trong đối tượng Room được cập nhật và 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à không có lỗi nào được gửi. Nhà phát triển chịu trách nhiệm xử lý tên dài và 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.
Nhóm thiết bị
Nhóm thiết bị đại diện cho một tập hợp thiết bị do người dùng xác định trong một cấu trúc duy nhất. Tư cách thành viên nhóm được giữ lại trong các dịch vụ của Google và hiển thị cho các thành viên khác trong cấu trúc và các ứng dụng khác có quyền truy cập vào cấu trúc.
Giống như phòng thực tế, các nhóm thiết bị thuộc về một cấu trúc duy nhất. Nhưng không giống như phòng, nhóm thiết bị là nhóm logic. Một thiết bị có thể thuộc về nhiều nhóm thiết bị cùng một lúc. Nhóm thiết bị có thể chứa tối đa 100 thiết bị.
Nhóm thiết bị được biểu thị bằng thực thểDeviceGroup, khác với HomeDevice. Để tương tác với các nhóm thiết bị, hãy thêm các loại thiết bị và đặc điểm liên quan khi định cấu hình ReferencedAutomationTypes trong Home.configure, cùng với các đặc điểm GroupTrait, GroupManagementTrait và GroupMembershipTrait.
Bạn có thể tương tác với các thiết bị trong một nhóm bằng cách lặp lại trực tiếp trên các thiết bị thành viên (xem phần Tương tác với các thiết bị thành viên trong nhóm) hoặc bằng cách nhắm mục tiêu một phần loại thiết bị trên DeviceGroup (xem phần Điều khiển một nhóm thiết bị).
Lấy danh sách nhóm thiết bị
Cách truy vấn tất cả nhóm thiết bị trong nhà:
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)")
}
Tương tác với thiết bị của thành viên trong nhóm
Việc lặp lại trên các thiết bị thành viên của một nhóm giúp bạn kiểm soát chi tiết từng thành viên, cho phép bạn gộp các lệnh vào một yêu cầu và cho phép bạn tổng hợp hoặc ghi thuộc tính trên các thành viên.
Trước tiên, hãy lọc các thiết bị trong nhà bằng cách kiểm tra GroupMembershipTrait của từng thiết bị để tìm mã nhóm mục tiêu:
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)
}
}
Cách gửi một yêu cầu theo lô duy nhất có các lệnh cho một đặc điểm trên tất cả thành viên tương thích của một nhóm:
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()
}
Bạn cũng có thể cập nhật một thuộc tính trên tất cả thiết bị thành viên phù hợp trong một nhóm (ví dụ: đặt onTransitionTime thành 1 trên tất cả thành viên DimmableLightDeviceType) cùng một lúc và chờ hoàn tất trong một thời hạn:
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()
}
Để tổng hợp một thuộc tính trên các thành viên của một nhóm, chẳng hạn như tìm colorTempPhysicalMaxMireds tối thiểu trên tất cả đèn nhiệt độ màu trong nhóm:
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()
Tạo nhóm thiết bị
Sử dụng
GroupManagementTrait
trên cấu trúc để tạo nhóm thiết bị:
let groupsManagementTrait =
try await structure.traits(Google.GroupManagementTrait)
let _ = try await groupsManagementTrait.createUserDefinedGroup(
withName: "Kitchen Lights",
withDevices: [light1, light2]
)
Quản lý tư cách thành viên trong nhóm
Cách thêm thành viên vào một nhóm hiện có:
let groupManagementTrait =
try await structure.traits(Google.GroupManagementTrait.self)
groupManagementTrait.addGroupMembers(
groupObjectId: group.id,
memberDeviceObjectIds = [light3.id],
)
Cách xoá thành viên khỏi nhóm:
let groupManagementTrait =
try await structure.traits(Google.GroupManagementTrait.self)
_ = try await groupManagementTrait.removeGroupMembers(
groupObjectId: group.id,
memberDeviceObjectIdsArray: Array(removedIDs)
)
Thay đổi tên của một nhóm thiết bị
Để đổi tên một nhóm thiết bị, hãy cập nhật trường name của GroupTrait:
let groupTrait = group.traits.get(Google.GroupTrait.self)
_ = try await groupTrait.update { $0.name = "Movie Corner" }
Xoá nhóm thiết bị
Cách xoá một nhóm thiết bị khỏi một nhà:
let groupManagementTrait =
try await structure.traits.get(Google.GroupManagementTrait.self)
_ = try await groupManagementTrait.deleteGroup(groupObjectId: group.id)